From 3bb1a0b75b471c41c1c8713d3b6120924571b830 Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Fri, 18 Sep 2026 14:50:58 -0700 Subject: [PATCH] feat(access-requests): remove rollout flag and move feature into ee --- apps/sim/.env.example | 1 - apps/sim/app/access-requests/loading.tsx | 2 +- apps/sim/app/access-requests/page.test.tsx | 6 +- apps/sim/app/access-requests/page.tsx | 8 +- .../[requestId]/cancel/route.ts | 4 +- .../api/access-requests/discovery/route.ts | 4 +- apps/sim/app/api/access-requests/route.ts | 4 +- .../[requestId]/preview/route.ts | 4 +- .../[requestId]/resolve/route.ts | 4 +- .../[id]/access-requests/route.ts | 4 +- .../[id]/access-requests/settings/route.ts | 4 +- .../[workspaceId]/access-requests/loading.tsx | 2 +- .../[workspaceId]/access-requests/page.tsx | 4 +- .../workspace/[workspaceId]/files/files.tsx | 2 +- .../components/special-tags/special-tags.tsx | 2 +- .../usage-upgrade-display.test.tsx | 2 +- .../app/workspace/[workspaceId]/home/home.tsx | 2 +- .../integrations/[block]/page.tsx | 2 +- .../connected/[credentialId]/page.tsx | 2 +- .../integrations/integrations.tsx | 2 +- .../knowledge/[id]/[documentId]/page.tsx | 2 +- .../[workspaceId]/knowledge/[id]/page.tsx | 2 +- .../knowledge/knowledge.test.tsx | 2 +- .../[workspaceId]/knowledge/knowledge.tsx | 2 +- .../[workspaceId]/prefetch-access.test.tsx | 8 +- .../[workspaceId]/prefetch-access.ts | 4 +- .../settings/[section]/page.test.tsx | 2 +- .../[workspaceId]/settings/[section]/page.tsx | 2 +- .../settings/[section]/settings.tsx | 2 +- .../[workspaceId]/tables/[tableId]/page.tsx | 2 +- .../workspace/[workspaceId]/tables/tables.tsx | 2 +- .../panel/components/toolbar/toolbar.test.tsx | 4 +- .../panel/components/toolbar/toolbar.tsx | 4 +- .../w/[workflowId]/components/panel/panel.tsx | 4 +- .../search-modal/search-modal.test.tsx | 2 +- .../components/search-modal/search-modal.tsx | 2 +- .../settings-sidebar/settings-sidebar.tsx | 2 +- .../w/components/sidebar/sidebar.tsx | 2 +- apps/sim/ee/README.md | 1 + .../components/access-control-layout.test.tsx | 4 +- .../components/access-control.test.tsx | 2 +- .../components/access-control.tsx | 10 +- .../access-requests}/README.md | 7 +- .../access-request-review.test.tsx | 4 +- .../components}/access-request-review.tsx | 9 +- .../components}/access-requests-loading.tsx | 0 .../member-limit-request-action.tsx | 4 +- .../components}/my-access-request-details.tsx | 7 +- .../components}/my-access-requests.test.tsx | 4 +- .../components}/my-access-requests.tsx | 18 ++-- .../organization-access-requests.test.tsx | 6 +- .../organization-access-requests.tsx | 16 ++-- .../permission-access-boundary.test.tsx | 8 +- .../permission-access-boundary.tsx | 6 +- .../components}/policy-changes.test.ts | 2 +- .../components}/policy-changes.tsx | 0 .../request-access-action.test.tsx | 4 +- .../components}/request-access-action.tsx | 7 +- .../components}/search-params.test.ts | 2 +- .../components}/search-params.ts | 2 +- .../access-requests/components}/status.ts | 0 .../hooks}/access-request-keys.ts | 0 .../hooks}/access-requests.test.tsx | 4 +- .../access-requests/hooks}/access-requests.ts | 4 +- .../lib}/application/authorization.test.ts | 4 +- .../lib}/application/authorization.ts | 4 +- .../application/authorized-use-case.test.ts | 6 +- .../lib}/application/authorized-use-case.ts | 6 +- .../lib}/application/operations.ts | 0 .../lib}/application/prepare.ts | 12 +-- .../lib}/application/requests.test.ts | 19 ++-- .../lib}/application/requests.ts | 40 ++++---- .../lib}/application/review.test.ts | 21 ++-- .../lib}/application/review.ts | 28 +++--- .../access-requests/lib}/catalog-registry.ts | 16 ++-- .../access-requests/lib}/catalog.test.ts | 8 +- .../access-requests/lib}/catalog.ts | 10 +- .../access-requests/lib}/constants.ts | 0 .../lib}/impact.postgres.test.ts | 2 +- .../access-requests/lib}/impact.ts | 2 +- .../lib}/notification-events.ts | 0 .../lib}/notifications.test.ts | 8 +- .../access-requests/lib}/notifications.ts | 6 +- .../access-requests/lib}/policy.ts | 13 +-- .../lib}/repository.postgres.test.ts | 2 +- .../access-requests/lib}/repository.ts | 4 +- .../access-requests/lib}/schemas.test.ts | 2 +- .../access-requests/lib}/schemas.ts | 2 +- .../ee/access-requests/lib/settings.test.ts | 48 ++++++++++ .../access-requests/lib}/settings.ts | 8 +- .../access-requests/lib}/targets.test.ts | 6 +- .../access-requests/lib}/targets.ts | 0 .../access-requests/lib}/types.ts | 7 +- apps/sim/lib/api/contracts/access-requests.ts | 8 +- apps/sim/lib/core/config/env.ts | 1 - .../sim/lib/core/config/feature-flags.test.ts | 26 +---- apps/sim/lib/core/config/feature-flags.ts | 5 - apps/sim/lib/core/outbox/processor.test.ts | 2 +- apps/sim/lib/core/outbox/processor.ts | 2 +- .../settings.test.ts | 95 ------------------- .../workspace-section-access.test.ts | 2 +- .../application/workspace-section-access.ts | 2 +- ...check-tool-registry-boundary.baseline.json | 2 +- 103 files changed, 296 insertions(+), 379 deletions(-) rename apps/sim/{lib/permission-access-requests => ee/access-requests}/README.md (91%) rename apps/sim/{components/access-requests => ee/access-requests/components}/access-request-review.test.tsx (97%) rename apps/sim/{components/access-requests => ee/access-requests/components}/access-request-review.tsx (96%) rename apps/sim/{components/access-requests => ee/access-requests/components}/access-requests-loading.tsx (100%) rename apps/sim/{components/access-requests => ee/access-requests/components}/member-limit-request-action.tsx (82%) rename apps/sim/{components/access-requests => ee/access-requests/components}/my-access-request-details.tsx (94%) rename apps/sim/{components/access-requests => ee/access-requests/components}/my-access-requests.test.tsx (96%) rename apps/sim/{components/access-requests => ee/access-requests/components}/my-access-requests.tsx (93%) rename apps/sim/{components/access-requests => ee/access-requests/components}/organization-access-requests.test.tsx (95%) rename apps/sim/{components/access-requests => ee/access-requests/components}/organization-access-requests.tsx (95%) rename apps/sim/{components/access-requests => ee/access-requests/components}/permission-access-boundary.test.tsx (95%) rename apps/sim/{components/access-requests => ee/access-requests/components}/permission-access-boundary.tsx (94%) rename apps/sim/{components/access-requests => ee/access-requests/components}/policy-changes.test.ts (99%) rename apps/sim/{components/access-requests => ee/access-requests/components}/policy-changes.tsx (100%) rename apps/sim/{components/access-requests => ee/access-requests/components}/request-access-action.test.tsx (98%) rename apps/sim/{components/access-requests => ee/access-requests/components}/request-access-action.tsx (97%) rename apps/sim/{components/access-requests => ee/access-requests/components}/search-params.test.ts (95%) rename apps/sim/{components/access-requests => ee/access-requests/components}/search-params.ts (97%) rename apps/sim/{components/access-requests => ee/access-requests/components}/status.ts (100%) rename apps/sim/{hooks/queries/utils => ee/access-requests/hooks}/access-request-keys.ts (100%) rename apps/sim/{hooks/queries => ee/access-requests/hooks}/access-requests.test.tsx (98%) rename apps/sim/{hooks/queries => ee/access-requests/hooks}/access-requests.ts (98%) rename apps/sim/{lib/permission-access-requests => ee/access-requests/lib}/application/authorization.test.ts (98%) rename apps/sim/{lib/permission-access-requests => ee/access-requests/lib}/application/authorization.ts (96%) rename apps/sim/{lib/permission-access-requests => ee/access-requests/lib}/application/authorized-use-case.test.ts (96%) rename apps/sim/{lib/permission-access-requests => ee/access-requests/lib}/application/authorized-use-case.ts (94%) rename apps/sim/{lib/permission-access-requests => ee/access-requests/lib}/application/operations.ts (100%) rename apps/sim/{lib/permission-access-requests => ee/access-requests/lib}/application/prepare.ts (67%) rename apps/sim/{lib/permission-access-requests => ee/access-requests/lib}/application/requests.test.ts (96%) rename apps/sim/{lib/permission-access-requests => ee/access-requests/lib}/application/requests.ts (94%) rename apps/sim/{lib/permission-access-requests => ee/access-requests/lib}/application/review.test.ts (95%) rename apps/sim/{lib/permission-access-requests => ee/access-requests/lib}/application/review.ts (93%) rename apps/sim/{lib/permission-access-requests => ee/access-requests/lib}/catalog-registry.ts (99%) rename apps/sim/{lib/permission-access-requests => ee/access-requests/lib}/catalog.test.ts (99%) rename apps/sim/{lib/permission-access-requests => ee/access-requests/lib}/catalog.ts (93%) rename apps/sim/{lib/permission-access-requests => ee/access-requests/lib}/constants.ts (100%) rename apps/sim/{lib/permission-access-requests => ee/access-requests/lib}/impact.postgres.test.ts (99%) rename apps/sim/{lib/permission-access-requests => ee/access-requests/lib}/impact.ts (98%) rename apps/sim/{lib/permission-access-requests => ee/access-requests/lib}/notification-events.ts (100%) rename apps/sim/{lib/permission-access-requests => ee/access-requests/lib}/notifications.test.ts (97%) rename apps/sim/{lib/permission-access-requests => ee/access-requests/lib}/notifications.ts (96%) rename apps/sim/{lib/permission-access-requests => ee/access-requests/lib}/policy.ts (92%) rename apps/sim/{lib/permission-access-requests => ee/access-requests/lib}/repository.postgres.test.ts (97%) rename apps/sim/{lib/permission-access-requests => ee/access-requests/lib}/repository.ts (95%) rename apps/sim/{lib/permission-access-requests => ee/access-requests/lib}/schemas.test.ts (96%) rename apps/sim/{lib/permission-access-requests => ee/access-requests/lib}/schemas.ts (98%) create mode 100644 apps/sim/ee/access-requests/lib/settings.test.ts rename apps/sim/{lib/permission-access-requests => ee/access-requests/lib}/settings.ts (71%) rename apps/sim/{lib/permission-groups/access-requests => ee/access-requests/lib}/targets.test.ts (99%) rename apps/sim/{lib/permission-groups/access-requests => ee/access-requests/lib}/targets.ts (100%) rename apps/sim/{lib/permission-access-requests => ee/access-requests/lib}/types.ts (90%) delete mode 100644 apps/sim/lib/permission-access-requests/settings.test.ts diff --git a/apps/sim/.env.example b/apps/sim/.env.example index f5d05f0ac23..c8b8583d103 100644 --- a/apps/sim/.env.example +++ b/apps/sim/.env.example @@ -214,7 +214,6 @@ CRON_SECRET=your_cron_secret # Use `openssl rand -hex 32` to generate. Authentic # FORKING_ENABLED= # Workspace forks # CREDENTIAL_GROUPS= # Enterprise managed OAuth collections # TABLE_ROW_TTL= # Table TTL columns and expired-row cleanup -# PERMISSION_ACCESS_REQUESTS_ENABLED= # Global access-request rollout; organizations may opt out # KNOWLEDGE_MEMBER_ACCESS= # Per-member knowledge connectors and hybrid-by-default retrieval # ORGANIZATIONS_ENABLED= / NEXT_PUBLIC_ORGANIZATIONS_ENABLED= # Organizations only diff --git a/apps/sim/app/access-requests/loading.tsx b/apps/sim/app/access-requests/loading.tsx index 4eb54fb68e8..5ee4cac94d1 100644 --- a/apps/sim/app/access-requests/loading.tsx +++ b/apps/sim/app/access-requests/loading.tsx @@ -1,4 +1,4 @@ -import { AccessRequestsLoading } from '@/components/access-requests/access-requests-loading' +import { AccessRequestsLoading } from '@/ee/access-requests/components/access-requests-loading' export default function Loading() { return diff --git a/apps/sim/app/access-requests/page.test.tsx b/apps/sim/app/access-requests/page.test.tsx index f1f50b8cae5..9ea92ec6dd5 100644 --- a/apps/sim/app/access-requests/page.test.tsx +++ b/apps/sim/app/access-requests/page.test.tsx @@ -4,8 +4,10 @@ import { beforeEach, describe, expect, it, vi } from 'vitest' const { redirect } = vi.hoisted(() => ({ redirect: vi.fn() })) vi.mock('next/navigation', () => ({ redirect })) -vi.mock('@/components/access-requests/my-access-requests', () => ({ MyAccessRequests: () => null })) -vi.mock('@/components/access-requests/organization-access-requests', () => ({ +vi.mock('@/ee/access-requests/components/my-access-requests', () => ({ + MyAccessRequests: () => null, +})) +vi.mock('@/ee/access-requests/components/organization-access-requests', () => ({ OrganizationAccessRequests: () => null, })) diff --git a/apps/sim/app/access-requests/page.tsx b/apps/sim/app/access-requests/page.tsx index a3c90a5ec65..bca8ec035cd 100644 --- a/apps/sim/app/access-requests/page.tsx +++ b/apps/sim/app/access-requests/page.tsx @@ -3,14 +3,14 @@ import { ChipLink } from '@sim/emcn' import type { Metadata } from 'next' import { redirect } from 'next/navigation' import { createSearchParamsCache, createSerializer } from 'nuqs/server' -import { AccessRequestsLoading } from '@/components/access-requests/access-requests-loading' -import { MyAccessRequests } from '@/components/access-requests/my-access-requests' -import { OrganizationAccessRequests } from '@/components/access-requests/organization-access-requests' -import { accessRequestEntrySearchParams } from '@/components/access-requests/search-params' import { EmptyState } from '@/components/empty-state/empty-state' import { getSession } from '@/lib/auth' import { WORKSPACES_PATH } from '@/lib/navigation/paths' import { buildAuthCrossLink } from '@/app/(auth)/auth-redirect' +import { AccessRequestsLoading } from '@/ee/access-requests/components/access-requests-loading' +import { MyAccessRequests } from '@/ee/access-requests/components/my-access-requests' +import { OrganizationAccessRequests } from '@/ee/access-requests/components/organization-access-requests' +import { accessRequestEntrySearchParams } from '@/ee/access-requests/components/search-params' export const metadata: Metadata = { title: 'Access requests', diff --git a/apps/sim/app/api/access-requests/[requestId]/cancel/route.ts b/apps/sim/app/api/access-requests/[requestId]/cancel/route.ts index c887c12d619..f14ddb2bbfa 100644 --- a/apps/sim/app/api/access-requests/[requestId]/cancel/route.ts +++ b/apps/sim/app/api/access-requests/[requestId]/cancel/route.ts @@ -5,8 +5,8 @@ import { internalRateLimits, internalSessionAuth, } from '@/lib/api/server/routes' -import { accessRequestOperations } from '@/lib/permission-access-requests/application/operations' -import { cancelAccessRequest } from '@/lib/permission-access-requests/application/requests' +import { accessRequestOperations } from '@/ee/access-requests/lib/application/operations' +import { cancelAccessRequest } from '@/ee/access-requests/lib/application/requests' export const POST = defineInternalJsonRoute({ contract: cancelAccessRequestContract, diff --git a/apps/sim/app/api/access-requests/discovery/route.ts b/apps/sim/app/api/access-requests/discovery/route.ts index 4e0e645fc41..d01e371eeb9 100644 --- a/apps/sim/app/api/access-requests/discovery/route.ts +++ b/apps/sim/app/api/access-requests/discovery/route.ts @@ -5,8 +5,8 @@ import { internalRateLimits, internalSessionAuth, } from '@/lib/api/server/routes' -import { accessRequestOperations } from '@/lib/permission-access-requests/application/operations' -import { discoverAccessRequests } from '@/lib/permission-access-requests/application/requests' +import { accessRequestOperations } from '@/ee/access-requests/lib/application/operations' +import { discoverAccessRequests } from '@/ee/access-requests/lib/application/requests' export const GET = defineInternalJsonRoute({ contract: discoverAccessRequestsContract, diff --git a/apps/sim/app/api/access-requests/route.ts b/apps/sim/app/api/access-requests/route.ts index 74e2bd961c8..9df80669571 100644 --- a/apps/sim/app/api/access-requests/route.ts +++ b/apps/sim/app/api/access-requests/route.ts @@ -8,11 +8,11 @@ import { internalRateLimits, internalSessionAuth, } from '@/lib/api/server/routes' -import { accessRequestOperations } from '@/lib/permission-access-requests/application/operations' +import { accessRequestOperations } from '@/ee/access-requests/lib/application/operations' import { createAccessRequest, listMyAccessRequests, -} from '@/lib/permission-access-requests/application/requests' +} from '@/ee/access-requests/lib/application/requests' export const GET = defineInternalJsonRoute({ contract: listMyAccessRequestsContract, diff --git a/apps/sim/app/api/organizations/[id]/access-requests/[requestId]/preview/route.ts b/apps/sim/app/api/organizations/[id]/access-requests/[requestId]/preview/route.ts index c4ba646b057..e5bfd549838 100644 --- a/apps/sim/app/api/organizations/[id]/access-requests/[requestId]/preview/route.ts +++ b/apps/sim/app/api/organizations/[id]/access-requests/[requestId]/preview/route.ts @@ -5,8 +5,8 @@ import { internalRateLimits, internalSessionAuth, } from '@/lib/api/server/routes' -import { accessRequestOperations } from '@/lib/permission-access-requests/application/operations' -import { previewAccessRequest } from '@/lib/permission-access-requests/application/review' +import { accessRequestOperations } from '@/ee/access-requests/lib/application/operations' +import { previewAccessRequest } from '@/ee/access-requests/lib/application/review' export const GET = defineInternalJsonRoute({ contract: previewAccessRequestContract, diff --git a/apps/sim/app/api/organizations/[id]/access-requests/[requestId]/resolve/route.ts b/apps/sim/app/api/organizations/[id]/access-requests/[requestId]/resolve/route.ts index 0bc389ec7e9..b0e477a8b2c 100644 --- a/apps/sim/app/api/organizations/[id]/access-requests/[requestId]/resolve/route.ts +++ b/apps/sim/app/api/organizations/[id]/access-requests/[requestId]/resolve/route.ts @@ -5,8 +5,8 @@ import { internalRateLimits, internalSessionAuth, } from '@/lib/api/server/routes' -import { accessRequestOperations } from '@/lib/permission-access-requests/application/operations' -import { resolveAccessRequest } from '@/lib/permission-access-requests/application/review' +import { accessRequestOperations } from '@/ee/access-requests/lib/application/operations' +import { resolveAccessRequest } from '@/ee/access-requests/lib/application/review' export const POST = defineInternalJsonRoute({ contract: resolveAccessRequestContract, diff --git a/apps/sim/app/api/organizations/[id]/access-requests/route.ts b/apps/sim/app/api/organizations/[id]/access-requests/route.ts index f68a80694bb..dae84fefaa7 100644 --- a/apps/sim/app/api/organizations/[id]/access-requests/route.ts +++ b/apps/sim/app/api/organizations/[id]/access-requests/route.ts @@ -5,8 +5,8 @@ import { internalRateLimits, internalSessionAuth, } from '@/lib/api/server/routes' -import { accessRequestOperations } from '@/lib/permission-access-requests/application/operations' -import { listOrganizationAccessRequests } from '@/lib/permission-access-requests/application/requests' +import { accessRequestOperations } from '@/ee/access-requests/lib/application/operations' +import { listOrganizationAccessRequests } from '@/ee/access-requests/lib/application/requests' export const GET = defineInternalJsonRoute({ contract: listOrganizationAccessRequestsContract, diff --git a/apps/sim/app/api/organizations/[id]/access-requests/settings/route.ts b/apps/sim/app/api/organizations/[id]/access-requests/settings/route.ts index 6f4ceec0c09..00196e574a6 100644 --- a/apps/sim/app/api/organizations/[id]/access-requests/settings/route.ts +++ b/apps/sim/app/api/organizations/[id]/access-requests/settings/route.ts @@ -8,11 +8,11 @@ import { internalRateLimits, internalSessionAuth, } from '@/lib/api/server/routes' -import { accessRequestOperations } from '@/lib/permission-access-requests/application/operations' +import { accessRequestOperations } from '@/ee/access-requests/lib/application/operations' import { getAccessRequestSettings, updateAccessRequestSettings, -} from '@/lib/permission-access-requests/application/requests' +} from '@/ee/access-requests/lib/application/requests' export const GET = defineInternalJsonRoute({ contract: getAccessRequestSettingsContract, diff --git a/apps/sim/app/workspace/[workspaceId]/access-requests/loading.tsx b/apps/sim/app/workspace/[workspaceId]/access-requests/loading.tsx index 4eb54fb68e8..5ee4cac94d1 100644 --- a/apps/sim/app/workspace/[workspaceId]/access-requests/loading.tsx +++ b/apps/sim/app/workspace/[workspaceId]/access-requests/loading.tsx @@ -1,4 +1,4 @@ -import { AccessRequestsLoading } from '@/components/access-requests/access-requests-loading' +import { AccessRequestsLoading } from '@/ee/access-requests/components/access-requests-loading' export default function Loading() { return diff --git a/apps/sim/app/workspace/[workspaceId]/access-requests/page.tsx b/apps/sim/app/workspace/[workspaceId]/access-requests/page.tsx index b3d49e88885..fa84a020a79 100644 --- a/apps/sim/app/workspace/[workspaceId]/access-requests/page.tsx +++ b/apps/sim/app/workspace/[workspaceId]/access-requests/page.tsx @@ -1,7 +1,7 @@ import { Suspense } from 'react' import type { Metadata } from 'next' -import { AccessRequestsLoading } from '@/components/access-requests/access-requests-loading' -import { MyAccessRequests } from '@/components/access-requests/my-access-requests' +import { AccessRequestsLoading } from '@/ee/access-requests/components/access-requests-loading' +import { MyAccessRequests } from '@/ee/access-requests/components/my-access-requests' export const metadata: Metadata = { title: 'My access requests' } diff --git a/apps/sim/app/workspace/[workspaceId]/files/files.tsx b/apps/sim/app/workspace/[workspaceId]/files/files.tsx index 610456cd742..5c98c2aaeba 100644 --- a/apps/sim/app/workspace/[workspaceId]/files/files.tsx +++ b/apps/sim/app/workspace/[workspaceId]/files/files.tsx @@ -24,7 +24,6 @@ import { getErrorMessage, toError } from '@sim/utils/errors' import { useParams, useRouter } from 'next/navigation' import { useQueryStates } from 'nuqs' import { usePostHog } from 'posthog-js/react' -import { PermissionAccessBoundary } from '@/components/access-requests/permission-access-boundary' import { getDocumentIcon } from '@/components/icons/document-icons' import { useLimitUpgradeToast } from '@/lib/billing/client' import { captureEvent } from '@/lib/posthog/client' @@ -137,6 +136,7 @@ import { } from '@/app/workspace/[workspaceId]/files/untitled-title' import { useRegisterGlobalCommands } from '@/app/workspace/[workspaceId]/providers/global-commands-provider' import { useUserPermissionsContext } from '@/app/workspace/[workspaceId]/providers/workspace-permissions-provider' +import { PermissionAccessBoundary } from '@/ee/access-requests/components/permission-access-boundary' import { usePinItem, usePinnedIds, useUnpinItem } from '@/hooks/queries/pinned-items' import { useWorkspaceMembersQuery, type WorkspaceMember } from '@/hooks/queries/workspace' import { diff --git a/apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/special-tags/special-tags.tsx b/apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/special-tags/special-tags.tsx index f68a9e8bcfb..c96110df49f 100644 --- a/apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/special-tags/special-tags.tsx +++ b/apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/special-tags/special-tags.tsx @@ -5,7 +5,6 @@ import { cn, Expandable, ExpandableContent, SecretReveal, Tooltip, toast } from import { ArrowRight, Check, ChevronDown, SquareArrowUpRight, TerminalWindow } from '@sim/emcn/icons' import { isRecordLike } from '@sim/utils/object' import { useParams } from 'next/navigation' -import { MemberLimitRequestAction } from '@/components/access-requests/member-limit-request-action' import { useSession } from '@/lib/auth/auth-client' import { buildHostedUpgradeUrl, HOSTED_BILLING_SETTINGS_URL } from '@/lib/billing/upgrade-reasons' import { canManageWorkspaceBilling } from '@/lib/billing/workspace-permissions' @@ -62,6 +61,7 @@ import { useServiceAccountConnectTarget } from '@/app/workspace/[workspaceId]/in import { useWorkspaceHostContext } from '@/app/workspace/[workspaceId]/providers/workspace-host-provider' import { useUserPermissionsContext } from '@/app/workspace/[workspaceId]/providers/workspace-permissions-provider' import { BrandIcon } from '@/blocks/brand-icon' +import { MemberLimitRequestAction } from '@/ee/access-requests/components/member-limit-request-action' import { useUpdateWorkspaceCredential, useWorkspaceCredential, diff --git a/apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/special-tags/usage-upgrade-display.test.tsx b/apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/special-tags/usage-upgrade-display.test.tsx index 77a2ea45758..340b39668d4 100644 --- a/apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/special-tags/usage-upgrade-display.test.tsx +++ b/apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/special-tags/usage-upgrade-display.test.tsx @@ -24,7 +24,7 @@ vi.mock('@/app/workspace/[workspaceId]/providers/workspace-host-provider', () => vi.mock('@/hooks/use-settings-navigation', () => ({ useSettingsNavigation: () => ({ getSettingsHref: () => '/settings/billing' }), })) -vi.mock('@/components/access-requests/member-limit-request-action', () => ({ +vi.mock('@/ee/access-requests/components/member-limit-request-action', () => ({ MemberLimitRequestAction: () => , })) diff --git a/apps/sim/app/workspace/[workspaceId]/home/home.tsx b/apps/sim/app/workspace/[workspaceId]/home/home.tsx index ff7515d1711..56846b001d5 100644 --- a/apps/sim/app/workspace/[workspaceId]/home/home.tsx +++ b/apps/sim/app/workspace/[workspaceId]/home/home.tsx @@ -19,7 +19,6 @@ import { useQueryClient } from '@tanstack/react-query' import { useParams, useRouter } from 'next/navigation' import { useQueryState } from 'nuqs' import { usePostHog } from 'posthog-js/react' -import { PermissionAccessBoundary } from '@/components/access-requests/permission-access-boundary' import { requestJson } from '@/lib/api/client/request' import { createWorkflowContract } from '@/lib/api/contracts' import { @@ -45,6 +44,7 @@ import { resolveResourceSelectionUpdate, } from '@/app/workspace/[workspaceId]/home/resource-view-policy' import { resourceParam, resourceUrlKeys } from '@/app/workspace/[workspaceId]/home/search-params' +import { PermissionAccessBoundary } from '@/ee/access-requests/components/permission-access-boundary' import { useFolders } from '@/hooks/queries/folders' import { useMarkMothershipChatRead } from '@/hooks/queries/mothership-chats' import { useWorkflows } from '@/hooks/queries/workflows' diff --git a/apps/sim/app/workspace/[workspaceId]/integrations/[block]/page.tsx b/apps/sim/app/workspace/[workspaceId]/integrations/[block]/page.tsx index 51890cea304..b363f80287d 100644 --- a/apps/sim/app/workspace/[workspaceId]/integrations/[block]/page.tsx +++ b/apps/sim/app/workspace/[workspaceId]/integrations/[block]/page.tsx @@ -1,10 +1,10 @@ import { Suspense } from 'react' import type { Metadata } from 'next' import { notFound } from 'next/navigation' -import { PermissionAccessBoundary } from '@/components/access-requests/permission-access-boundary' import { INTEGRATIONS } from '@/lib/integrations' import { IntegrationBlockDetail } from '@/app/workspace/[workspaceId]/integrations/[block]/integration-block-detail' import { IntegrationBlockDetailFallback } from '@/app/workspace/[workspaceId]/integrations/[block]/integration-block-detail-fallback' +import { PermissionAccessBoundary } from '@/ee/access-requests/components/permission-access-boundary' export async function generateMetadata({ params, diff --git a/apps/sim/app/workspace/[workspaceId]/integrations/connected/[credentialId]/page.tsx b/apps/sim/app/workspace/[workspaceId]/integrations/connected/[credentialId]/page.tsx index 4267bc40e60..96e4ce8721e 100644 --- a/apps/sim/app/workspace/[workspaceId]/integrations/connected/[credentialId]/page.tsx +++ b/apps/sim/app/workspace/[workspaceId]/integrations/connected/[credentialId]/page.tsx @@ -1,6 +1,6 @@ import type { Metadata } from 'next' -import { PermissionAccessBoundary } from '@/components/access-requests/permission-access-boundary' import { ConnectedCredentialDetail } from '@/app/workspace/[workspaceId]/integrations/connected/[credentialId]/connected-credential-detail' +import { PermissionAccessBoundary } from '@/ee/access-requests/components/permission-access-boundary' export const metadata: Metadata = { title: 'Connected Integration', diff --git a/apps/sim/app/workspace/[workspaceId]/integrations/integrations.tsx b/apps/sim/app/workspace/[workspaceId]/integrations/integrations.tsx index a1b1ea26755..4f814f592f1 100644 --- a/apps/sim/app/workspace/[workspaceId]/integrations/integrations.tsx +++ b/apps/sim/app/workspace/[workspaceId]/integrations/integrations.tsx @@ -13,7 +13,6 @@ import { } from '@sim/emcn' import { useParams } from 'next/navigation' import { useQueryStates } from 'nuqs' -import { PermissionAccessBoundary } from '@/components/access-requests/permission-access-boundary' import { blockTypeToIconMap, formatIntegrationType, @@ -35,6 +34,7 @@ import { } from '@/app/workspace/[workspaceId]/integrations/search-params' import { SettingsEmptyState } from '@/app/workspace/[workspaceId]/settings/components/settings-empty-state' import { SettingsResourceRow } from '@/app/workspace/[workspaceId]/settings/components/settings-resource-row' +import { PermissionAccessBoundary } from '@/ee/access-requests/components/permission-access-boundary' import { useWorkspaceCredentials, type WorkspaceCredential } from '@/hooks/queries/credentials' import { useDebouncedSearchSetter } from '@/hooks/use-debounced-search-setter' import { usePermissionConfig } from '@/hooks/use-permission-config' diff --git a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/[documentId]/page.tsx b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/[documentId]/page.tsx index a49bbd1ee6d..ceb959622ba 100644 --- a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/[documentId]/page.tsx +++ b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/[documentId]/page.tsx @@ -1,8 +1,8 @@ import { Suspense } from 'react' import type { Metadata } from 'next' -import { PermissionAccessBoundary } from '@/components/access-requests/permission-access-boundary' import { Document } from '@/app/workspace/[workspaceId]/knowledge/[id]/[documentId]/document' import DocumentLoading from '@/app/workspace/[workspaceId]/knowledge/[id]/[documentId]/loading' +import { PermissionAccessBoundary } from '@/ee/access-requests/components/permission-access-boundary' interface DocumentPageProps { params: Promise<{ diff --git a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/page.tsx b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/page.tsx index a441f86dfd8..64fd9cc7de7 100644 --- a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/page.tsx +++ b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/page.tsx @@ -1,8 +1,8 @@ import { Suspense } from 'react' import type { Metadata } from 'next' -import { PermissionAccessBoundary } from '@/components/access-requests/permission-access-boundary' import { KnowledgeBase } from '@/app/workspace/[workspaceId]/knowledge/[id]/base' import KnowledgeBaseLoading from '@/app/workspace/[workspaceId]/knowledge/[id]/loading' +import { PermissionAccessBoundary } from '@/ee/access-requests/components/permission-access-boundary' interface PageProps { params: Promise<{ diff --git a/apps/sim/app/workspace/[workspaceId]/knowledge/knowledge.test.tsx b/apps/sim/app/workspace/[workspaceId]/knowledge/knowledge.test.tsx index a03d3348d72..36a3e9e6b98 100644 --- a/apps/sim/app/workspace/[workspaceId]/knowledge/knowledge.test.tsx +++ b/apps/sim/app/workspace/[workspaceId]/knowledge/knowledge.test.tsx @@ -37,7 +37,7 @@ vi.mock('@/hooks/use-permission-config', () => ({ usePermissionConfig: () => ({ vi.mock('@/ee/access-control/hooks/permission-groups', () => ({ useUserPermissionConfig: () => ({ data: { config: {} }, isPending: false }), })) -vi.mock('@/hooks/queries/access-requests', () => ({ +vi.mock('@/ee/access-requests/hooks/access-requests', () => ({ useDiscoverAccessRequests: () => ({ data: { enabled: false, entries: [] }, isPending: false }), })) vi.mock('@/app/workspace/[workspaceId]/providers/workspace-permissions-provider', () => ({ diff --git a/apps/sim/app/workspace/[workspaceId]/knowledge/knowledge.tsx b/apps/sim/app/workspace/[workspaceId]/knowledge/knowledge.tsx index 2bcfc892f11..ccda6b899a9 100644 --- a/apps/sim/app/workspace/[workspaceId]/knowledge/knowledge.tsx +++ b/apps/sim/app/workspace/[workspaceId]/knowledge/knowledge.tsx @@ -8,7 +8,6 @@ import { createLogger } from '@sim/logger' import { getErrorMessage } from '@sim/utils/errors' import { useParams, useRouter } from 'next/navigation' import { useQueryStates } from 'nuqs' -import { PermissionAccessBoundary } from '@/components/access-requests/permission-access-boundary' import { MAX_KNOWLEDGE_BATCH_ITEMS } from '@/lib/knowledge/constants' import type { KnowledgeBaseData } from '@/lib/knowledge/types' import { SEARCH_DEBOUNCE_MS } from '@/lib/url-state' @@ -85,6 +84,7 @@ import { useRegisterGlobalCommands } from '@/app/workspace/[workspaceId]/provide import { useUserPermissionsContext } from '@/app/workspace/[workspaceId]/providers/workspace-permissions-provider' import { BrandIcon } from '@/blocks/brand-icon' import { CONNECTOR_META_REGISTRY } from '@/connectors/registry' +import { PermissionAccessBoundary } from '@/ee/access-requests/components/permission-access-boundary' import { useKnowledgeBasesList } from '@/hooks/kb/use-knowledge' import { useCreateFolder, useDeleteFolderMutation, useUpdateFolder } from '@/hooks/queries/folders' import { diff --git a/apps/sim/app/workspace/[workspaceId]/prefetch-access.test.tsx b/apps/sim/app/workspace/[workspaceId]/prefetch-access.test.tsx index f74b6c91084..482b16115b4 100644 --- a/apps/sim/app/workspace/[workspaceId]/prefetch-access.test.tsx +++ b/apps/sim/app/workspace/[workspaceId]/prefetch-access.test.tsx @@ -14,7 +14,7 @@ const mocks = vi.hoisted(() => ({ vi.mock('@/lib/permission-groups/application/read-user-config', () => ({ readUserPermissionConfig: { execute: mocks.policy }, })) -vi.mock('@/lib/permission-access-requests/application/requests', () => ({ +vi.mock('@/ee/access-requests/lib/application/requests', () => ({ discoverAccessRequests: { execute: mocks.discovery }, })) vi.mock('@/lib/api/client/request', () => ({ requestJson: mocks.requestJson })) @@ -39,21 +39,21 @@ vi.mock('@sim/emcn/icons', () => ({ Upload: () => null, BookOpen: () => null, })) -vi.mock('@/components/access-requests/request-access-action', () => ({ +vi.mock('@/ee/access-requests/components/request-access-action', () => ({ RequestAccessAction: ({ pendingRequestId }: { pendingRequestId: string | null }) => ( ), })) -import { PermissionAccessBoundary } from '@/components/access-requests/permission-access-boundary' import { ApiClientError } from '@/lib/api/client/errors' import { getUserPermissionConfigContract } from '@/lib/api/contracts/permission-groups' import { DEFAULT_PERMISSION_GROUP_CONFIG } from '@/lib/permission-groups/fields' import { prefetchWorkspaceAccess } from '@/app/workspace/[workspaceId]/prefetch-access' +import { PermissionAccessBoundary } from '@/ee/access-requests/components/permission-access-boundary' import { accessRequestKeys, workspaceFeatureDiscoveryQuery, -} from '@/hooks/queries/utils/access-request-keys' +} from '@/ee/access-requests/hooks/access-request-keys' import { permissionGroupKeys } from '@/hooks/queries/utils/permission-group-keys' const principal = { kind: 'session', userId: 'viewer', sessionId: 'session' } as const diff --git a/apps/sim/app/workspace/[workspaceId]/prefetch-access.ts b/apps/sim/app/workspace/[workspaceId]/prefetch-access.ts index 182426e174a..1b05ba5913a 100644 --- a/apps/sim/app/workspace/[workspaceId]/prefetch-access.ts +++ b/apps/sim/app/workspace/[workspaceId]/prefetch-access.ts @@ -11,7 +11,7 @@ import { ACCESS_REQUESTS_STALE_TIME, accessRequestKeys, workspaceFeatureDiscoveryQuery, -} from '@/hooks/queries/utils/access-request-keys' +} from '@/ee/access-requests/hooks/access-request-keys' import { PERMISSION_GROUPS_STALE_TIME, permissionGroupKeys, @@ -46,7 +46,7 @@ export async function prefetchWorkspaceAccess( queryKey: accessRequestKeys.discovery(query), queryFn: async () => { const { discoverAccessRequests } = await import( - '@/lib/permission-access-requests/application/requests' + '@/ee/access-requests/lib/application/requests' ) return discoverAccessRequestsContract.response.schema.parse( await discoverAccessRequests.execute({ principal, input: query }) diff --git a/apps/sim/app/workspace/[workspaceId]/settings/[section]/page.test.tsx b/apps/sim/app/workspace/[workspaceId]/settings/[section]/page.test.tsx index 04e42904940..aeffeec2629 100644 --- a/apps/sim/app/workspace/[workspaceId]/settings/[section]/page.test.tsx +++ b/apps/sim/app/workspace/[workspaceId]/settings/[section]/page.test.tsx @@ -28,7 +28,7 @@ const { vi.mock('next/navigation', () => ({ notFound: mockNotFound, redirect: mockRedirect })) vi.mock('@/lib/auth', () => ({ getSession: mockGetSession })) -vi.mock('@/components/access-requests/permission-access-boundary', () => ({ +vi.mock('@/ee/access-requests/components/permission-access-boundary', () => ({ PermissionAccessBoundary: vi.fn(() => null), })) vi.mock('@/lib/settings/application/workspace-section-access', () => ({ diff --git a/apps/sim/app/workspace/[workspaceId]/settings/[section]/page.tsx b/apps/sim/app/workspace/[workspaceId]/settings/[section]/page.tsx index 97cf21c2783..df6f6c2d7b9 100644 --- a/apps/sim/app/workspace/[workspaceId]/settings/[section]/page.tsx +++ b/apps/sim/app/workspace/[workspaceId]/settings/[section]/page.tsx @@ -2,7 +2,6 @@ import { Suspense } from 'react' import { dehydrate, HydrationBoundary } from '@tanstack/react-query' import type { Metadata } from 'next' import { notFound, redirect } from 'next/navigation' -import { PermissionAccessBoundary } from '@/components/access-requests/permission-access-boundary' import { EmptyState } from '@/components/empty-state/empty-state' import { getOrganizationSettingsHref, @@ -13,6 +12,7 @@ import { authorizeWorkspaceSettingsSection } from '@/lib/settings/application/wo import { getWorkspaceHostContextForViewer } from '@/lib/workspaces/host-context' import { getQueryClient } from '@/app/_shell/providers/get-query-client' import { resolveSettingsSection } from '@/app/workspace/[workspaceId]/settings/navigation' +import { PermissionAccessBoundary } from '@/ee/access-requests/components/permission-access-boundary' import { SECTION_PREFETCHERS } from './prefetch' import { SettingsPage } from './settings' diff --git a/apps/sim/app/workspace/[workspaceId]/settings/[section]/settings.tsx b/apps/sim/app/workspace/[workspaceId]/settings/[section]/settings.tsx index 016de4cb3e4..997bf5af779 100644 --- a/apps/sim/app/workspace/[workspaceId]/settings/[section]/settings.tsx +++ b/apps/sim/app/workspace/[workspaceId]/settings/[section]/settings.tsx @@ -3,7 +3,6 @@ import { useEffect } from 'react' import dynamic from 'next/dynamic' import { usePostHog } from 'posthog-js/react' -import { PermissionAccessBoundary } from '@/components/access-requests/permission-access-boundary' import { getSettingsPermissionConfigKey } from '@/components/settings/navigation' import { useSession } from '@/lib/auth/auth-client' import { useDeploymentShape } from '@/lib/core/config/deployment-shape' @@ -15,6 +14,7 @@ import { getSettingsSectionMeta, type SettingsSection, } from '@/app/workspace/[workspaceId]/settings/navigation' +import { PermissionAccessBoundary } from '@/ee/access-requests/components/permission-access-boundary' const Admin = dynamic(() => import('@/app/workspace/[workspaceId]/settings/components/admin/admin').then((m) => m.Admin) diff --git a/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/page.tsx b/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/page.tsx index 152bd121970..702187a5ab6 100644 --- a/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/page.tsx +++ b/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/page.tsx @@ -1,7 +1,7 @@ import { Suspense } from 'react' import type { Metadata } from 'next' -import { PermissionAccessBoundary } from '@/components/access-requests/permission-access-boundary' import TableLoading from '@/app/workspace/[workspaceId]/tables/[tableId]/loading' +import { PermissionAccessBoundary } from '@/ee/access-requests/components/permission-access-boundary' import { Table } from './table' export const metadata: Metadata = { diff --git a/apps/sim/app/workspace/[workspaceId]/tables/tables.tsx b/apps/sim/app/workspace/[workspaceId]/tables/tables.tsx index 4c68bbdb44c..56257d6dbcc 100644 --- a/apps/sim/app/workspace/[workspaceId]/tables/tables.tsx +++ b/apps/sim/app/workspace/[workspaceId]/tables/tables.tsx @@ -8,7 +8,6 @@ import { createLogger } from '@sim/logger' import { getErrorMessage } from '@sim/utils/errors' import { useParams, useRouter } from 'next/navigation' import { useQueryStates } from 'nuqs' -import { PermissionAccessBoundary } from '@/components/access-requests/permission-access-boundary' import type { TableDefinition } from '@/lib/table' import { generateUniqueTableName, MAX_TABLE_BATCH_ITEMS } from '@/lib/table/constants' import { SEARCH_DEBOUNCE_MS } from '@/lib/url-state' @@ -80,6 +79,7 @@ import { tablesSortParams, tablesUrlKeys, } from '@/app/workspace/[workspaceId]/tables/search-params' +import { PermissionAccessBoundary } from '@/ee/access-requests/components/permission-access-boundary' import { useCreateFolder, useDeleteFolderMutation, useUpdateFolder } from '@/hooks/queries/folders' import { usePinItem, usePinnedIds, useUnpinItem } from '@/hooks/queries/pinned-items' import { diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/toolbar/toolbar.test.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/toolbar/toolbar.test.tsx index 9d5ae83298f..71d3b176bd0 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/toolbar/toolbar.test.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/toolbar/toolbar.test.tsx @@ -82,10 +82,10 @@ vi.mock('@/hooks/use-permission-config', () => ({ isBlockRequestable: (type: string) => type.startsWith('locked-'), }), })) -vi.mock('@/components/access-requests/permission-access-boundary', () => ({ +vi.mock('@/ee/access-requests/components/permission-access-boundary', () => ({ useWorkspaceAccessRequestFeatures: discovery, })) -vi.mock('@/components/access-requests/request-access-action', () => ({ +vi.mock('@/ee/access-requests/components/request-access-action', () => ({ RequestAccessModal: ({ label, onClose }: { label: string; onClose: () => void }) => (
Request {label} diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/toolbar/toolbar.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/toolbar/toolbar.tsx index e4323e2c711..09ede00b538 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/toolbar/toolbar.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/toolbar/toolbar.tsx @@ -24,8 +24,6 @@ import { import { ChevronDown, Lock, Search } from '@sim/emcn/icons' import { useParams } from 'next/navigation' import { usePostHog } from 'posthog-js/react' -import { useWorkspaceAccessRequestFeatures } from '@/components/access-requests/permission-access-boundary' -import { RequestAccessModal } from '@/components/access-requests/request-access-action' import { captureEvent } from '@/lib/posthog/client' import { getTriggersForSidebar, hasTriggerCapability } from '@/lib/workflows/triggers/trigger-utils' import { @@ -41,6 +39,8 @@ import { useCustomBlockOverlayVersion } from '@/blocks/custom/client-overlay' import { getCustomBlockTile } from '@/blocks/custom/custom-block-icon' import { getCanonicalBlocksByCategory } from '@/blocks/registry' import type { BlockConfig } from '@/blocks/types' +import { useWorkspaceAccessRequestFeatures } from '@/ee/access-requests/components/permission-access-boundary' +import { RequestAccessModal } from '@/ee/access-requests/components/request-access-action' import { useOrgBrandConfig } from '@/ee/whitelabeling/components/branding-provider' import { useCustomBlocks } from '@/hooks/queries/custom-blocks' import { usePermissionConfig } from '@/hooks/use-permission-config' diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/panel.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/panel.tsx index cd6873ce25e..5f894cfc5f3 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/panel.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/panel.tsx @@ -27,7 +27,6 @@ import { useQueryClient } from '@tanstack/react-query' import { useParams, useRouter } from 'next/navigation' import { usePostHog } from 'posthog-js/react' import { useShallow } from 'zustand/react/shallow' -import { RequestAccessModal } from '@/components/access-requests/request-access-action' import { VariableIcon } from '@/components/icons' import { ThinkingLoader } from '@/components/ui' import { requestJson } from '@/lib/api/client/request' @@ -68,7 +67,8 @@ import { useCurrentWorkflow } from '@/app/workspace/[workspaceId]/w/[workflowId] import { useWorkflowExecution } from '@/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-workflow-execution' import { getWorkflowLockToggleIds } from '@/app/workspace/[workspaceId]/w/[workflowId]/utils' import { useDeleteWorkflow, useImportWorkflow } from '@/app/workspace/[workspaceId]/w/hooks' -import { useDiscoverAccessRequests } from '@/hooks/queries/access-requests' +import { RequestAccessModal } from '@/ee/access-requests/components/request-access-action' +import { useDiscoverAccessRequests } from '@/ee/access-requests/hooks/access-requests' import { useCopilotChatSelection } from '@/hooks/queries/copilot-chat-selection' import { type CopilotChatListItem, diff --git a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/search-modal/search-modal.test.tsx b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/search-modal/search-modal.test.tsx index 8b89a41104f..cc1deb58045 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/search-modal/search-modal.test.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/search-modal/search-modal.test.tsx @@ -68,7 +68,7 @@ vi.mock('@/hooks/use-permission-config', () => ({ }), })) -vi.mock('@/hooks/queries/access-requests', () => ({ +vi.mock('@/ee/access-requests/hooks/access-requests', () => ({ useDiscoverAccessRequests: () => ({ data: { enabled: false, entries: [] }, isPending: false }), })) diff --git a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/search-modal/search-modal.tsx b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/search-modal/search-modal.tsx index 0d6017ea30a..85a47af1cf1 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/search-modal/search-modal.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/search-modal/search-modal.tsx @@ -40,7 +40,6 @@ import { Command } from 'cmdk' import { useParams, useRouter } from 'next/navigation' import { usePostHog } from 'posthog-js/react' import { createPortal } from 'react-dom' -import { useWorkspaceAccessRequestFeatures } from '@/components/access-requests/permission-access-boundary' import { supportsAtomicBrowserPanelOcclusion } from '@/lib/browser-agent/transport' import { useDeploymentShape } from '@/lib/core/config/deployment-shape' import { MothershipHandoffStorage } from '@/lib/core/utils/browser-storage' @@ -89,6 +88,7 @@ import { CMDK_SECTION_GAP_CLASS, } from '@/app/workspace/[workspaceId]/w/components/sidebar/constants' import { SIDEBAR_SCROLL_EVENT } from '@/app/workspace/[workspaceId]/w/components/sidebar/sidebar' +import { useWorkspaceAccessRequestFeatures } from '@/ee/access-requests/components/permission-access-boundary' import { useFolderMap } from '@/hooks/queries/folders' import { useKnowledgeBasesQuery } from '@/hooks/queries/kb/knowledge' import { useTablesList } from '@/hooks/queries/tables' diff --git a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/settings-sidebar/settings-sidebar.tsx b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/settings-sidebar/settings-sidebar.tsx index bbe633e516a..c9f4f040c84 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/settings-sidebar/settings-sidebar.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/settings-sidebar/settings-sidebar.tsx @@ -16,7 +16,6 @@ import { import { ArrowUpRight, Building, ChevronLeft, Lock } from '@sim/emcn/icons' import { useQueryClient } from '@tanstack/react-query' import { useParams, usePathname, useRouter } from 'next/navigation' -import { useWorkspaceAccessRequestFeatures } from '@/components/access-requests/permission-access-boundary' import { type DesktopSettingsSurface, getOrganizationSettingsHref, @@ -47,6 +46,7 @@ import { SIDEBAR_RAIL_CHIP_CLASS, SIDEBAR_SECTION_GAP_CLASS, } from '@/app/workspace/[workspaceId]/w/components/sidebar/constants' +import { useWorkspaceAccessRequestFeatures } from '@/ee/access-requests/components/permission-access-boundary' import { useSSOProviders } from '@/ee/sso/hooks/sso' import { useForkingAvailable } from '@/ee/workspace-forking/hooks/use-forking-available' import { useGeneralSettings } from '@/hooks/queries/general-settings' diff --git a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/sidebar.tsx b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/sidebar.tsx index 947d94305e5..2f2d5891a9c 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/sidebar.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/sidebar.tsx @@ -39,7 +39,6 @@ import { import { createLogger } from '@sim/logger' import { useParams, usePathname, useRouter } from 'next/navigation' import { usePostHog } from 'posthog-js/react' -import { useWorkspaceAccessRequestFeatures } from '@/components/access-requests/permission-access-boundary' import { useSession } from '@/lib/auth/auth-client' import { canViewWorkspaceBillingSettings } from '@/lib/billing/workspace-permissions' import { focusVisibleBrowserOmnibox } from '@/lib/browser-agent/renderer-shortcuts' @@ -119,6 +118,7 @@ import { } from '@/app/workspace/[workspaceId]/w/components/sidebar/utils' import { useImportWorkflow } from '@/app/workspace/[workspaceId]/w/hooks' import { useCustomBlockOverlayVersion } from '@/blocks/custom/client-overlay' +import { useWorkspaceAccessRequestFeatures } from '@/ee/access-requests/components/permission-access-boundary' import { useWorkspaceCredentials } from '@/hooks/queries/credentials' import { useFolderMap, useFolders } from '@/hooks/queries/folders' import { type LogFilters, useLogsList } from '@/hooks/queries/logs' diff --git a/apps/sim/ee/README.md b/apps/sim/ee/README.md index 6a7ee3c8d52..c84b39518a3 100644 --- a/apps/sim/ee/README.md +++ b/apps/sim/ee/README.md @@ -7,6 +7,7 @@ for production use. - **SSO (Single Sign-On)**: OIDC and SAML authentication integration - **Access Control**: Permission groups for fine-grained user access management +- **Access Requests**: Members request restricted features or a higher credit cap; organization admins review and apply them. On for every entitled organization unless it opts out - **Whitelabeling**: Custom branding and theming for enterprise deployments - **Directory provisioning (SCIM)**: SCIM 2.0 user and group provisioning from Okta, Microsoft Entra, and other identity providers, with group-to-access mapping diff --git a/apps/sim/ee/access-control/components/access-control-layout.test.tsx b/apps/sim/ee/access-control/components/access-control-layout.test.tsx index 80ee57e878e..e47f7ebcbab 100644 --- a/apps/sim/ee/access-control/components/access-control-layout.test.tsx +++ b/apps/sim/ee/access-control/components/access-control-layout.test.tsx @@ -11,7 +11,7 @@ vi.mock('next/navigation', () => ({ usePathname: () => '/settings/access-control', })) vi.mock('@/ee/access-control/components/group-detail', () => ({ GroupDetail: () => null })) -vi.mock('@/components/access-requests/access-request-review', () => ({ +vi.mock('@/ee/access-requests/components/access-request-review', () => ({ AccessRequestReview: () => null, })) vi.mock('@/ee/access-control/hooks/permission-groups', () => ({ @@ -23,7 +23,7 @@ vi.mock('@/ee/access-control/hooks/permission-groups', () => ({ vi.mock('@/hooks/queries/organization', () => ({ useOrganizationBilling: () => ({ data: undefined, isPending: false }), })) -vi.mock('@/hooks/queries/access-requests', () => ({ +vi.mock('@/ee/access-requests/hooks/access-requests', () => ({ ACCESS_REQUEST_PAGE_SIZE: 25, useOrganizationAccessRequests: mocks.requests, useAccessRequestSettings: () => ({ data: { allowRequests: true }, isPending: false }), diff --git a/apps/sim/ee/access-control/components/access-control.test.tsx b/apps/sim/ee/access-control/components/access-control.test.tsx index bd2718e1684..a3538511c08 100644 --- a/apps/sim/ee/access-control/components/access-control.test.tsx +++ b/apps/sim/ee/access-control/components/access-control.test.tsx @@ -32,7 +32,7 @@ vi.mock('nuqs', () => ({ useQueryState: () => [null, vi.fn()], useQueryStates: () => [{ 'access-view': 'groups' }, vi.fn()], })) -vi.mock('@/components/access-requests/organization-access-requests', () => ({ +vi.mock('@/ee/access-requests/components/organization-access-requests', () => ({ OrganizationAccessRequests: () => null, })) vi.mock('@/app/workspace/[workspaceId]/settings/components/settings-empty-state', () => ({ diff --git a/apps/sim/ee/access-control/components/access-control.tsx b/apps/sim/ee/access-control/components/access-control.tsx index 10869e2f3e3..e013167a580 100644 --- a/apps/sim/ee/access-control/components/access-control.tsx +++ b/apps/sim/ee/access-control/components/access-control.tsx @@ -18,11 +18,6 @@ import { createLogger } from '@sim/logger' import { getErrorMessage } from '@sim/utils/errors' import { useParams } from 'next/navigation' import { useQueryState, useQueryStates } from 'nuqs' -import { OrganizationAccessRequests } from '@/components/access-requests/organization-access-requests' -import { - accessRequestUrlOptions, - accessReviewSearchParams, -} from '@/components/access-requests/search-params' import { isEnterprise } from '@/lib/billing/plan-helpers' import { useDeploymentShape } from '@/lib/core/config/deployment-shape' import { @@ -54,6 +49,11 @@ import { usePermissionGroups, useUserPermissionConfig, } from '@/ee/access-control/hooks/permission-groups' +import { OrganizationAccessRequests } from '@/ee/access-requests/components/organization-access-requests' +import { + accessRequestUrlOptions, + accessReviewSearchParams, +} from '@/ee/access-requests/components/search-params' import { useOrganizationBilling } from '@/hooks/queries/organization' const logger = createLogger('AccessControl') diff --git a/apps/sim/lib/permission-access-requests/README.md b/apps/sim/ee/access-requests/README.md similarity index 91% rename from apps/sim/lib/permission-access-requests/README.md rename to apps/sim/ee/access-requests/README.md index 0f18a206667..7d0b04e90c6 100644 --- a/apps/sim/lib/permission-access-requests/README.md +++ b/apps/sim/ee/access-requests/README.md @@ -2,12 +2,11 @@ Members request access from locked features, the block picker, or **My access requests**. Organization owners and administrators review requests in **Access control → Requests**, **Review access requests** in the workspace menu, or through an authenticated email link. The same queue handles increases to an administrator-set member credit cap. -## Rollout +## Deployment 1. Apply migration `0349_permission_access_requests.sql` before deploying the application changes. -2. Enable the global AppConfig `permission-access-requests` flag. Outside AppConfig deployments, set `PERMISSION_ACCESS_REQUESTS_ENABLED=true`. -3. Each organization starts with **Allow users to request permissions** enabled. An explicit organization opt-out disables creation and approval and restores existing feature hiding. History, cancellation, and decline remain available. -4. The existing outbox worker delivers notifications. Email links open authenticated review/history; email never applies a change. +2. Each organization starts with **Allow users to request permissions** enabled. An explicit organization opt-out disables creation and approval and restores existing feature hiding. History, cancellation, and decline remain available. +3. The existing outbox worker delivers notifications. Email links open authenticated review/history; email never applies a change. ## Policy and lifecycle diff --git a/apps/sim/components/access-requests/access-request-review.test.tsx b/apps/sim/ee/access-requests/components/access-request-review.test.tsx similarity index 97% rename from apps/sim/components/access-requests/access-request-review.test.tsx rename to apps/sim/ee/access-requests/components/access-request-review.test.tsx index 02c969b500f..dc7366e0aaa 100644 --- a/apps/sim/components/access-requests/access-request-review.test.tsx +++ b/apps/sim/ee/access-requests/components/access-request-review.test.tsx @@ -5,7 +5,7 @@ import { act } from 'react' import { toast } from '@sim/emcn' import { createRoot, type Root } from 'react-dom/client' import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' -import { AccessRequestReview } from '@/components/access-requests/access-request-review' +import { AccessRequestReview } from '@/ee/access-requests/components/access-request-review' vi.mock('@sim/emcn', async (importOriginal) => ({ ...(await importOriginal()), @@ -13,7 +13,7 @@ vi.mock('@sim/emcn', async (importOriginal) => ({ })) const mocks = vi.hoisted(() => ({ preview: vi.fn(), resolve: vi.fn() })) -vi.mock('@/hooks/queries/access-requests', () => ({ +vi.mock('@/ee/access-requests/hooks/access-requests', () => ({ useAccessRequestPreview: mocks.preview, useResolveAccessRequest: mocks.resolve, })) diff --git a/apps/sim/components/access-requests/access-request-review.tsx b/apps/sim/ee/access-requests/components/access-request-review.tsx similarity index 96% rename from apps/sim/components/access-requests/access-request-review.tsx rename to apps/sim/ee/access-requests/components/access-request-review.tsx index db68369704f..6772705a1fc 100644 --- a/apps/sim/components/access-requests/access-request-review.tsx +++ b/apps/sim/ee/access-requests/components/access-request-review.tsx @@ -11,9 +11,12 @@ import { ChipModalHeader, toast, } from '@sim/emcn' -import { PolicyChanges } from '@/components/access-requests/policy-changes' -import { ACCESS_REQUEST_STATUS_LABELS } from '@/components/access-requests/status' -import { useAccessRequestPreview, useResolveAccessRequest } from '@/hooks/queries/access-requests' +import { PolicyChanges } from '@/ee/access-requests/components/policy-changes' +import { ACCESS_REQUEST_STATUS_LABELS } from '@/ee/access-requests/components/status' +import { + useAccessRequestPreview, + useResolveAccessRequest, +} from '@/ee/access-requests/hooks/access-requests' interface AccessRequestReviewProps { organizationId: string diff --git a/apps/sim/components/access-requests/access-requests-loading.tsx b/apps/sim/ee/access-requests/components/access-requests-loading.tsx similarity index 100% rename from apps/sim/components/access-requests/access-requests-loading.tsx rename to apps/sim/ee/access-requests/components/access-requests-loading.tsx diff --git a/apps/sim/components/access-requests/member-limit-request-action.tsx b/apps/sim/ee/access-requests/components/member-limit-request-action.tsx similarity index 82% rename from apps/sim/components/access-requests/member-limit-request-action.tsx rename to apps/sim/ee/access-requests/components/member-limit-request-action.tsx index f174e442c38..f02409de2ad 100644 --- a/apps/sim/components/access-requests/member-limit-request-action.tsx +++ b/apps/sim/ee/access-requests/components/member-limit-request-action.tsx @@ -1,8 +1,8 @@ 'use client' -import { RequestAccessAction } from '@/components/access-requests/request-access-action' import type { AccessRequestScope } from '@/lib/api/contracts/access-requests' -import { useDiscoverAccessRequests } from '@/hooks/queries/access-requests' +import { RequestAccessAction } from '@/ee/access-requests/components/request-access-action' +import { useDiscoverAccessRequests } from '@/ee/access-requests/hooks/access-requests' interface MemberLimitRequestActionProps { scope: AccessRequestScope diff --git a/apps/sim/components/access-requests/my-access-request-details.tsx b/apps/sim/ee/access-requests/components/my-access-request-details.tsx similarity index 94% rename from apps/sim/components/access-requests/my-access-request-details.tsx rename to apps/sim/ee/access-requests/components/my-access-request-details.tsx index 5eb44c1e1fc..12b69995577 100644 --- a/apps/sim/components/access-requests/my-access-request-details.tsx +++ b/apps/sim/ee/access-requests/components/my-access-request-details.tsx @@ -11,9 +11,12 @@ import { ChipTag, toast, } from '@sim/emcn' -import { ACCESS_REQUEST_STATUS_LABELS } from '@/components/access-requests/status' import type { AccessRequestScope } from '@/lib/api/contracts/access-requests' -import { useCancelAccessRequest, useMyAccessRequests } from '@/hooks/queries/access-requests' +import { ACCESS_REQUEST_STATUS_LABELS } from '@/ee/access-requests/components/status' +import { + useCancelAccessRequest, + useMyAccessRequests, +} from '@/ee/access-requests/hooks/access-requests' interface MyAccessRequestDetailsProps { scope: AccessRequestScope diff --git a/apps/sim/components/access-requests/my-access-requests.test.tsx b/apps/sim/ee/access-requests/components/my-access-requests.test.tsx similarity index 96% rename from apps/sim/components/access-requests/my-access-requests.test.tsx rename to apps/sim/ee/access-requests/components/my-access-requests.test.tsx index 2913b635dd8..b62b94f4232 100644 --- a/apps/sim/components/access-requests/my-access-requests.test.tsx +++ b/apps/sim/ee/access-requests/components/my-access-requests.test.tsx @@ -5,7 +5,7 @@ import { act } from 'react' import { NuqsTestingAdapter } from 'nuqs/adapters/testing' import { createRoot, type Root } from 'react-dom/client' import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' -import { MyAccessRequests } from '@/components/access-requests/my-access-requests' +import { MyAccessRequests } from '@/ee/access-requests/components/my-access-requests' const mocks = vi.hoisted(() => ({ mine: vi.fn(), @@ -13,7 +13,7 @@ const mocks = vi.hoisted(() => ({ cancel: vi.fn(), url: vi.fn(), })) -vi.mock('@/hooks/queries/access-requests', () => ({ +vi.mock('@/ee/access-requests/hooks/access-requests', () => ({ ACCESS_REQUEST_PAGE_SIZE: 25, useMyAccessRequests: mocks.mine, useDiscoverAccessRequests: mocks.discovery, diff --git a/apps/sim/components/access-requests/my-access-requests.tsx b/apps/sim/ee/access-requests/components/my-access-requests.tsx similarity index 93% rename from apps/sim/components/access-requests/my-access-requests.tsx rename to apps/sim/ee/access-requests/components/my-access-requests.tsx index 3504065a114..fe9a579f934 100644 --- a/apps/sim/components/access-requests/my-access-requests.tsx +++ b/apps/sim/ee/access-requests/components/my-access-requests.tsx @@ -3,27 +3,27 @@ import { Chip, ChipInput, ChipLink, ChipSwitch, ChipTag } from '@sim/emcn' import { Lock, Search } from '@sim/emcn/icons' import { useQueryStates } from 'nuqs' -import { MyAccessRequestDetails } from '@/components/access-requests/my-access-request-details' -import { RequestAccessAction } from '@/components/access-requests/request-access-action' -import { - accessRequestSearchParams, - accessRequestUrlOptions, -} from '@/components/access-requests/search-params' -import { ACCESS_REQUEST_STATUS_LABELS } from '@/components/access-requests/status' import { EmptyState } from '@/components/empty-state/empty-state' import type { AccessRequestScope } from '@/lib/api/contracts/access-requests' import { WORKSPACES_PATH } from '@/lib/navigation/paths' -import { ACCESS_REQUEST_MAX_SEARCH_LENGTH } from '@/lib/permission-access-requests/constants' import { SEARCH_DEBOUNCE_MS } from '@/lib/url-state' import { RESOURCE_LIST_STACK, SettingsResourceRow, } from '@/app/workspace/[workspaceId]/settings/components/settings-resource-row' +import { MyAccessRequestDetails } from '@/ee/access-requests/components/my-access-request-details' +import { RequestAccessAction } from '@/ee/access-requests/components/request-access-action' +import { + accessRequestSearchParams, + accessRequestUrlOptions, +} from '@/ee/access-requests/components/search-params' +import { ACCESS_REQUEST_STATUS_LABELS } from '@/ee/access-requests/components/status' import { ACCESS_REQUEST_PAGE_SIZE, useDiscoverAccessRequests, useMyAccessRequests, -} from '@/hooks/queries/access-requests' +} from '@/ee/access-requests/hooks/access-requests' +import { ACCESS_REQUEST_MAX_SEARCH_LENGTH } from '@/ee/access-requests/lib/constants' import { useDebounce } from '@/hooks/use-debounce' import { useDebouncedSearchSetter } from '@/hooks/use-debounced-search-setter' diff --git a/apps/sim/components/access-requests/organization-access-requests.test.tsx b/apps/sim/ee/access-requests/components/organization-access-requests.test.tsx similarity index 95% rename from apps/sim/components/access-requests/organization-access-requests.test.tsx rename to apps/sim/ee/access-requests/components/organization-access-requests.test.tsx index 216b03924ed..22a170ba1e4 100644 --- a/apps/sim/components/access-requests/organization-access-requests.test.tsx +++ b/apps/sim/ee/access-requests/components/organization-access-requests.test.tsx @@ -11,17 +11,17 @@ const mocks = vi.hoisted(() => ({ mutate: vi.fn(), refetch: vi.fn(), })) -vi.mock('@/hooks/queries/access-requests', () => ({ +vi.mock('@/ee/access-requests/hooks/access-requests', () => ({ ACCESS_REQUEST_PAGE_SIZE: 25, useAccessRequestSettings: mocks.settings, useOrganizationAccessRequests: mocks.requests, useUpdateAccessRequestSettings: mocks.update, })) -vi.mock('@/components/access-requests/access-request-review', () => ({ +vi.mock('@/ee/access-requests/components/access-request-review', () => ({ AccessRequestReview: () => null, })) -import { OrganizationAccessRequests } from '@/components/access-requests/organization-access-requests' +import { OrganizationAccessRequests } from '@/ee/access-requests/components/organization-access-requests' describe('organization access request settings', () => { let container: HTMLDivElement diff --git a/apps/sim/components/access-requests/organization-access-requests.tsx b/apps/sim/ee/access-requests/components/organization-access-requests.tsx similarity index 95% rename from apps/sim/components/access-requests/organization-access-requests.tsx rename to apps/sim/ee/access-requests/components/organization-access-requests.tsx index 08bb9d4eee8..f31ddb33008 100644 --- a/apps/sim/components/access-requests/organization-access-requests.tsx +++ b/apps/sim/ee/access-requests/components/organization-access-requests.tsx @@ -3,13 +3,6 @@ import { Chip, ChipDropdown, ChipInput, ChipSwitch, ChipTag, toast } from '@sim/emcn' import { Search } from '@sim/emcn/icons' import { useQueryStates } from 'nuqs' -import { AccessRequestReview } from '@/components/access-requests/access-request-review' -import { - accessRequestUrlOptions, - accessReviewSearchParams, -} from '@/components/access-requests/search-params' -import { ACCESS_REQUEST_STATUS_LABELS } from '@/components/access-requests/status' -import { ACCESS_REQUEST_MAX_SEARCH_LENGTH } from '@/lib/permission-access-requests/constants' import { SEARCH_DEBOUNCE_MS } from '@/lib/url-state' import { SettingsEmptyState, @@ -21,12 +14,19 @@ import { SettingsResourceRow, } from '@/app/workspace/[workspaceId]/settings/components/settings-resource-row' import { SettingsSection } from '@/app/workspace/[workspaceId]/settings/components/settings-section/settings-section' +import { AccessRequestReview } from '@/ee/access-requests/components/access-request-review' +import { + accessRequestUrlOptions, + accessReviewSearchParams, +} from '@/ee/access-requests/components/search-params' +import { ACCESS_REQUEST_STATUS_LABELS } from '@/ee/access-requests/components/status' import { ACCESS_REQUEST_PAGE_SIZE, useAccessRequestSettings, useOrganizationAccessRequests, useUpdateAccessRequestSettings, -} from '@/hooks/queries/access-requests' +} from '@/ee/access-requests/hooks/access-requests' +import { ACCESS_REQUEST_MAX_SEARCH_LENGTH } from '@/ee/access-requests/lib/constants' import { useDebounce } from '@/hooks/use-debounce' import { useDebouncedSearchSetter } from '@/hooks/use-debounced-search-setter' diff --git a/apps/sim/components/access-requests/permission-access-boundary.test.tsx b/apps/sim/ee/access-requests/components/permission-access-boundary.test.tsx similarity index 95% rename from apps/sim/components/access-requests/permission-access-boundary.test.tsx rename to apps/sim/ee/access-requests/components/permission-access-boundary.test.tsx index 6dc658227b3..a48b07d88a6 100644 --- a/apps/sim/components/access-requests/permission-access-boundary.test.tsx +++ b/apps/sim/ee/access-requests/components/permission-access-boundary.test.tsx @@ -34,12 +34,14 @@ vi.mock('@sim/emcn/icons', () => ({ BookOpen: () => null, })) vi.mock('@/ee/access-control/hooks/permission-groups', () => ({ useUserPermissionConfig: policy })) -vi.mock('@/hooks/queries/access-requests', () => ({ useDiscoverAccessRequests: discovery })) -vi.mock('@/components/access-requests/request-access-action', () => ({ +vi.mock('@/ee/access-requests/hooks/access-requests', () => ({ + useDiscoverAccessRequests: discovery, +})) +vi.mock('@/ee/access-requests/components/request-access-action', () => ({ RequestAccessAction: () => , })) -import { PermissionAccessBoundary } from '@/components/access-requests/permission-access-boundary' +import { PermissionAccessBoundary } from '@/ee/access-requests/components/permission-access-boundary' describe('PermissionAccessBoundary', () => { let container: HTMLDivElement diff --git a/apps/sim/components/access-requests/permission-access-boundary.tsx b/apps/sim/ee/access-requests/components/permission-access-boundary.tsx similarity index 94% rename from apps/sim/components/access-requests/permission-access-boundary.tsx rename to apps/sim/ee/access-requests/components/permission-access-boundary.tsx index bc111f3e694..77d0f78487b 100644 --- a/apps/sim/components/access-requests/permission-access-boundary.tsx +++ b/apps/sim/ee/access-requests/components/permission-access-boundary.tsx @@ -3,15 +3,15 @@ import type { ReactNode } from 'react' import { Chip } from '@sim/emcn' import { useParams, useRouter } from 'next/navigation' -import { RequestAccessAction } from '@/components/access-requests/request-access-action' import { EmptyState } from '@/components/empty-state/empty-state' import type { BooleanPermissionGroupConfigKey } from '@/lib/permission-groups/features' import { FilesEmptyState } from '@/app/workspace/[workspaceId]/components/resource/components/resource-empty-state/files-empty-state' import { KnowledgeEmptyState } from '@/app/workspace/[workspaceId]/components/resource/components/resource-empty-state/knowledge-empty-state' import { TablesEmptyState } from '@/app/workspace/[workspaceId]/components/resource/components/resource-empty-state/tables-empty-state' import { useUserPermissionConfig } from '@/ee/access-control/hooks/permission-groups' -import { useDiscoverAccessRequests } from '@/hooks/queries/access-requests' -import { workspaceFeatureDiscoveryQuery } from '@/hooks/queries/utils/access-request-keys' +import { RequestAccessAction } from '@/ee/access-requests/components/request-access-action' +import { workspaceFeatureDiscoveryQuery } from '@/ee/access-requests/hooks/access-request-keys' +import { useDiscoverAccessRequests } from '@/ee/access-requests/hooks/access-requests' /** Safe feature metadata shared by navigation and access-required pages. */ export function useWorkspaceAccessRequestFeatures() { diff --git a/apps/sim/components/access-requests/policy-changes.test.ts b/apps/sim/ee/access-requests/components/policy-changes.test.ts similarity index 99% rename from apps/sim/components/access-requests/policy-changes.test.ts rename to apps/sim/ee/access-requests/components/policy-changes.test.ts index ace9e0ae6c6..173bbff5f98 100644 --- a/apps/sim/components/access-requests/policy-changes.test.ts +++ b/apps/sim/ee/access-requests/components/policy-changes.test.ts @@ -5,7 +5,7 @@ import { describe, expect, it } from 'vitest' import { describePolicyChange, describePolicyValue, -} from '@/components/access-requests/policy-changes' +} from '@/ee/access-requests/components/policy-changes' const target = { kind: 'integration', id: 'slack_v2' } as const diff --git a/apps/sim/components/access-requests/policy-changes.tsx b/apps/sim/ee/access-requests/components/policy-changes.tsx similarity index 100% rename from apps/sim/components/access-requests/policy-changes.tsx rename to apps/sim/ee/access-requests/components/policy-changes.tsx diff --git a/apps/sim/components/access-requests/request-access-action.test.tsx b/apps/sim/ee/access-requests/components/request-access-action.test.tsx similarity index 98% rename from apps/sim/components/access-requests/request-access-action.test.tsx rename to apps/sim/ee/access-requests/components/request-access-action.test.tsx index 8a4263d68ff..7a13b40ac72 100644 --- a/apps/sim/components/access-requests/request-access-action.test.tsx +++ b/apps/sim/ee/access-requests/components/request-access-action.test.tsx @@ -4,8 +4,8 @@ import { act } from 'react' import { createRoot, type Root } from 'react-dom/client' import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' -import { RequestAccessAction } from '@/components/access-requests/request-access-action' import type { AccessRequestTarget } from '@/lib/api/contracts/access-requests' +import { RequestAccessAction } from '@/ee/access-requests/components/request-access-action' const mocks = vi.hoisted(() => ({ discovery: vi.fn(), @@ -17,7 +17,7 @@ vi.mock('next/navigation', () => ({ useRouter: () => ({ push: mocks.push }), usePathname: () => '/workspace/workspace', })) -vi.mock('@/hooks/queries/access-requests', () => ({ +vi.mock('@/ee/access-requests/hooks/access-requests', () => ({ useCreateAccessRequest: () => ({ mutate: mocks.create, isPending: false, error: null }), useDiscoverAccessRequests: mocks.discovery, })) diff --git a/apps/sim/components/access-requests/request-access-action.tsx b/apps/sim/ee/access-requests/components/request-access-action.tsx similarity index 97% rename from apps/sim/components/access-requests/request-access-action.tsx rename to apps/sim/ee/access-requests/components/request-access-action.tsx index 34e5703d77f..49f5641ce3d 100644 --- a/apps/sim/components/access-requests/request-access-action.tsx +++ b/apps/sim/ee/access-requests/components/request-access-action.tsx @@ -17,8 +17,11 @@ import { import { Lock } from '@sim/emcn/icons' import { useRouter } from 'next/navigation' import type { AccessRequestScope, AccessRequestTarget } from '@/lib/api/contracts/access-requests' -import { getAccessRequestTargetKey } from '@/lib/permission-groups/access-requests/targets' -import { useCreateAccessRequest, useDiscoverAccessRequests } from '@/hooks/queries/access-requests' +import { + useCreateAccessRequest, + useDiscoverAccessRequests, +} from '@/ee/access-requests/hooks/access-requests' +import { getAccessRequestTargetKey } from '@/ee/access-requests/lib/targets' interface RequestAccessActionProps { scope: AccessRequestScope diff --git a/apps/sim/components/access-requests/search-params.test.ts b/apps/sim/ee/access-requests/components/search-params.test.ts similarity index 95% rename from apps/sim/components/access-requests/search-params.test.ts rename to apps/sim/ee/access-requests/components/search-params.test.ts index 9a6f1a531b0..98846339a08 100644 --- a/apps/sim/components/access-requests/search-params.test.ts +++ b/apps/sim/ee/access-requests/components/search-params.test.ts @@ -5,7 +5,7 @@ import { describe, expect, it } from 'vitest' import { accessRequestSearchParams, accessReviewSearchParams, -} from '@/components/access-requests/search-params' +} from '@/ee/access-requests/components/search-params' describe('access request URL bounds', () => { it.each(['-1', '1.5', '40001', '1e3', '999999999999999999999'])( diff --git a/apps/sim/components/access-requests/search-params.ts b/apps/sim/ee/access-requests/components/search-params.ts similarity index 97% rename from apps/sim/components/access-requests/search-params.ts rename to apps/sim/ee/access-requests/components/search-params.ts index 639adf68736..efe8d9cdb99 100644 --- a/apps/sim/components/access-requests/search-params.ts +++ b/apps/sim/ee/access-requests/components/search-params.ts @@ -4,7 +4,7 @@ import { ACCESS_REQUEST_MAX_ID_LENGTH, ACCESS_REQUEST_MAX_OFFSET, ACCESS_REQUEST_MAX_SEARCH_LENGTH, -} from '@/lib/permission-access-requests/constants' +} from '@/ee/access-requests/lib/constants' const accessRequestPageParser = createParser({ parse(value) { diff --git a/apps/sim/components/access-requests/status.ts b/apps/sim/ee/access-requests/components/status.ts similarity index 100% rename from apps/sim/components/access-requests/status.ts rename to apps/sim/ee/access-requests/components/status.ts diff --git a/apps/sim/hooks/queries/utils/access-request-keys.ts b/apps/sim/ee/access-requests/hooks/access-request-keys.ts similarity index 100% rename from apps/sim/hooks/queries/utils/access-request-keys.ts rename to apps/sim/ee/access-requests/hooks/access-request-keys.ts diff --git a/apps/sim/hooks/queries/access-requests.test.tsx b/apps/sim/ee/access-requests/hooks/access-requests.test.tsx similarity index 98% rename from apps/sim/hooks/queries/access-requests.test.tsx rename to apps/sim/ee/access-requests/hooks/access-requests.test.tsx index 21d97bf12b7..9ce34d47fc1 100644 --- a/apps/sim/hooks/queries/access-requests.test.tsx +++ b/apps/sim/ee/access-requests/hooks/access-requests.test.tsx @@ -14,12 +14,12 @@ import { listMyAccessRequestsContract, resolveAccessRequestContract, } from '@/lib/api/contracts/access-requests' +import { accessRequestKeys } from '@/ee/access-requests/hooks/access-request-keys' import { useDiscoverAccessRequests, useMyAccessRequests, useResolveAccessRequest, -} from '@/hooks/queries/access-requests' -import { accessRequestKeys } from '@/hooks/queries/utils/access-request-keys' +} from '@/ee/access-requests/hooks/access-requests' import { organizationKeys } from '@/hooks/queries/utils/organization-keys' import { workspaceUsageKeys } from '@/hooks/queries/utils/workspace-usage-keys' diff --git a/apps/sim/hooks/queries/access-requests.ts b/apps/sim/ee/access-requests/hooks/access-requests.ts similarity index 98% rename from apps/sim/hooks/queries/access-requests.ts rename to apps/sim/ee/access-requests/hooks/access-requests.ts index dfa5d75d6d0..9b1d31d5c6d 100644 --- a/apps/sim/hooks/queries/access-requests.ts +++ b/apps/sim/ee/access-requests/hooks/access-requests.ts @@ -22,11 +22,11 @@ import type { WorkspaceCreditAvailability, WorkspaceUsageGate, } from '@/lib/api/contracts/workspaces' -import { ACCESS_REQUEST_LIST_PAGE_SIZE } from '@/lib/permission-access-requests/constants' import { ACCESS_REQUESTS_STALE_TIME, accessRequestKeys, -} from '@/hooks/queries/utils/access-request-keys' +} from '@/ee/access-requests/hooks/access-request-keys' +import { ACCESS_REQUEST_LIST_PAGE_SIZE } from '@/ee/access-requests/lib/constants' import { invalidateWorkspaceUsage } from '@/hooks/queries/utils/invalidate-usage' import { organizationKeys } from '@/hooks/queries/utils/organization-keys' import { permissionGroupKeys } from '@/hooks/queries/utils/permission-group-keys' diff --git a/apps/sim/lib/permission-access-requests/application/authorization.test.ts b/apps/sim/ee/access-requests/lib/application/authorization.test.ts similarity index 98% rename from apps/sim/lib/permission-access-requests/application/authorization.test.ts rename to apps/sim/ee/access-requests/lib/application/authorization.test.ts index 679a19206fb..bb0e652f8e8 100644 --- a/apps/sim/lib/permission-access-requests/application/authorization.test.ts +++ b/apps/sim/ee/access-requests/lib/application/authorization.test.ts @@ -18,8 +18,8 @@ import type { DbOrTx } from '@/lib/db/types' import { authorizeAccessRequestScope, loadAccessRequestMembership, -} from '@/lib/permission-access-requests/application/authorization' -import { accessRequestOperations } from '@/lib/permission-access-requests/application/operations' +} from '@/ee/access-requests/lib/application/authorization' +import { accessRequestOperations } from '@/ee/access-requests/lib/application/operations' const principal: SessionPrincipal = { kind: 'session', userId: 'person', sessionId: 'session' } const workspaceScope = { kind: 'workspace' as const, workspaceId: 'workspace' } diff --git a/apps/sim/lib/permission-access-requests/application/authorization.ts b/apps/sim/ee/access-requests/lib/application/authorization.ts similarity index 96% rename from apps/sim/lib/permission-access-requests/application/authorization.ts rename to apps/sim/ee/access-requests/lib/application/authorization.ts index 0dac5ff2e7c..6e613b6c737 100644 --- a/apps/sim/lib/permission-access-requests/application/authorization.ts +++ b/apps/sim/ee/access-requests/lib/application/authorization.ts @@ -15,8 +15,8 @@ import { } from '@/lib/core/application/workspace-authorization' import { OrchestrationError } from '@/lib/core/orchestration/types' import type { DbOrTx } from '@/lib/db/types' -import type { AccessRequestOperation } from '@/lib/permission-access-requests/application/operations' -import type { AccessRequestScope } from '@/lib/permission-groups/access-requests/targets' +import type { AccessRequestOperation } from '@/ee/access-requests/lib/application/operations' +import type { AccessRequestScope } from '@/ee/access-requests/lib/targets' export interface AccessRequestContext { organizationId: string | null diff --git a/apps/sim/lib/permission-access-requests/application/authorized-use-case.test.ts b/apps/sim/ee/access-requests/lib/application/authorized-use-case.test.ts similarity index 96% rename from apps/sim/lib/permission-access-requests/application/authorized-use-case.test.ts rename to apps/sim/ee/access-requests/lib/application/authorized-use-case.test.ts index 607dc7a6963..652f072253b 100644 --- a/apps/sim/lib/permission-access-requests/application/authorized-use-case.test.ts +++ b/apps/sim/ee/access-requests/lib/application/authorized-use-case.test.ts @@ -9,7 +9,7 @@ const mocks = vi.hoisted(() => ({ audit: vi.fn(), outbound: vi.fn(), })) -vi.mock('@/lib/permission-access-requests/application/authorization', () => ({ +vi.mock('@/ee/access-requests/lib/application/authorization', () => ({ authorizeAccessRequestScope: mocks.authorize, })) vi.mock('@/lib/billing/organizations/membership', () => ({ @@ -25,8 +25,8 @@ vi.mock('@/lib/core/network/context.server', () => ({ import type { AccessRequestScope } from '@/lib/api/contracts/access-requests' import { OrchestrationError } from '@/lib/core/orchestration/types' import type { DbOrTx } from '@/lib/db/types' -import { defineAuthorizedAccessRequestUseCase } from '@/lib/permission-access-requests/application/authorized-use-case' -import { accessRequestOperations } from '@/lib/permission-access-requests/application/operations' +import { defineAuthorizedAccessRequestUseCase } from '@/ee/access-requests/lib/application/authorized-use-case' +import { accessRequestOperations } from '@/ee/access-requests/lib/application/operations' const principal: SessionPrincipal = { kind: 'session', userId: 'requester', sessionId: 'session' } const scope: AccessRequestScope = { kind: 'workspace', workspaceId: 'workspace' } diff --git a/apps/sim/lib/permission-access-requests/application/authorized-use-case.ts b/apps/sim/ee/access-requests/lib/application/authorized-use-case.ts similarity index 94% rename from apps/sim/lib/permission-access-requests/application/authorized-use-case.ts rename to apps/sim/ee/access-requests/lib/application/authorized-use-case.ts index 7eea4a76977..3672ee15f84 100644 --- a/apps/sim/lib/permission-access-requests/application/authorized-use-case.ts +++ b/apps/sim/ee/access-requests/lib/application/authorized-use-case.ts @@ -12,9 +12,9 @@ import type { DbOrTx } from '@/lib/db/types' import { type AccessRequestContext, authorizeAccessRequestScope, -} from '@/lib/permission-access-requests/application/authorization' -import type { AccessRequestOperation } from '@/lib/permission-access-requests/application/operations' -import type { AccessRequestScope } from '@/lib/permission-groups/access-requests/targets' +} from '@/ee/access-requests/lib/application/authorization' +import type { AccessRequestOperation } from '@/ee/access-requests/lib/application/operations' +import type { AccessRequestScope } from '@/ee/access-requests/lib/targets' interface AccessRequestPreparationArgs { principal: SessionPrincipal diff --git a/apps/sim/lib/permission-access-requests/application/operations.ts b/apps/sim/ee/access-requests/lib/application/operations.ts similarity index 100% rename from apps/sim/lib/permission-access-requests/application/operations.ts rename to apps/sim/ee/access-requests/lib/application/operations.ts diff --git a/apps/sim/lib/permission-access-requests/application/prepare.ts b/apps/sim/ee/access-requests/lib/application/prepare.ts similarity index 67% rename from apps/sim/lib/permission-access-requests/application/prepare.ts rename to apps/sim/ee/access-requests/lib/application/prepare.ts index a05269b1f9d..11568b99267 100644 --- a/apps/sim/lib/permission-access-requests/application/prepare.ts +++ b/apps/sim/ee/access-requests/lib/application/prepare.ts @@ -1,10 +1,9 @@ import { isOrganizationOnEnterprisePlan } from '@/lib/billing/core/subscription' import { isAccessControlEnabled, isHosted } from '@/lib/core/config/env-flags' -import { isFeatureEnabled } from '@/lib/core/config/feature-flags' import { OrchestrationError } from '@/lib/core/orchestration/types' -import type { AccessRequestContext } from '@/lib/permission-access-requests/application/authorization' -import { loadAccessRequestCatalog } from '@/lib/permission-access-requests/catalog' -import type { AccessRequestTarget } from '@/lib/permission-groups/access-requests/targets' +import type { AccessRequestContext } from '@/ee/access-requests/lib/application/authorization' +import { loadAccessRequestCatalog } from '@/ee/access-requests/lib/catalog' +import type { AccessRequestTarget } from '@/ee/access-requests/lib/targets' /** Resolve deployment metadata before opening a transaction or taking policy locks. */ export async function prepareAccessRequestPolicy( @@ -17,7 +16,7 @@ export async function prepareAccessRequestPolicy( 'forbidden', 'Access requests require an organization-owned workspace' ) - const [catalog, entitled, globalEnabled] = await Promise.all([ + const [catalog, entitled] = await Promise.all([ loadAccessRequestCatalog( { organizationId: context.organizationId, @@ -29,9 +28,8 @@ export async function prepareAccessRequestPolicy( isHosted ? isOrganizationOnEnterprisePlan(context.organizationId) : Promise.resolve(isAccessControlEnabled), - isFeatureEnabled('permission-access-requests'), ]) - return { catalog, entitled, globalEnabled } + return { catalog, entitled } } export type PreparedAccessRequestPolicy = Awaited> diff --git a/apps/sim/lib/permission-access-requests/application/requests.test.ts b/apps/sim/ee/access-requests/lib/application/requests.test.ts similarity index 96% rename from apps/sim/lib/permission-access-requests/application/requests.test.ts rename to apps/sim/ee/access-requests/lib/application/requests.test.ts index 616c518ca57..c3e20698881 100644 --- a/apps/sim/lib/permission-access-requests/application/requests.test.ts +++ b/apps/sim/ee/access-requests/lib/application/requests.test.ts @@ -11,9 +11,9 @@ import { import { dbChainMockFns, queueTableRows, resetDbChainMock } from '@sim/testing' import { beforeEach, describe, expect, it, vi } from 'vitest' import type { AccessRequestRecord, AccessRequestTarget } from '@/lib/api/contracts/access-requests' -import type { StoredAccessRequest } from '@/lib/permission-access-requests/repository' -import { createAccessRequestCatalog } from '@/lib/permission-groups/access-requests/targets' import { DEFAULT_PERMISSION_GROUP_CONFIG } from '@/lib/permission-groups/fields' +import type { StoredAccessRequest } from '@/ee/access-requests/lib/repository' +import { createAccessRequestCatalog } from '@/ee/access-requests/lib/targets' const mocks = vi.hoisted(() => ({ authorize: vi.fn(), @@ -23,7 +23,6 @@ const mocks = vi.hoisted(() => ({ audit: vi.fn(), outbox: vi.fn(), enabled: vi.fn(), - featureEnabled: vi.fn(), enterprise: vi.fn(), catalog: vi.fn(), targets: vi.fn(), @@ -34,7 +33,7 @@ const mocks = vi.hoisted(() => ({ list: vi.fn(), })) -vi.mock('@/lib/permission-access-requests/application/authorization', () => ({ +vi.mock('@/ee/access-requests/lib/application/authorization', () => ({ authorizeAccessRequestScope: mocks.authorize, loadAccessRequestMembership: mocks.membership, })) @@ -46,16 +45,15 @@ vi.mock('@/lib/core/application/authorized-workspace-use-case', () => ({ })) vi.mock('@/lib/core/outbox/service', () => ({ enqueueOutboxEvent: mocks.outbox })) vi.mock('@/lib/permission-groups/locks', () => ({ acquirePermissionGroupOrgLock: mocks.groupLock })) -vi.mock('@/lib/permission-access-requests/settings', () => ({ +vi.mock('@/ee/access-requests/lib/settings', () => ({ isAccessRequestEnabled: mocks.enabled, readAccessRequestSettings: vi.fn(), })) -vi.mock('@/lib/core/config/feature-flags', () => ({ isFeatureEnabled: mocks.featureEnabled })) vi.mock('@/lib/core/config/env-flags', () => ({ isHosted: true, isAccessControlEnabled: true })) vi.mock('@/lib/billing/core/subscription', () => ({ isOrganizationOnEnterprisePlan: mocks.enterprise, })) -vi.mock('@/lib/permission-access-requests/catalog', () => ({ +vi.mock('@/ee/access-requests/lib/catalog', () => ({ loadAccessRequestCatalog: mocks.catalog, listAccessRequestTargets: mocks.targets, getAccessRequestDeploymentUnavailableReason: mocks.deploymentReason, @@ -64,7 +62,7 @@ vi.mock('@/lib/permission-groups/resolve.server', () => ({ resolveWorkspaceGroup: mocks.group, resolveDefaultGroup: mocks.group, })) -vi.mock('@/lib/permission-access-requests/repository', () => ({ +vi.mock('@/ee/access-requests/lib/repository', () => ({ presentAccessRequest: mocks.present, loadStoredAccessRequest: mocks.stored, listAccessRequestRecords: mocks.list, @@ -75,11 +73,11 @@ import { createAccessRequest, discoverAccessRequests, listMyAccessRequests, -} from '@/lib/permission-access-requests/application/requests' +} from '@/ee/access-requests/lib/application/requests' import { PERMISSION_ACCESS_REQUEST_CREATED_EVENT, PERMISSION_ACCESS_REQUEST_DECIDED_EVENT, -} from '@/lib/permission-access-requests/notification-events' +} from '@/ee/access-requests/lib/notification-events' const principal = { kind: 'session', userId: 'requester', sessionId: 'session' } as const const scope = { kind: 'workspace', workspaceId: 'workspace' } as const @@ -152,7 +150,6 @@ beforeEach(() => { mocks.authorize.mockResolvedValue(context) mocks.membership.mockResolvedValue(null) mocks.enabled.mockResolvedValue(true) - mocks.featureEnabled.mockResolvedValue(true) mocks.enterprise.mockResolvedValue(true) mocks.catalog.mockResolvedValue(catalog) mocks.deploymentReason.mockReturnValue(null) diff --git a/apps/sim/lib/permission-access-requests/application/requests.ts b/apps/sim/ee/access-requests/lib/application/requests.ts similarity index 94% rename from apps/sim/lib/permission-access-requests/application/requests.ts rename to apps/sim/ee/access-requests/lib/application/requests.ts index 0f5ed0715ed..e3bf1be02d5 100644 --- a/apps/sim/lib/permission-access-requests/application/requests.ts +++ b/apps/sim/ee/access-requests/lib/application/requests.ts @@ -9,37 +9,44 @@ import { and, count, eq, gte, isNull, or } from 'drizzle-orm' import { OrchestrationError } from '@/lib/core/orchestration/types' import { enqueueOutboxEvent } from '@/lib/core/outbox/service' import type { DbOrTx } from '@/lib/db/types' -import type { AccessRequestContext } from '@/lib/permission-access-requests/application/authorization' -import { loadAccessRequestMembership } from '@/lib/permission-access-requests/application/authorization' -import { defineAuthorizedAccessRequestUseCase } from '@/lib/permission-access-requests/application/authorized-use-case' -import { accessRequestOperations } from '@/lib/permission-access-requests/application/operations' -import { prepareAccessRequestPolicy } from '@/lib/permission-access-requests/application/prepare' +import { acquirePermissionGroupOrgLock } from '@/lib/permission-groups/locks' +import type { AccessRequestContext } from '@/ee/access-requests/lib/application/authorization' +import { loadAccessRequestMembership } from '@/ee/access-requests/lib/application/authorization' +import { defineAuthorizedAccessRequestUseCase } from '@/ee/access-requests/lib/application/authorized-use-case' +import { accessRequestOperations } from '@/ee/access-requests/lib/application/operations' +import { prepareAccessRequestPolicy } from '@/ee/access-requests/lib/application/prepare' import { listAccessRequestTargets, loadAccessRequestCatalog, -} from '@/lib/permission-access-requests/catalog' +} from '@/ee/access-requests/lib/catalog' import { ACCESS_REQUEST_MAX_DAILY_SUBMISSIONS, ACCESS_REQUEST_MAX_PENDING, ACCESS_REQUEST_SUBMISSION_WINDOW_MS, -} from '@/lib/permission-access-requests/constants' +} from '@/ee/access-requests/lib/constants' import { PERMISSION_ACCESS_REQUEST_CREATED_EVENT, PERMISSION_ACCESS_REQUEST_DECIDED_EVENT, -} from '@/lib/permission-access-requests/notification-events' +} from '@/ee/access-requests/lib/notification-events' import { evaluateAccessRequestTarget, loadAccessRequestPolicy, -} from '@/lib/permission-access-requests/policy' +} from '@/ee/access-requests/lib/policy' import { listAccessRequestRecords, loadStoredAccessRequest, presentAccessRequest, -} from '@/lib/permission-access-requests/repository' +} from '@/ee/access-requests/lib/repository' import { isAccessRequestEnabled, readAccessRequestSettings, -} from '@/lib/permission-access-requests/settings' +} from '@/ee/access-requests/lib/settings' +import type { AccessRequestScope } from '@/ee/access-requests/lib/targets' +import { + describeAccessRequestTarget, + getAccessRequestTargetKey, + validateAccessRequestTarget, +} from '@/ee/access-requests/lib/targets' import type { AccessRequestDiscovery, AccessRequestRecord, @@ -47,14 +54,7 @@ import type { AccessRequestStatus, CreateAccessRequestInput, DiscoverAccessRequestsInput, -} from '@/lib/permission-access-requests/types' -import type { AccessRequestScope } from '@/lib/permission-groups/access-requests/targets' -import { - describeAccessRequestTarget, - getAccessRequestTargetKey, - validateAccessRequestTarget, -} from '@/lib/permission-groups/access-requests/targets' -import { acquirePermissionGroupOrgLock } from '@/lib/permission-groups/locks' +} from '@/ee/access-requests/lib/types' function requireOrganization(organizationId: string | null): string { if (!organizationId) @@ -229,7 +229,7 @@ export const createAccessRequest = defineAuthorizedAccessRequestUseCase({ prepared, }): Promise { const organizationId = requireOrganization(context.organizationId) - if (!(await isAccessRequestEnabled(organizationId, executor, prepared.globalEnabled))) + if (!(await isAccessRequestEnabled(organizationId, executor))) throw new OrchestrationError( 'forbidden', 'Access requests are turned off for this organization' diff --git a/apps/sim/lib/permission-access-requests/application/review.test.ts b/apps/sim/ee/access-requests/lib/application/review.test.ts similarity index 95% rename from apps/sim/lib/permission-access-requests/application/review.test.ts rename to apps/sim/ee/access-requests/lib/application/review.test.ts index cc111932b7f..f4abf9fe9a6 100644 --- a/apps/sim/lib/permission-access-requests/application/review.test.ts +++ b/apps/sim/ee/access-requests/lib/application/review.test.ts @@ -12,9 +12,9 @@ import { import { dbChainMockFns, queueTableRows, resetDbChainMock } from '@sim/testing' import { beforeEach, describe, expect, it, vi } from 'vitest' import type { AccessRequestRecord, AccessRequestTarget } from '@/lib/api/contracts/access-requests' -import type { StoredAccessRequest } from '@/lib/permission-access-requests/repository' -import { createAccessRequestCatalog } from '@/lib/permission-groups/access-requests/targets' import { DEFAULT_PERMISSION_GROUP_CONFIG } from '@/lib/permission-groups/fields' +import type { StoredAccessRequest } from '@/ee/access-requests/lib/repository' +import { createAccessRequestCatalog } from '@/ee/access-requests/lib/targets' const mocks = vi.hoisted(() => ({ authorize: vi.fn(), @@ -24,7 +24,6 @@ const mocks = vi.hoisted(() => ({ audit: vi.fn(), outbox: vi.fn(), enabled: vi.fn(), - featureEnabled: vi.fn(), enterprise: vi.fn(), catalog: vi.fn(), deploymentReason: vi.fn(), @@ -35,7 +34,7 @@ const mocks = vi.hoisted(() => ({ setLimit: vi.fn(), })) -vi.mock('@/lib/permission-access-requests/application/authorization', () => ({ +vi.mock('@/ee/access-requests/lib/application/authorization', () => ({ authorizeAccessRequestScope: mocks.authorize, loadAccessRequestMembership: mocks.membership, })) @@ -47,15 +46,14 @@ vi.mock('@/lib/core/application/authorized-workspace-use-case', () => ({ })) vi.mock('@/lib/core/outbox/service', () => ({ enqueueOutboxEvent: mocks.outbox })) vi.mock('@/lib/permission-groups/locks', () => ({ acquirePermissionGroupOrgLock: mocks.groupLock })) -vi.mock('@/lib/permission-access-requests/settings', () => ({ +vi.mock('@/ee/access-requests/lib/settings', () => ({ isAccessRequestEnabled: mocks.enabled, })) -vi.mock('@/lib/core/config/feature-flags', () => ({ isFeatureEnabled: mocks.featureEnabled })) vi.mock('@/lib/core/config/env-flags', () => ({ isHosted: true, isAccessControlEnabled: true })) vi.mock('@/lib/billing/core/subscription', () => ({ isOrganizationOnEnterprisePlan: mocks.enterprise, })) -vi.mock('@/lib/permission-access-requests/catalog', () => ({ +vi.mock('@/ee/access-requests/lib/catalog', () => ({ loadAccessRequestCatalog: mocks.catalog, getAccessRequestDeploymentUnavailableReason: mocks.deploymentReason, })) @@ -63,10 +61,10 @@ vi.mock('@/lib/permission-groups/resolve.server', () => ({ resolveWorkspaceGroup: mocks.group, resolveDefaultGroup: mocks.group, })) -vi.mock('@/lib/permission-access-requests/impact', () => ({ +vi.mock('@/ee/access-requests/lib/impact', () => ({ loadAccessRequestGroupImpact: mocks.impact, })) -vi.mock('@/lib/permission-access-requests/repository', () => ({ +vi.mock('@/ee/access-requests/lib/repository', () => ({ presentAccessRequest: mocks.present, loadStoredAccessRequest: mocks.stored, })) @@ -77,8 +75,8 @@ vi.mock('@/lib/billing/organizations/member-limits', () => ({ import { previewAccessRequest, resolveAccessRequest, -} from '@/lib/permission-access-requests/application/review' -import { PERMISSION_ACCESS_REQUEST_DECIDED_EVENT } from '@/lib/permission-access-requests/notification-events' +} from '@/ee/access-requests/lib/application/review' +import { PERMISSION_ACCESS_REQUEST_DECIDED_EVENT } from '@/ee/access-requests/lib/notification-events' const principal = { kind: 'session', userId: 'admin', sessionId: 'session' } as const const input = { organizationId: 'organization', requestId: 'request' } @@ -176,7 +174,6 @@ beforeEach(() => { }) mocks.membership.mockResolvedValue({ membershipId: 'membership', role: 'read' }) mocks.enabled.mockResolvedValue(true) - mocks.featureEnabled.mockResolvedValue(true) mocks.enterprise.mockResolvedValue(true) mocks.catalog.mockResolvedValue(catalog) mocks.deploymentReason.mockReturnValue(null) diff --git a/apps/sim/lib/permission-access-requests/application/review.ts b/apps/sim/ee/access-requests/lib/application/review.ts similarity index 93% rename from apps/sim/lib/permission-access-requests/application/review.ts rename to apps/sim/ee/access-requests/lib/application/review.ts index 630cd7d4fca..e1a45306dc3 100644 --- a/apps/sim/lib/permission-access-requests/application/review.ts +++ b/apps/sim/ee/access-requests/lib/application/review.ts @@ -9,36 +9,36 @@ import type { WorkspaceUseCaseAuditEntry } from '@/lib/core/application/authoriz import { OrchestrationError } from '@/lib/core/orchestration/types' import { enqueueOutboxEvent } from '@/lib/core/outbox/service' import type { DbOrTx } from '@/lib/db/types' -import { loadAccessRequestMembership } from '@/lib/permission-access-requests/application/authorization' -import { defineAuthorizedAccessRequestUseCase } from '@/lib/permission-access-requests/application/authorized-use-case' -import { accessRequestOperations } from '@/lib/permission-access-requests/application/operations' +import { acquirePermissionGroupOrgLock } from '@/lib/permission-groups/locks' +import { loadAccessRequestMembership } from '@/ee/access-requests/lib/application/authorization' +import { defineAuthorizedAccessRequestUseCase } from '@/ee/access-requests/lib/application/authorized-use-case' +import { accessRequestOperations } from '@/ee/access-requests/lib/application/operations' import { type PreparedAccessRequestPolicy, prepareAccessRequestPolicy, -} from '@/lib/permission-access-requests/application/prepare' -import { loadAccessRequestGroupImpact } from '@/lib/permission-access-requests/impact' -import { PERMISSION_ACCESS_REQUEST_DECIDED_EVENT } from '@/lib/permission-access-requests/notification-events' +} from '@/ee/access-requests/lib/application/prepare' +import { loadAccessRequestGroupImpact } from '@/ee/access-requests/lib/impact' +import { PERMISSION_ACCESS_REQUEST_DECIDED_EVENT } from '@/ee/access-requests/lib/notification-events' import { evaluateAccessRequestTarget, loadAccessRequestPolicy, loadMemberLimit, -} from '@/lib/permission-access-requests/policy' +} from '@/ee/access-requests/lib/policy' import { loadStoredAccessRequest, presentAccessRequest, type StoredAccessRequest, -} from '@/lib/permission-access-requests/repository' +} from '@/ee/access-requests/lib/repository' import { storedAccessRequestDecisionSchema, storedAccessRequestTargetSchema, -} from '@/lib/permission-access-requests/schemas' -import { isAccessRequestEnabled } from '@/lib/permission-access-requests/settings' +} from '@/ee/access-requests/lib/schemas' +import { isAccessRequestEnabled } from '@/ee/access-requests/lib/settings' +import type { AccessRequestScope } from '@/ee/access-requests/lib/targets' import type { AccessRequestPreview, ResolveAccessRequestDecision, -} from '@/lib/permission-access-requests/types' -import type { AccessRequestScope } from '@/lib/permission-groups/access-requests/targets' -import { acquirePermissionGroupOrgLock } from '@/lib/permission-groups/locks' +} from '@/ee/access-requests/lib/types' interface ReviewInput { organizationId: string @@ -139,7 +139,7 @@ async function loadReviewPreview( catalog, currentPolicy ) - const enabled = await isAccessRequestEnabled(row.organizationId, executor, prepared.globalEnabled) + const enabled = await isAccessRequestEnabled(row.organizationId, executor) const audience = policy.group ? await loadAccessRequestGroupImpact( executor, diff --git a/apps/sim/lib/permission-access-requests/catalog-registry.ts b/apps/sim/ee/access-requests/lib/catalog-registry.ts similarity index 99% rename from apps/sim/lib/permission-access-requests/catalog-registry.ts rename to apps/sim/ee/access-requests/lib/catalog-registry.ts index c3678f3ae4a..bb45379fac7 100644 --- a/apps/sim/lib/permission-access-requests/catalog-registry.ts +++ b/apps/sim/ee/access-requests/lib/catalog-registry.ts @@ -11,14 +11,6 @@ import { isIntegrationDeploymentAvailableForVisibility, isOAuthServiceDeploymentAvailable, } from '@/lib/integrations/availability.server' -import { - type AccessRequestCatalog, - type AccessRequestCatalogItem, - type AccessRequestModelItem, - type AccessRequestTarget, - type AccessRequestToolItem, - createAccessRequestCatalog, -} from '@/lib/permission-groups/access-requests/targets' import { resolveAccessControlBlockType, toAccessControlAllowlist, @@ -26,6 +18,14 @@ import { import { getBlockRegistry } from '@/blocks/registry' import { isHiddenUnder } from '@/blocks/visibility/context' import { CONNECTOR_META_REGISTRY } from '@/connectors/registry' +import { + type AccessRequestCatalog, + type AccessRequestCatalogItem, + type AccessRequestModelItem, + type AccessRequestTarget, + type AccessRequestToolItem, + createAccessRequestCatalog, +} from '@/ee/access-requests/lib/targets' import { getStaticProviderModels, PROVIDER_DEFINITIONS } from '@/providers/models' import { filterBlacklistedModels } from '@/providers/utils' import { getToolMetadata } from '@/tools/metadata' diff --git a/apps/sim/lib/permission-access-requests/catalog.test.ts b/apps/sim/ee/access-requests/lib/catalog.test.ts similarity index 99% rename from apps/sim/lib/permission-access-requests/catalog.test.ts rename to apps/sim/ee/access-requests/lib/catalog.test.ts index ad85beb35d3..c0c81cfc667 100644 --- a/apps/sim/lib/permission-access-requests/catalog.test.ts +++ b/apps/sim/ee/access-requests/lib/catalog.test.ts @@ -94,17 +94,17 @@ vi.mock('@/connectors/registry', () => ({ }, })) +import { isBlockTypeAccessControlExempt } from '@/lib/permission-groups/block-access' +import { DEFAULT_PERMISSION_GROUP_CONFIG } from '@/lib/permission-groups/fields' import { getAccessRequestDeploymentUnavailableReason, listAccessRequestTargets, loadAccessRequestCatalog, -} from '@/lib/permission-access-requests/catalog' +} from '@/ee/access-requests/lib/catalog' import { buildAccessRequestPolicyDelta, validateAccessRequestTarget, -} from '@/lib/permission-groups/access-requests/targets' -import { isBlockTypeAccessControlExempt } from '@/lib/permission-groups/block-access' -import { DEFAULT_PERMISSION_GROUP_CONFIG } from '@/lib/permission-groups/fields' +} from '@/ee/access-requests/lib/targets' const context = { userId: 'viewer', organizationId: 'org', workspaceId: 'ws' } diff --git a/apps/sim/lib/permission-access-requests/catalog.ts b/apps/sim/ee/access-requests/lib/catalog.ts similarity index 93% rename from apps/sim/lib/permission-access-requests/catalog.ts rename to apps/sim/ee/access-requests/lib/catalog.ts index 983be1eda05..e6442f3b139 100644 --- a/apps/sim/lib/permission-access-requests/catalog.ts +++ b/apps/sim/ee/access-requests/lib/catalog.ts @@ -6,14 +6,14 @@ import { isSandboxesEnabled, isSsoEnabled, } from '@/lib/core/config/env-flags' -import type { AccessRequestCatalogContext } from '@/lib/permission-access-requests/catalog-registry' +import { PLATFORM_FEATURES } from '@/lib/permission-groups/features' +import { FILE_SHARE_AUTH_TYPES } from '@/lib/permission-groups/fields' +import type { AccessRequestCatalogContext } from '@/ee/access-requests/lib/catalog-registry' import { type AccessRequestCatalog, type AccessRequestTarget, createAccessRequestCatalog, -} from '@/lib/permission-groups/access-requests/targets' -import { PLATFORM_FEATURES } from '@/lib/permission-groups/features' -import { FILE_SHARE_AUTH_TYPES } from '@/lib/permission-groups/fields' +} from '@/ee/access-requests/lib/targets' /** Small navigation and credit-limit checks never load or enumerate the integration registries. */ export async function loadAccessRequestCatalog( @@ -32,7 +32,7 @@ export async function loadAccessRequestCatalog( knowledgeConnectors: [], }) const { loadAccessRequestRegistryCatalog } = await import( - '@/lib/permission-access-requests/catalog-registry' + '@/ee/access-requests/lib/catalog-registry' ) return loadAccessRequestRegistryCatalog(context, targetKind) } diff --git a/apps/sim/lib/permission-access-requests/constants.ts b/apps/sim/ee/access-requests/lib/constants.ts similarity index 100% rename from apps/sim/lib/permission-access-requests/constants.ts rename to apps/sim/ee/access-requests/lib/constants.ts diff --git a/apps/sim/lib/permission-access-requests/impact.postgres.test.ts b/apps/sim/ee/access-requests/lib/impact.postgres.test.ts similarity index 99% rename from apps/sim/lib/permission-access-requests/impact.postgres.test.ts rename to apps/sim/ee/access-requests/lib/impact.postgres.test.ts index 3f9eb90359a..bd36ae5dd62 100644 --- a/apps/sim/lib/permission-access-requests/impact.postgres.test.ts +++ b/apps/sim/ee/access-requests/lib/impact.postgres.test.ts @@ -5,7 +5,7 @@ import { generateId } from '@sim/utils/id' import { drizzle } from 'drizzle-orm/postgres-js' import postgres from 'postgres' import { describe, expect, it, vi } from 'vitest' -import { loadAccessRequestGroupImpact } from '@/lib/permission-access-requests/impact' +import { loadAccessRequestGroupImpact } from '@/ee/access-requests/lib/impact' vi.unmock('@sim/db/schema') vi.unmock('drizzle-orm') diff --git a/apps/sim/lib/permission-access-requests/impact.ts b/apps/sim/ee/access-requests/lib/impact.ts similarity index 98% rename from apps/sim/lib/permission-access-requests/impact.ts rename to apps/sim/ee/access-requests/lib/impact.ts index 2a0ae391b48..66199e0e4a1 100644 --- a/apps/sim/lib/permission-access-requests/impact.ts +++ b/apps/sim/ee/access-requests/lib/impact.ts @@ -8,7 +8,7 @@ import { } from '@sim/db/schema' import { and, count, eq, inArray, isNull, or, type SQL, sql } from 'drizzle-orm' import type { DbOrTx } from '@/lib/db/types' -import type { AccessRequestImpact } from '@/lib/permission-access-requests/types' +import type { AccessRequestImpact } from '@/ee/access-requests/lib/types' /** Order-independent change detector with fixed-size aggregate state instead of sorted row strings. */ function membershipRevision(value: SQL): SQL { diff --git a/apps/sim/lib/permission-access-requests/notification-events.ts b/apps/sim/ee/access-requests/lib/notification-events.ts similarity index 100% rename from apps/sim/lib/permission-access-requests/notification-events.ts rename to apps/sim/ee/access-requests/lib/notification-events.ts diff --git a/apps/sim/lib/permission-access-requests/notifications.test.ts b/apps/sim/ee/access-requests/lib/notifications.test.ts similarity index 97% rename from apps/sim/lib/permission-access-requests/notifications.test.ts rename to apps/sim/ee/access-requests/lib/notifications.test.ts index 9d11dda7fac..2ecee67538f 100644 --- a/apps/sim/lib/permission-access-requests/notifications.test.ts +++ b/apps/sim/ee/access-requests/lib/notifications.test.ts @@ -25,19 +25,19 @@ vi.mock('@/lib/messaging/email/mailer', () => ({ sendEmail: mockSend, hasEmailService: mockHasEmailService, })) -vi.mock('@/lib/permission-access-requests/application/authorization', () => ({ +vi.mock('@/ee/access-requests/lib/application/authorization', () => ({ loadAccessRequestMembership: mockMembership, })) vi.mock('@/lib/core/utils/urls', () => ({ getBaseUrl: () => 'https://sim.example' })) -vi.mock('@/lib/permission-access-requests/settings', () => ({ +vi.mock('@/ee/access-requests/lib/settings', () => ({ isAccessRequestEnabled: mockEnabled, })) import { PERMISSION_ACCESS_REQUEST_CREATED_EVENT, PERMISSION_ACCESS_REQUEST_DECIDED_EVENT, -} from '@/lib/permission-access-requests/notification-events' -import { permissionAccessRequestOutboxHandlers } from '@/lib/permission-access-requests/notifications' +} from '@/ee/access-requests/lib/notification-events' +import { permissionAccessRequestOutboxHandlers } from '@/ee/access-requests/lib/notifications' const request = { id: 'request-one', diff --git a/apps/sim/lib/permission-access-requests/notifications.ts b/apps/sim/ee/access-requests/lib/notifications.ts similarity index 96% rename from apps/sim/lib/permission-access-requests/notifications.ts rename to apps/sim/ee/access-requests/lib/notifications.ts index 5516dde5dd7..0ef80c6ae7f 100644 --- a/apps/sim/lib/permission-access-requests/notifications.ts +++ b/apps/sim/ee/access-requests/lib/notifications.ts @@ -13,12 +13,12 @@ import { } from '@/lib/core/outbox/service' import { getBaseUrl } from '@/lib/core/utils/urls' import { hasEmailService, sendEmail } from '@/lib/messaging/email/mailer' -import { loadAccessRequestMembership } from '@/lib/permission-access-requests/application/authorization' +import { loadAccessRequestMembership } from '@/ee/access-requests/lib/application/authorization' import { PERMISSION_ACCESS_REQUEST_CREATED_EVENT, PERMISSION_ACCESS_REQUEST_DECIDED_EVENT, -} from '@/lib/permission-access-requests/notification-events' -import { isAccessRequestEnabled } from '@/lib/permission-access-requests/settings' +} from '@/ee/access-requests/lib/notification-events' +import { isAccessRequestEnabled } from '@/ee/access-requests/lib/settings' const logger = createLogger('PermissionAccessRequestNotifications') const ADMIN_RECIPIENT_PAGE_SIZE = 50 diff --git a/apps/sim/lib/permission-access-requests/policy.ts b/apps/sim/ee/access-requests/lib/policy.ts similarity index 92% rename from apps/sim/lib/permission-access-requests/policy.ts rename to apps/sim/ee/access-requests/lib/policy.ts index 29c4459f2c3..31bac8dc673 100644 --- a/apps/sim/lib/permission-access-requests/policy.ts +++ b/apps/sim/ee/access-requests/lib/policy.ts @@ -5,12 +5,10 @@ import { isOrganizationOnEnterprisePlan } from '@/lib/billing/core/subscription' import { dollarsToCredits } from '@/lib/billing/credits/conversion' import { isAccessControlEnabled, isHosted } from '@/lib/core/config/env-flags' import type { DbOrTx } from '@/lib/db/types' -import type { AccessRequestContext } from '@/lib/permission-access-requests/application/authorization' -import { getAccessRequestDeploymentUnavailableReason } from '@/lib/permission-access-requests/catalog' -import type { - AccessRequestScope, - AccessRequestTarget, -} from '@/lib/permission-groups/access-requests/targets' +import { resolveDefaultGroup, resolveWorkspaceGroup } from '@/lib/permission-groups/resolve.server' +import type { AccessRequestContext } from '@/ee/access-requests/lib/application/authorization' +import { getAccessRequestDeploymentUnavailableReason } from '@/ee/access-requests/lib/catalog' +import type { AccessRequestScope, AccessRequestTarget } from '@/ee/access-requests/lib/targets' import { type AccessRequestCatalog, buildAccessRequestPolicyDelta, @@ -18,8 +16,7 @@ import { isAccessRequestTargetDenied, isAccessRequestTargetInScope, validateAccessRequestTarget, -} from '@/lib/permission-groups/access-requests/targets' -import { resolveDefaultGroup, resolveWorkspaceGroup } from '@/lib/permission-groups/resolve.server' +} from '@/ee/access-requests/lib/targets' export async function loadMemberLimit( executor: DbOrTx, diff --git a/apps/sim/lib/permission-access-requests/repository.postgres.test.ts b/apps/sim/ee/access-requests/lib/repository.postgres.test.ts similarity index 97% rename from apps/sim/lib/permission-access-requests/repository.postgres.test.ts rename to apps/sim/ee/access-requests/lib/repository.postgres.test.ts index ba9e215772d..cce7027acde 100644 --- a/apps/sim/lib/permission-access-requests/repository.postgres.test.ts +++ b/apps/sim/ee/access-requests/lib/repository.postgres.test.ts @@ -5,7 +5,7 @@ import { and, eq } from 'drizzle-orm' import { drizzle } from 'drizzle-orm/postgres-js' import postgres from 'postgres' import { afterAll, beforeAll, describe, expect, it, vi } from 'vitest' -import { listAccessRequestRecords } from '@/lib/permission-access-requests/repository' +import { listAccessRequestRecords } from '@/ee/access-requests/lib/repository' vi.unmock('@sim/db/schema') vi.unmock('drizzle-orm') diff --git a/apps/sim/lib/permission-access-requests/repository.ts b/apps/sim/ee/access-requests/lib/repository.ts similarity index 95% rename from apps/sim/lib/permission-access-requests/repository.ts rename to apps/sim/ee/access-requests/lib/repository.ts index ce13fc5748a..2e651e0e1d2 100644 --- a/apps/sim/lib/permission-access-requests/repository.ts +++ b/apps/sim/ee/access-requests/lib/repository.ts @@ -3,8 +3,8 @@ import { and, count, desc, eq, ilike, or, type SQL } from 'drizzle-orm' import { escapeLikePattern } from '@/lib/api/list-query' import { OrchestrationError } from '@/lib/core/orchestration/types' import type { DbOrTx } from '@/lib/db/types' -import { storedAccessRequestTargetSchema } from '@/lib/permission-access-requests/schemas' -import type { AccessRequestList, AccessRequestRecord } from '@/lib/permission-access-requests/types' +import { storedAccessRequestTargetSchema } from '@/ee/access-requests/lib/schemas' +import type { AccessRequestList, AccessRequestRecord } from '@/ee/access-requests/lib/types' export type StoredAccessRequest = typeof permissionAccessRequest.$inferSelect diff --git a/apps/sim/lib/permission-access-requests/schemas.test.ts b/apps/sim/ee/access-requests/lib/schemas.test.ts similarity index 96% rename from apps/sim/lib/permission-access-requests/schemas.test.ts rename to apps/sim/ee/access-requests/lib/schemas.test.ts index d98cf87162a..234e21edc1c 100644 --- a/apps/sim/lib/permission-access-requests/schemas.test.ts +++ b/apps/sim/ee/access-requests/lib/schemas.test.ts @@ -2,11 +2,11 @@ * @vitest-environment node */ import { describe, expect, it } from 'vitest' -import { storedAccessRequestPolicyChangeSchema } from '@/lib/permission-access-requests/schemas' import { DEFAULT_PERMISSION_GROUP_CONFIG, PERMISSION_GROUP_FIELDS, } from '@/lib/permission-groups/fields' +import { storedAccessRequestPolicyChangeSchema } from '@/ee/access-requests/lib/schemas' describe('stored access request policy changes', () => { it('accepts unchanged canonical values for every field', () => { diff --git a/apps/sim/lib/permission-access-requests/schemas.ts b/apps/sim/ee/access-requests/lib/schemas.ts similarity index 98% rename from apps/sim/lib/permission-access-requests/schemas.ts rename to apps/sim/ee/access-requests/lib/schemas.ts index 5e17319cd38..2ce98b701af 100644 --- a/apps/sim/lib/permission-access-requests/schemas.ts +++ b/apps/sim/ee/access-requests/lib/schemas.ts @@ -1,7 +1,7 @@ import { z } from 'zod' -import type { AccessRequestTarget as DomainAccessRequestTarget } from '@/lib/permission-groups/access-requests/targets' import { PLATFORM_FEATURES } from '@/lib/permission-groups/features' import { FILE_SHARE_AUTH_TYPES, PERMISSION_GROUP_FIELDS } from '@/lib/permission-groups/fields' +import type { AccessRequestTarget as DomainAccessRequestTarget } from '@/ee/access-requests/lib/targets' const targetIdSchema = z.string().min(1, 'Target ID cannot be empty').max(512) const fingerprintSchema = z.string().min(1, 'A current preview is required').max(128) diff --git a/apps/sim/ee/access-requests/lib/settings.test.ts b/apps/sim/ee/access-requests/lib/settings.test.ts new file mode 100644 index 00000000000..8a540763fcb --- /dev/null +++ b/apps/sim/ee/access-requests/lib/settings.test.ts @@ -0,0 +1,48 @@ +/** + * @vitest-environment node + */ +import { organizationAccessRequestSettings } from '@sim/db/schema' +import { dbChainMockFns, queueTableRows, resetDbChainMock } from '@sim/testing' +import { beforeEach, describe, expect, it } from 'vitest' +import { + isAccessRequestEnabled, + readAccessRequestSettings, +} from '@/ee/access-requests/lib/settings' + +beforeEach(() => { + resetDbChainMock() +}) + +describe('permission access request settings', () => { + it('defaults the organization preference on when no settings row exists', async () => { + queueTableRows(organizationAccessRequestSettings, []) + + await expect(readAccessRequestSettings('organization-one')).resolves.toEqual({ + allowRequests: true, + }) + expect(dbChainMockFns.limit).toHaveBeenCalledWith(1) + expect(dbChainMockFns.where).toHaveBeenCalledWith({ + type: 'eq', + left: organizationAccessRequestSettings.organizationId, + right: 'organization-one', + }) + }) + + it('honors an organization opt-out', async () => { + queueTableRows(organizationAccessRequestSettings, [{ allowRequests: false }]) + + await expect(isAccessRequestEnabled('organization-one')).resolves.toBe(false) + }) + + it('preserves an explicit enabled preference', async () => { + queueTableRows(organizationAccessRequestSettings, [{ allowRequests: true }]) + + await expect(isAccessRequestEnabled('organization-one')).resolves.toBe(true) + }) + + it('does not reinterpret a failed settings lookup as permission to submit', async () => { + dbChainMockFns.limit.mockRejectedValueOnce(new Error('database unavailable')) + + await expect(isAccessRequestEnabled('organization-one')).rejects.toThrow('database unavailable') + }) +}) diff --git a/apps/sim/lib/permission-access-requests/settings.ts b/apps/sim/ee/access-requests/lib/settings.ts similarity index 71% rename from apps/sim/lib/permission-access-requests/settings.ts rename to apps/sim/ee/access-requests/lib/settings.ts index f2b35394116..24f7daf2585 100644 --- a/apps/sim/lib/permission-access-requests/settings.ts +++ b/apps/sim/ee/access-requests/lib/settings.ts @@ -1,7 +1,6 @@ import { db } from '@sim/db' import { organizationAccessRequestSettings } from '@sim/db/schema' import { eq } from 'drizzle-orm' -import { isFeatureEnabled } from '@/lib/core/config/feature-flags' import type { DbOrTx } from '@/lib/db/types' /** Missing settings preserve the default-on organization preference. */ @@ -14,13 +13,10 @@ export async function readAccessRequestSettings(organizationId: string, executor return { allowRequests: row?.allowRequests ?? true } } -/** The rollout flag is evaluated globally; organization preferences can only narrow it. */ +/** Access requests are on unless the organization has opted out. */ export async function isAccessRequestEnabled( organizationId: string, - executor: DbOrTx = db, - enabledAtAdmission?: boolean + executor: DbOrTx = db ): Promise { - if (enabledAtAdmission === false || !(await isFeatureEnabled('permission-access-requests'))) - return false return (await readAccessRequestSettings(organizationId, executor)).allowRequests } diff --git a/apps/sim/lib/permission-groups/access-requests/targets.test.ts b/apps/sim/ee/access-requests/lib/targets.test.ts similarity index 99% rename from apps/sim/lib/permission-groups/access-requests/targets.test.ts rename to apps/sim/ee/access-requests/lib/targets.test.ts index d5ac0b2db25..43d59c1a081 100644 --- a/apps/sim/lib/permission-groups/access-requests/targets.test.ts +++ b/apps/sim/ee/access-requests/lib/targets.test.ts @@ -2,6 +2,8 @@ * @vitest-environment node */ import { describe, expect, it } from 'vitest' +import { CAPABILITY_RULES } from '@/lib/permission-groups/capabilities' +import { DEFAULT_PERMISSION_GROUP_CONFIG } from '@/lib/permission-groups/fields' import { type AccessRequestTarget, buildAccessRequestPolicyDelta, @@ -11,9 +13,7 @@ import { isAccessRequestTargetDenied, isAccessRequestTargetInScope, validateAccessRequestTarget, -} from '@/lib/permission-groups/access-requests/targets' -import { CAPABILITY_RULES } from '@/lib/permission-groups/capabilities' -import { DEFAULT_PERMISSION_GROUP_CONFIG } from '@/lib/permission-groups/fields' +} from '@/ee/access-requests/lib/targets' const catalog = createAccessRequestCatalog({ integrations: [ diff --git a/apps/sim/lib/permission-groups/access-requests/targets.ts b/apps/sim/ee/access-requests/lib/targets.ts similarity index 100% rename from apps/sim/lib/permission-groups/access-requests/targets.ts rename to apps/sim/ee/access-requests/lib/targets.ts diff --git a/apps/sim/lib/permission-access-requests/types.ts b/apps/sim/ee/access-requests/lib/types.ts similarity index 90% rename from apps/sim/lib/permission-access-requests/types.ts rename to apps/sim/ee/access-requests/lib/types.ts index 9acb355d778..33f6e18e476 100644 --- a/apps/sim/lib/permission-access-requests/types.ts +++ b/apps/sim/ee/access-requests/lib/types.ts @@ -1,8 +1,5 @@ -import type { AccessRequestDecision } from '@/lib/permission-access-requests/schemas' -import type { - AccessRequestScope, - AccessRequestTarget, -} from '@/lib/permission-groups/access-requests/targets' +import type { AccessRequestDecision } from '@/ee/access-requests/lib/schemas' +import type { AccessRequestScope, AccessRequestTarget } from '@/ee/access-requests/lib/targets' export type AccessRequestStatus = 'pending' | 'fulfilled' | 'declined' | 'cancelled' | 'closed' diff --git a/apps/sim/lib/api/contracts/access-requests.ts b/apps/sim/lib/api/contracts/access-requests.ts index 53f40b4f172..4532bbf6524 100644 --- a/apps/sim/lib/api/contracts/access-requests.ts +++ b/apps/sim/lib/api/contracts/access-requests.ts @@ -1,22 +1,22 @@ import { z } from 'zod' import { organizationIdSchema, workspaceIdSchema } from '@/lib/api/contracts/primitives' import { defineRouteContract } from '@/lib/api/contracts/types' +import { PERMISSION_GROUP_FIELDS } from '@/lib/permission-groups/fields' import { ACCESS_REQUEST_MAX_ID_LENGTH, ACCESS_REQUEST_MAX_OFFSET, ACCESS_REQUEST_MAX_SEARCH_LENGTH, -} from '@/lib/permission-access-requests/constants' +} from '@/ee/access-requests/lib/constants' import { storedAccessRequestDecisionSchema, storedAccessRequestPolicyChangeSchema, storedAccessRequestPolicyValueSchema, storedAccessRequestTargetSchema, -} from '@/lib/permission-access-requests/schemas' +} from '@/ee/access-requests/lib/schemas' import { ACCESS_REQUEST_TARGET_KINDS, type AccessRequestScope as DomainAccessRequestScope, -} from '@/lib/permission-groups/access-requests/targets' -import { PERMISSION_GROUP_FIELDS } from '@/lib/permission-groups/fields' +} from '@/ee/access-requests/lib/targets' export const ACCESS_REQUEST_STATUSES = [ 'pending', diff --git a/apps/sim/lib/core/config/env.ts b/apps/sim/lib/core/config/env.ts index 8d61dba5005..6f7e4974c84 100644 --- a/apps/sim/lib/core/config/env.ts +++ b/apps/sim/lib/core/config/env.ts @@ -626,7 +626,6 @@ export const env = createEnv({ FORKING_ENABLED: z.boolean().optional(), // Enable workspace forking on self-hosted (bypasses hosted requirements) TABLES_V2_API: z.boolean().optional(), // Enable the v2 tables HTTP API (public /api/v2/tables + internal /api/table/[tableId]/query predicate-grammar route) TABLE_ROW_TTL: z.boolean().optional(), - PERMISSION_ACCESS_REQUESTS_ENABLED: z.boolean().optional(), CREDENTIAL_GROUPS: z.boolean().optional(), // Enable enterprise Credential Groups globally KNOWLEDGE_MEMBER_ACCESS: z.boolean().optional(), // Enable per-member knowledge connectors and hybrid-by-default retrieval globally diff --git a/apps/sim/lib/core/config/feature-flags.test.ts b/apps/sim/lib/core/config/feature-flags.test.ts index bd010a4f949..de18088049a 100644 --- a/apps/sim/lib/core/config/feature-flags.test.ts +++ b/apps/sim/lib/core/config/feature-flags.test.ts @@ -2,7 +2,7 @@ * @vitest-environment node */ import { resetEnvFlagsMock, setEnvFlags } from '@sim/testing' -import { afterAll, afterEach, beforeEach, describe, expect, it, vi } from 'vitest' +import { afterAll, beforeEach, describe, expect, it, vi } from 'vitest' import type { FeatureFlagContext, FeatureFlagName } from '@/lib/core/config/feature-flags' const { mockFetch, mockIsPlatformAdmin, envRef } = vi.hoisted(() => ({ @@ -13,7 +13,6 @@ const { mockFetch, mockIsPlatformAdmin, envRef } = vi.hoisted(() => ({ APPCONFIG_ENVIRONMENT: 'staging' as string | undefined, TABLES_V2_API: undefined as boolean | undefined, TABLE_ROW_TTL: undefined as boolean | undefined, - PERMISSION_ACCESS_REQUESTS_ENABLED: undefined as boolean | undefined, CREDENTIAL_GROUPS: undefined as boolean | undefined, KNOWLEDGE_MEMBER_ACCESS: undefined as boolean | undefined, SLACK_SEARCH_SHARED_APP: undefined as boolean | undefined, @@ -337,26 +336,3 @@ describe('table-row-ttl flag', () => { expect(await isFeatureEnabled('table-row-ttl')).toBe(true) }) }) - -describe('permission access request rollout', () => { - beforeEach(() => { - vi.clearAllMocks() - setEnvFlags({ isAppConfigEnabled: false }) - envRef.PERMISSION_ACCESS_REQUESTS_ENABLED = undefined - }) - afterEach(() => { - envRef.PERMISSION_ACCESS_REQUESTS_ENABLED = undefined - }) - it('defaults off and can be enabled with the fallback secret', async () => { - expect(await isFeatureEnabled('permission-access-requests')).toBe(false) - envRef.PERMISSION_ACCESS_REQUESTS_ENABLED = true - expect(await isFeatureEnabled('permission-access-requests')).toBe(true) - expect(mockFetch).not.toHaveBeenCalled() - }) - it('uses a global AppConfig rule without organization targeting', async () => { - withAppConfig({ 'permission-access-requests': { enabled: false, orgIds: ['org'] } }) - expect(await isFeatureEnabled('permission-access-requests')).toBe(false) - withAppConfig({ 'permission-access-requests': { enabled: true } }) - expect(await isFeatureEnabled('permission-access-requests')).toBe(true) - }) -}) diff --git a/apps/sim/lib/core/config/feature-flags.ts b/apps/sim/lib/core/config/feature-flags.ts index 597001b5cc2..2a94f48ee09 100644 --- a/apps/sim/lib/core/config/feature-flags.ts +++ b/apps/sim/lib/core/config/feature-flags.ts @@ -46,11 +46,6 @@ interface FeatureFlagDefinition { /** The single registry of known flags. To add a flag, add one entry here. */ const FEATURE_FLAGS = { - 'permission-access-requests': { - description: - 'Enable permission and member usage-cap requests globally. Organizations can opt out in access control settings.', - fallback: 'PERMISSION_ACCESS_REQUESTS_ENABLED', - }, 'slack-search-shared-app': { description: 'Enable the official shared Slack app for existing Search customers. Supports orgId ' + diff --git a/apps/sim/lib/core/outbox/processor.test.ts b/apps/sim/lib/core/outbox/processor.test.ts index d20af17bc58..6ad93cc80fa 100644 --- a/apps/sim/lib/core/outbox/processor.test.ts +++ b/apps/sim/lib/core/outbox/processor.test.ts @@ -37,7 +37,7 @@ vi.mock('@/lib/mothership/inbox/cleanup-outbox', () => ({ inboxCleanupOutboxHand vi.mock('@/lib/organizations/resource-cleanup', () => ({ organizationResourceCleanupOutboxHandlers: {}, })) -vi.mock('@/lib/permission-access-requests/notifications', () => ({ +vi.mock('@/ee/access-requests/lib/notifications', () => ({ permissionAccessRequestOutboxHandlers: {}, })) vi.mock('@/lib/uploads/contexts/workspace/workspace-file-live-doc-outbox', () => ({ diff --git a/apps/sim/lib/core/outbox/processor.ts b/apps/sim/lib/core/outbox/processor.ts index 464460579bc..41e625b118f 100644 --- a/apps/sim/lib/core/outbox/processor.ts +++ b/apps/sim/lib/core/outbox/processor.ts @@ -20,12 +20,12 @@ import { knowledgeDocumentProcessingOutboxHandlers } from '@/lib/knowledge/docum import { recoverKnowledgeDocumentProcessing } from '@/lib/knowledge/documents/processing-recovery' import { inboxCleanupOutboxHandlers } from '@/lib/mothership/inbox/cleanup-outbox' import { organizationResourceCleanupOutboxHandlers } from '@/lib/organizations/resource-cleanup' -import { permissionAccessRequestOutboxHandlers } from '@/lib/permission-access-requests/notifications' import { workspaceFileLiveDocOutboxHandlers } from '@/lib/uploads/contexts/workspace/workspace-file-live-doc-outbox' import { workspaceFileStorageCleanupOutboxHandlers } from '@/lib/uploads/contexts/workspace/workspace-file-storage-cleanup-outbox' import { workflowDeploymentOutboxHandlers } from '@/lib/workflows/deployment-outbox' import { invitationMigrationOutboxHandlers } from '@/lib/workspaces/admin-move' import { workspaceOperationOutboxHandlers } from '@/lib/workspaces/operations/outbox' +import { permissionAccessRequestOutboxHandlers } from '@/ee/access-requests/lib/notifications' import { forkContentOutboxHandlers } from '@/ee/workspace-forking/application/content-outbox' import { reapStaleBackgroundWork } from '@/ee/workspace-forking/lib/background-work/store' diff --git a/apps/sim/lib/permission-access-requests/settings.test.ts b/apps/sim/lib/permission-access-requests/settings.test.ts deleted file mode 100644 index 69643b15c04..00000000000 --- a/apps/sim/lib/permission-access-requests/settings.test.ts +++ /dev/null @@ -1,95 +0,0 @@ -/** - * @vitest-environment node - */ -import { organizationAccessRequestSettings } from '@sim/db/schema' -import { dbChainMockFns, queueTableRows, resetDbChainMock } from '@sim/testing' -import { beforeEach, describe, expect, it, vi } from 'vitest' - -const { mockIsFeatureEnabled } = vi.hoisted(() => ({ mockIsFeatureEnabled: vi.fn() })) - -vi.mock('@/lib/core/config/feature-flags', () => ({ isFeatureEnabled: mockIsFeatureEnabled })) - -import { - isAccessRequestEnabled, - readAccessRequestSettings, -} from '@/lib/permission-access-requests/settings' - -beforeEach(() => { - vi.clearAllMocks() - resetDbChainMock() - mockIsFeatureEnabled.mockResolvedValue(true) -}) - -describe('permission access request settings', () => { - it('defaults the organization preference on when no settings row exists', async () => { - queueTableRows(organizationAccessRequestSettings, []) - - await expect(readAccessRequestSettings('organization-one')).resolves.toEqual({ - allowRequests: true, - }) - expect(dbChainMockFns.limit).toHaveBeenCalledWith(1) - expect(dbChainMockFns.where).toHaveBeenCalledWith({ - type: 'eq', - left: organizationAccessRequestSettings.organizationId, - right: 'organization-one', - }) - }) - - it('does not let the default-on preference bypass the global rollout flag', async () => { - mockIsFeatureEnabled.mockResolvedValue(false) - - await expect(isAccessRequestEnabled('organization-one')).resolves.toBe(false) - - expect(mockIsFeatureEnabled).toHaveBeenCalledExactlyOnceWith('permission-access-requests') - expect(dbChainMockFns.select).not.toHaveBeenCalled() - }) - - it('enables requests when rollout is active and the organization has not opted out', async () => { - queueTableRows(organizationAccessRequestSettings, []) - - await expect(isAccessRequestEnabled('organization-one')).resolves.toBe(true) - }) - - it('rechecks rollout after an enabled admission snapshot', async () => { - mockIsFeatureEnabled.mockResolvedValue(false) - - await expect(isAccessRequestEnabled('organization-one', undefined, true)).resolves.toBe(false) - - expect(mockIsFeatureEnabled).toHaveBeenCalledExactlyOnceWith('permission-access-requests') - expect(dbChainMockFns.select).not.toHaveBeenCalled() - }) - - it('keeps a disabled admission snapshot denied even if rollout is now enabled', async () => { - await expect(isAccessRequestEnabled('organization-one', undefined, false)).resolves.toBe(false) - - expect(mockIsFeatureEnabled).not.toHaveBeenCalled() - expect(dbChainMockFns.select).not.toHaveBeenCalled() - }) - - it('requires the current organization preference after an enabled admission snapshot', async () => { - queueTableRows(organizationAccessRequestSettings, [{ allowRequests: false }]) - - await expect(isAccessRequestEnabled('organization-one', undefined, true)).resolves.toBe(false) - - expect(mockIsFeatureEnabled).toHaveBeenCalledExactlyOnceWith('permission-access-requests') - expect(dbChainMockFns.select).toHaveBeenCalledTimes(1) - }) - - it('honors an organization opt-out while global rollout is active', async () => { - queueTableRows(organizationAccessRequestSettings, [{ allowRequests: false }]) - - await expect(isAccessRequestEnabled('organization-one')).resolves.toBe(false) - }) - - it('preserves an explicit enabled preference', async () => { - queueTableRows(organizationAccessRequestSettings, [{ allowRequests: true }]) - - await expect(isAccessRequestEnabled('organization-one')).resolves.toBe(true) - }) - - it('does not reinterpret a failed settings lookup as permission to submit', async () => { - dbChainMockFns.limit.mockRejectedValueOnce(new Error('database unavailable')) - - await expect(isAccessRequestEnabled('organization-one')).rejects.toThrow('database unavailable') - }) -}) diff --git a/apps/sim/lib/settings/application/workspace-section-access.test.ts b/apps/sim/lib/settings/application/workspace-section-access.test.ts index f1378edf865..77c804cd809 100644 --- a/apps/sim/lib/settings/application/workspace-section-access.test.ts +++ b/apps/sim/lib/settings/application/workspace-section-access.test.ts @@ -59,7 +59,7 @@ vi.mock('@/components/settings/navigation', () => ({ ), WORKSPACE_PERMISSION_CONFIG_KEYS: { secrets: 'hideSecretsTab' }, })) -vi.mock('@/lib/permission-access-requests/settings', () => ({ +vi.mock('@/ee/access-requests/lib/settings', () => ({ isAccessRequestEnabled: mocks.isAccessRequestEnabled, })) vi.mock('@/lib/billing/core/subscription', () => ({ diff --git a/apps/sim/lib/settings/application/workspace-section-access.ts b/apps/sim/lib/settings/application/workspace-section-access.ts index 01cca335dfe..ab8c8e2a6d4 100644 --- a/apps/sim/lib/settings/application/workspace-section-access.ts +++ b/apps/sim/lib/settings/application/workspace-section-access.ts @@ -12,7 +12,6 @@ import { import { isOrganizationOnEnterprisePlan } from '@/lib/billing/core/subscription' import { getDeploymentShape } from '@/lib/core/config/deployment-shape' import { canOpenOrganizationSettingsSection } from '@/lib/organizations/settings-access' -import { isAccessRequestEnabled } from '@/lib/permission-access-requests/settings' import type { BooleanPermissionGroupConfigKey } from '@/lib/permission-groups/features' import { isOrganizationPermissionRegimeActive } from '@/lib/permission-groups/resolve.server' import { isPlatformAdmin } from '@/lib/permissions/super-user' @@ -20,6 +19,7 @@ import { authorizeOrganizationSettingsSection } from '@/lib/settings/application import { isCustomBlocksEligibleForOrganization } from '@/lib/workflows/custom-blocks/operations' import { checkWorkspaceAccess } from '@/lib/workspaces/permissions/utils' import { resolveVerifiedUserAccessControlContext } from '@/ee/access-control/utils/permission-check' +import { isAccessRequestEnabled } from '@/ee/access-requests/lib/settings' import { isForkingAvailableForWorkspace } from '@/ee/workspace-forking/lib/lineage/authz' export type WorkspaceSettingsSectionAccess = diff --git a/scripts/check-tool-registry-boundary.baseline.json b/scripts/check-tool-registry-boundary.baseline.json index 9be3e4c4193..af6dad97f18 100644 --- a/scripts/check-tool-registry-boundary.baseline.json +++ b/scripts/check-tool-registry-boundary.baseline.json @@ -77,7 +77,7 @@ "app/workspace/[workspaceId]/access-requests/page.tsx": { "modules": 45, "gateways": { - "apps/sim/components/access-requests/my-access-requests.tsx": 43 + "apps/sim/ee/access-requests/components/my-access-requests.tsx": 43 } }, "app/workspace/[workspaceId]/chat/[chatId]/error.tsx": {