Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions cloudflare_workers/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type { ExecutionContext, ScheduledController } from '@cloudflare/workers-
import type { Bindings } from '../../supabase/functions/_backend/utils/cloudflare.ts'
import { app as accept_invitation } from '../../supabase/functions/_backend/private/accept_invitation.ts'
import { app as admin_credits } from '../../supabase/functions/_backend/private/admin_credits.ts'
import { app as admin_org_support_channel } from '../../supabase/functions/_backend/private/admin_org_support_channel.ts'
import { app as admin_stats } from '../../supabase/functions/_backend/private/admin_stats.ts'
import { app as channel_device } from '../../supabase/functions/_backend/private/channel_device.ts'
import { app as channel_stats } from '../../supabase/functions/_backend/private/channel_stats.ts'
Expand Down Expand Up @@ -138,6 +139,7 @@ appPrivate.route('/invite_existing_user_to_org', invite_existing_user_to_org)
appPrivate.route('/set_org_email', set_org_email)
appPrivate.route('/validate_password_compliance', validate_password_compliance)
appPrivate.route('/admin_credits', admin_credits)
appPrivate.route('/admin_org_support_channel', admin_org_support_channel)
appPrivate.route('/admin_stats', admin_stats)
appPrivate.route('/stats', stats_priv)
appPrivate.route('/channel_stats', channel_stats)
Expand Down
27 changes: 27 additions & 0 deletions messages/en.context.json
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,17 @@
"admin-notifications-sent-last-month": "Used in Capgo web console areas: pages/admin/dashboard. Role: UI label. Translate for UI; keep Capgo product names, code, and placeholders unchanged.",
"admin-notifications-title": "Used in Capgo web console areas: pages/admin/dashboard. Role: section or dialog title. Translate for UI; keep Capgo product names, code, and placeholders unchanged.",
"admin-organizations": "Used in Capgo web console areas: constants, pages/admin/dashboard. Role: short UI label. Translate for UI; keep Capgo product names, code, and placeholders unchanged.",
"enterprise-adoption-chart-description": "Used in Capgo web console areas: pages/admin/dashboard. Role: helper or description text. Translate for UI; keep Capgo product names, code, and placeholders unchanged.",
"enterprise-adoption-chart-title": "Used in Capgo web console areas: pages/admin/dashboard. Role: section or dialog title. Translate for UI; keep Capgo product names, code, and placeholders unchanged.",
"enterprise-channel-adoption": "Used in Capgo web console areas: pages/admin/dashboard. Role: chart series label. Translate for UI; keep Capgo product names, code, and placeholders unchanged.",
"enterprise-channel-chart-description": "Used in Capgo web console areas: pages/admin/dashboard. Role: helper or description text. Translate for UI; keep Capgo product names, code, and placeholders unchanged.",
"enterprise-channel-chart-title": "Used in Capgo web console areas: pages/admin/dashboard. Role: section or dialog title. Translate for UI; keep Capgo product names, code, and placeholders unchanged.",
"enterprise-channel-count": "Used in Capgo web console areas: pages/admin/dashboard. Role: chart series label. Translate for UI; keep Capgo product names, code, and placeholders unchanged.",
"enterprise-count": "Used in Capgo web console areas: pages/admin/dashboard. Role: chart series label. Translate for UI; keep Capgo product names, code, and placeholders unchanged.",
"enterprise-sso-adoption": "Used in Capgo web console areas: pages/admin/dashboard. Role: chart series label. Translate for UI; keep Capgo product names, code, and placeholders unchanged.",
"enterprise-sso-chart-description": "Used in Capgo web console areas: pages/admin/dashboard. Role: helper or description text. Translate for UI; keep Capgo product names, code, and placeholders unchanged.",
"enterprise-sso-chart-title": "Used in Capgo web console areas: pages/admin/dashboard. Role: section or dialog title. Translate for UI; keep Capgo product names, code, and placeholders unchanged.",
"enterprise-sso-count": "Used in Capgo web console areas: pages/admin/dashboard. Role: chart series label. Translate for UI; keep Capgo product names, code, and placeholders unchanged.",
"admin-users-country-breakdown": "Used in Capgo web console areas: pages/admin/dashboard. Role: UI label. Translate for UI; keep Capgo product names, code, and placeholders unchanged.",
"admin-users-country-breakdown-description": "Used in Capgo web console areas: pages/admin/dashboard. Role: helper or description text. Translate for UI; keep Capgo product names, code, and placeholders unchanged.",
"admin-users-country-chart": "Used in Capgo web console areas: pages/admin/dashboard. Role: UI label. Translate for UI; keep Capgo product names, code, and placeholders unchanged.",
Expand Down Expand Up @@ -2825,6 +2836,7 @@
"sso-add-provider": "Used in Capgo web console areas: components/organizations. Role: UI label. Translate for UI; keep Capgo product names, code, and placeholders unchanged.",
"sso-check-failed": "Used in Capgo web console. Role: toast or status message about \"sso check failed\". Translate for UI; keep Capgo product names, code, and placeholders unchanged.",
"sso-configuration": "Used in Capgo web console areas: pages/settings/organization. Role: UI label. Translate for UI; keep Capgo product names, code, and placeholders unchanged.",
"sso-configured": "Used in Capgo web console areas: pages/admin/dashboard. Role: short UI label. Translate for UI; keep Capgo product names, code, and placeholders unchanged.",
"sso-configuration-description": "Used in Capgo web console areas: pages/settings/organization. Role: helper or description text. Translate for UI; keep Capgo product names, code, and placeholders unchanged.",
"sso-copied-to-clipboard": "Used in Capgo web console areas: components/organizations. Role: UI label. Translate for UI; keep Capgo product names, code, and placeholders unchanged.",
"sso-copy": "Used in Capgo web console areas: components/organizations. Role: short UI label. Translate for UI; keep Capgo product names, code, and placeholders unchanged.",
Expand All @@ -2836,6 +2848,7 @@
"sso-delete-confirm": "Used in Capgo web console areas: components/organizations. Role: UI sentence. Translate for UI; keep Capgo product names, code, and placeholders unchanged.",
"sso-delete-title": "Used in Capgo web console areas: components/organizations. Role: section or dialog title. Translate for UI; keep Capgo product names, code, and placeholders unchanged.",
"sso-detected": "Used in Capgo web console areas: pages. Role: UI label. Translate for UI; keep Capgo product names, code, and placeholders unchanged.",
"sso-required": "Used in Capgo web console areas: pages. Role: UI sentence shown when a domain requires SSO. Translate for UI; keep Capgo product names, code, and placeholders unchanged.",
"sso-dismiss": "Used in Capgo web console areas: components/organizations. Role: short UI label. Translate for UI; keep Capgo product names, code, and placeholders unchanged.",
"sso-dns-record-name": "Used in Capgo web console areas: components/organizations. Role: short UI label. Translate for UI; keep Capgo product names, code, and placeholders unchanged.",
"sso-dns-record-type": "Used in Capgo web console areas: components/organizations. Role: short UI label. Translate for UI; keep Capgo product names, code, and placeholders unchanged.",
Expand Down Expand Up @@ -2958,6 +2971,20 @@
"support-usernames-prompt-remind-later": "Used in Capgo web console areas: components/dashboard. Role: UI label. Translate for UI; keep Capgo product names, code, and placeholders unchanged.",
"support-usernames-prompt-save": "Used in Capgo web console areas: components/dashboard. Role: short UI label. Translate for UI; keep Capgo product names, code, and placeholders unchanged.",
"support-usernames-prompt-title": "Used in Capgo web console areas: components/dashboard. Role: section or dialog title. Translate for UI; keep Capgo product names, code, and placeholders unchanged.",
"support-channel": "Used in Capgo web console areas: pages/admin/dashboard, pages/settings/organization. Role: short UI label. Translate for UI; keep Capgo product names, code, and placeholders unchanged.",
"support-channel-clear": "Used in Capgo web console areas: pages/admin/dashboard. Role: short UI label. Translate for UI; keep Capgo product names, code, and placeholders unchanged.",
"support-channel-description": "Used in Capgo web console areas: pages/settings/organization. Role: helper or description text. Translate for UI; keep Capgo product names, code, and placeholders unchanged.",
"support-channel-discord": "Used in Capgo web console areas: pages/admin/dashboard, pages/settings/organization. Role: short UI label. Translate for UI; keep Capgo product names, code, and placeholders unchanged.",
"support-channel-none": "Used in Capgo web console areas: pages/admin/dashboard. Role: short UI label. Translate for UI; keep Capgo product names, code, and placeholders unchanged.",
"support-channel-open": "Used in Capgo web console areas: pages/settings/organization. Role: short UI label. Translate for UI; keep Capgo product names, code, and placeholders unchanged.",
"support-channel-save": "Used in Capgo web console areas: pages/admin/dashboard. Role: short UI label. Translate for UI; keep Capgo product names, code, and placeholders unchanged.",
"support-channel-saved": "Used in Capgo web console areas: pages/admin/dashboard. Role: UI sentence. Translate for UI; keep Capgo product names, code, and placeholders unchanged.",
"support-channel-set": "Used in Capgo web console areas: pages/admin/dashboard. Role: short UI label. Translate for UI; keep Capgo product names, code, and placeholders unchanged.",
"support-channel-slack": "Used in Capgo web console areas: pages/admin/dashboard, pages/settings/organization. Role: short UI label. Translate for UI; keep Capgo product names, code, and placeholders unchanged.",
"support-channel-teams": "Used in Capgo web console areas: pages/admin/dashboard, pages/settings/organization. Role: short UI label. Translate for UI; keep Capgo product names, code, and placeholders unchanged.",
"support-channel-title": "Used in Capgo web console areas: pages/settings/organization. Role: section or dialog title. Translate for UI; keep Capgo product names, code, and placeholders unchanged.",
"support-channel-type": "Used in Capgo web console areas: pages/admin/dashboard. Role: form field label. Translate for UI; keep Capgo product names, code, and placeholders unchanged.",
"support-channel-url": "Used in Capgo web console areas: pages/admin/dashboard. Role: form field label. Translate for UI; keep Capgo product names, code, and placeholders unchanged.",
"switch-to-billing-period": "Used in Capgo web console areas: components/dashboard. Role: UI label. Translate for UI; keep Capgo product names, code, and placeholders unchanged.",
"team": "Used in Capgo web console areas: constants. Role: short UI label. Translate for UI; keep Capgo product names, code, and placeholders unchanged.",
"terms-of-service": "Used in Capgo web console areas: pages. Role: UI label. Translate for UI; keep Capgo product names, code, and placeholders unchanged.",
Expand Down
27 changes: 27 additions & 0 deletions messages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,17 @@
"admin-credits-title": "Grant Credits",
"admin-dashboard": "Admin Dashboard",
"admin-organizations": "Organizations",
"enterprise-adoption-chart-description": "Share of paid Enterprise organizations that have enabled SSO or a dedicated support channel.",
"enterprise-adoption-chart-title": "Enterprise feature adoption",
"enterprise-channel-adoption": "Support channel adoption",
"enterprise-channel-chart-description": "Cumulative paid Enterprise organizations versus those with a Slack, Discord, or Teams channel.",
"enterprise-channel-chart-title": "Enterprise support channels",
"enterprise-channel-count": "Support channels",
"enterprise-count": "Enterprise organizations",
"enterprise-sso-adoption": "SSO adoption",
"enterprise-sso-chart-description": "Cumulative paid Enterprise organizations versus those with active SSO.",
"enterprise-sso-chart-title": "Enterprise SSO",
"enterprise-sso-count": "SSO configured",
"admin-users-email-type-breakdown": "Email Type Breakdown",
"admin-users-email-type-breakdown-description": "Registration mix in the selected period, split between professional, personal, and disposable email domains.",
"admin-users-email-type-disposable": "Disposable Emails",
Expand Down Expand Up @@ -2570,15 +2581,31 @@
"support-usernames-prompt-remind-later": "Remind me later",
"support-usernames-prompt-helper": "Add Discord and GitHub so we can match your Capgo Cloud account when you open a support issue. Priority GitHub support is included on Maker and above, and for everyone during trial.",
"support-usernames-prompt-title": "Speed up Capgo Cloud support",
"support-channel": "Support channel",
"support-channel-clear": "Clear channel",
"support-channel-description": "Your dedicated Capgo support channel. Open it to talk with the Capgo team.",
"support-channel-discord": "Discord",
"support-channel-none": "Not set",
"support-channel-open": "Open channel",
"support-channel-save": "Save channel",
"support-channel-saved": "Support channel updated",
"support-channel-set": "Set channel",
"support-channel-slack": "Slack",
"support-channel-teams": "Teams",
"support-channel-title": "Dedicated support channel",
"support-channel-type": "Channel type",
"support-channel-url": "Channel link",
"something-went-wrong-try-again-later": "Something went wrong! Try again later.",
"sso-add-provider": "Add SSO Provider",
"sso-configuration": "SSO Configuration",
"sso-configured": "SSO",
"sso-configuration-description": "Configure SAML 2.0 Single Sign-On for your organization",
"sso-create-provider": "Create Provider",
"sso-creating": "Creating...",
"sso-delete-confirm": "Are you sure you want to delete the SSO provider for {domain}?",
"sso-delete-title": "Delete SSO Provider",
"sso-detected": "Single Sign-On available",
"sso-required": "This domain requires Single Sign-On",
"sso-dismiss": "Dismiss",
"sso-dns-record-name": "Name",
"sso-dns-record-type": "Type",
Expand Down
18 changes: 17 additions & 1 deletion playwright/e2e/sso-login.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ test.describe('SSO Login Flow', () => {
await expect.poll(() => checks).toBeGreaterThan(1)
})

test('should use SSO only when the domain has SSO', async ({ page }) => {
test('should keep password login when SSO is available but not enforced', async ({ page }) => {
await page.route('**/private/sso/check-domain', async (route) => {
await route.fulfill({
status: 200,
Expand All @@ -63,6 +63,22 @@ test.describe('SSO Login Flow', () => {
})
})

await page.fill('[data-test="email"]', 'user@sso.example')
await expect(page.locator('[data-test="sso-login"]')).toBeVisible({ timeout: 10000 })
await expect(page.locator('[data-password-ready="true"]')).toHaveCount(1)
await expect(page.locator('[data-test="password"]')).toBeVisible()
await expect(page.locator('[data-test="submit"]')).toBeVisible()
})

test('should hide password login when SSO is enforced', async ({ page }) => {
await page.route('**/private/sso/check-domain', async (route) => {
await route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify({ has_sso: true, enforce_sso: true }),
})
})

await page.fill('[data-test="email"]', 'user@sso.example')
await expect(page.locator('[data-test="sso-login"]')).toBeVisible({ timeout: 10000 })
await expect(page.locator('[data-password-ready="false"]')).toHaveCount(1)
Expand Down
Binary file added pr-preview/admin-enterprise-orgs.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added pr-preview/login-sso-enforced.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added pr-preview/login-sso-optional.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added pr-preview/org-support-channel.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
44 changes: 44 additions & 0 deletions read_replicate/schema_replicate.catalog.json
Original file line number Diff line number Diff line change
Expand Up @@ -1530,6 +1530,36 @@
"table": "orgs",
"type": "timestamp with time zone"
},
{
"default": null,
"generated": "",
"identity": "",
"name": "support_channel_type",
"notNull": false,
"position": 26,
"table": "orgs",
"type": "text"
},
{
"default": null,
"generated": "",
"identity": "",
"name": "support_channel_url",
"notNull": false,
"position": 27,
"table": "orgs",
"type": "text"
},
{
"default": null,
"generated": "",
"identity": "",
"name": "support_channel_set_at",
"notNull": false,
"position": 28,
"table": "orgs",
"type": "timestamp with time zone"
},
{
"default": "now()",
"generated": "",
Expand Down Expand Up @@ -2009,6 +2039,20 @@
"type": "c",
"valid": true
},
{
"definition": "CHECK (support_channel_type IS NULL OR (support_channel_type = ANY (ARRAY['slack'::text, 'discord'::text, 'teams'::text])))",
"name": "orgs_support_channel_type_check",
"table": "orgs",
"type": "c",
"valid": true
},
{
"definition": "CHECK (support_channel_type IS NULL AND support_channel_url IS NULL OR support_channel_type IS NOT NULL AND support_channel_url IS NOT NULL AND char_length(support_channel_url) <= 2048 AND support_channel_url ~ '^https://'::text)",
"name": "orgs_support_channel_url_check",
"table": "orgs",
"type": "c",
"valid": true
},
{
"definition": "UNIQUE (customer_id)",
"name": "unique customer_id on orgs",
Expand Down
7 changes: 6 additions & 1 deletion read_replicate/schema_replicate.sql
Original file line number Diff line number Diff line change
Expand Up @@ -403,10 +403,15 @@ CREATE TABLE public.orgs (
auto_top_up_enabled boolean DEFAULT false NOT NULL,
auto_top_up_threshold numeric(18,6) DEFAULT 10 NOT NULL,
auto_top_up_last_attempt_at timestamp with time zone,
support_channel_type text,
support_channel_url text,
support_channel_set_at timestamp with time zone,
CONSTRAINT orgs_max_apikey_expiration_days_valid CHECK (((max_apikey_expiration_days IS NULL) OR ((max_apikey_expiration_days >= 1) AND (max_apikey_expiration_days <= 365)))),
CONSTRAINT orgs_onboarding_valid CHECK (((jsonb_typeof(onboarding) = 'object'::text) AND ((NOT (onboarding ? 'intent'::text)) OR ((onboarding ->> 'intent'::text) = ANY (ARRAY['unknown'::text, 'ota'::text, 'builder'::text, 'both'::text, 'exploring'::text]))))),
CONSTRAINT orgs_password_policy_config_min_length_check CHECK (((password_policy_config IS NULL) OR ((jsonb_typeof(password_policy_config) = 'object'::text) AND ((NOT (password_policy_config ? 'min_length'::text)) OR ((jsonb_typeof((password_policy_config -> 'min_length'::text)) = 'number'::text) AND (((password_policy_config ->> 'min_length'::text))::numeric = trunc(((password_policy_config ->> 'min_length'::text))::numeric)) AND ((((password_policy_config ->> 'min_length'::text))::numeric >= (6)::numeric) AND (((password_policy_config ->> 'min_length'::text))::numeric <= (72)::numeric))))))),
CONSTRAINT orgs_required_encryption_key_valid CHECK (((required_encryption_key IS NULL) OR (length((required_encryption_key)::text) = ANY (ARRAY[20, 21]))))
CONSTRAINT orgs_required_encryption_key_valid CHECK (((required_encryption_key IS NULL) OR (length((required_encryption_key)::text) = ANY (ARRAY[20, 21])))),
CONSTRAINT orgs_support_channel_type_check CHECK (((support_channel_type IS NULL) OR (support_channel_type = ANY (ARRAY['slack'::text, 'discord'::text, 'teams'::text])))),
CONSTRAINT orgs_support_channel_url_check CHECK ((((support_channel_type IS NULL) AND (support_channel_url IS NULL)) OR ((support_channel_type IS NOT NULL) AND (support_channel_url IS NOT NULL) AND (char_length(support_channel_url) <= 2048) AND (support_channel_url ~ '^https://'::text))))
);

ALTER TABLE ONLY public.orgs REPLICA IDENTITY FULL;
Expand Down
Loading
Loading