Skip to content

Commit

Permalink
Refill form on sso validation (#3603)
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewwallacespeckle authored Dec 2, 2024
1 parent 3b51fc6 commit 0c044c6
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 117 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@ import { useMixpanel } from '~/lib/core/composables/mp'
const props = defineProps<{
workspaceSlug: string
providerInfo?: {
providerName: string
clientId: string
issuerUrl: string
}
}>()
defineEmits<{
Expand All @@ -78,10 +83,10 @@ const { challenge } = useLoginOrRegisterUtils()
const mixpanel = useMixpanel()
const formData = ref<SsoFormValues>({
providerName: '',
clientId: '',
providerName: props.providerInfo?.providerName || '',
clientId: props.providerInfo?.clientId || '',
clientSecret: '',
issuerUrl: ''
issuerUrl: props.providerInfo?.issuerUrl || ''
})
const { handleSubmit } = useForm<SsoFormValues>()
Expand Down Expand Up @@ -112,4 +117,19 @@ const onSubmit = handleSubmit(() => {
external: true
})
})
watch(
() => props.providerInfo,
(newInfo) => {
if (newInfo) {
formData.value = {
...formData.value,
providerName: newInfo.providerName,
clientId: newInfo.clientId,
issuerUrl: newInfo.issuerUrl
}
}
},
{ immediate: true }
)
</script>
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@
<SettingsWorkspacesSecuritySsoForm
v-else
:workspace-slug="workspace.slug"
:provider-info="errorProviderInfo"
@cancel="handleCancel"
@submit="handleFormSubmit"
/>
Expand Down Expand Up @@ -116,6 +117,7 @@

<SettingsWorkspacesSecuritySsoForm
:workspace-slug="workspace.slug"
:provider-info="errorProviderInfo"
@cancel="handleCancel"
@submit="handleFormSubmit"
/>
Expand Down Expand Up @@ -235,4 +237,64 @@ const redirectUrl = computed(() => {
const goToBilling = () => {
goToWorkspaceMenuItem(props.workspace.id, SettingMenuKeys.Workspace.Billing)
}
const route = useRoute()
const errorProviderInfo = ref<
| {
providerName: string
clientId: string
issuerUrl: string
}
| undefined
>(undefined)
const router = useRouter()
const { triggerNotification } = useGlobalToast()
onMounted(() => {
const providerName = route.query?.providerName as string
const clientId = route.query?.clientId as string
const issuerUrl = route.query?.issuerUrl as string
const ssoError = route.query?.ssoError as string
const ssoValidationSuccess = route.query?.ssoValidationSuccess
// Handle error notifications
if (ssoValidationSuccess === 'true') {
triggerNotification({
type: ToastNotificationType.Success,
title: 'SSO Configuration Successful',
description: 'Your SSO settings have been successfully configured.'
})
} else if (ssoValidationSuccess === 'false' || ssoError) {
triggerNotification({
type: ToastNotificationType.Danger,
title: 'SSO Configuration Error',
description: ssoError
? decodeURIComponent(ssoError)
: 'SSO settings validation failed'
})
}
// Handle provider info if present
if (providerName && clientId && issuerUrl) {
errorProviderInfo.value = {
providerName,
clientId,
issuerUrl
}
isFormVisible.value = true
}
// Clean up URL params
router.replace({
query: {
...route.query,
ssoError: undefined,
providerName: undefined,
clientId: undefined,
issuerUrl: undefined,
ssoValidationSuccess: undefined
}
})
})
</script>
16 changes: 16 additions & 0 deletions packages/frontend-2/components/workspace/ProjectList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@
v-model:open="showSettingsDialog"
:target-menu-item="settingsDialogTarget"
:target-workspace-id="workspace.id"
:sso-provider-info="ssoProviderInfo"
/>
<WorkspaceMoveProjectsDialog
v-model:open="showMoveProjectsDialog"
Expand Down Expand Up @@ -295,4 +296,19 @@ onResult((queryResult) => {
validateCheckoutSession(queryResult.data.workspaceBySlug.id)
}
})
const ssoProviderInfo = ref<{
providerName: string
clientId: string
issuerUrl: string
} | null>(null)
onMounted(() => {
const ssoValidationSuccess = route.query?.ssoValidationSuccess
if (ssoValidationSuccess) {
// Open security settings dialog
onShowSettingsDialog(SettingMenuKeys.Workspace.Security)
}
})
</script>
33 changes: 1 addition & 32 deletions packages/frontend-2/middleware/requiresWorkspacesEnabled.ts
Original file line number Diff line number Diff line change
@@ -1,40 +1,9 @@
export default defineNuxtRouteMiddleware((to) => {
export default defineNuxtRouteMiddleware(() => {
const isWorkspacesEnabled = useIsWorkspacesEnabled()

// If workspaces are enabled, continue as normal
if (isWorkspacesEnabled.value) return

// If there's an SSO error, redirect to the main workspace page with provider details
const hasSsoError = to.query.ssoError || to.query.ssoValidationSuccess === 'false'

if (hasSsoError) {
// Collect provider details from URL
const providerDetails = {
providerName: to.query.providerName,
clientId: to.query.clientId,
issuerUrl: to.query.issuerUrl
}

// Only include non-null values
const queryParams = Object.fromEntries(
Object.entries(providerDetails).filter(([_, value]) => value)
)

// Add the error message
if (to.query.ssoError) {
queryParams.error = to.query.ssoError as string
}

// Add a flag to open the settings dialog
queryParams.openSettingsDialog = 'true'

// Redirect to the main workspace page
return navigateTo({
path: `/workspaces/${to.params.slug}`,
query: queryParams
})
}

// Otherwise, block navigation
return abortNavigation(
createError({
Expand Down
82 changes: 0 additions & 82 deletions packages/frontend-2/pages/workspaces/[slug]/index.vue
Original file line number Diff line number Diff line change
@@ -1,26 +1,5 @@
<template>
<div>
<CommonAlert
v-if="ssoError || validationStatus.show"
:color="validationStatus.color"
class="mb-4"
>
<template #title>{{ validationStatus.title }}</template>
<template #description>
<div>{{ validationStatus.message }}</div>
<div v-if="providerDetails" class="mt-1 text-body-2xs opacity-80">
<div v-if="providerDetails.providerName">
Provider: {{ providerDetails.providerName }}
</div>
<div v-if="providerDetails.clientId">
Client ID: {{ providerDetails.clientId }}
</div>
<div v-if="providerDetails.issuerUrl">
Issuer URL: {{ providerDetails.issuerUrl }}
</div>
</div>
</template>
</CommonAlert>
<WorkspaceInviteWrapper
v-if="token"
:workspace-slug="workspaceSlug"
Expand All @@ -32,77 +11,16 @@

<script setup lang="ts">
import { useOnWorkspaceUpdated } from '~/lib/workspaces/composables/management'
import { useWorkspaceSsoValidation } from '~/lib/workspaces/composables/sso'
import { useWorkspaceProjectsUpdatedTracking } from '~/lib/workspaces/composables/projectUpdates'
import { CommonAlert } from '@speckle/ui-components'
import type { AlertColor } from '@speckle/ui-components'
definePageMeta({
middleware: ['requires-workspaces-enabled', 'require-valid-workspace']
})
const route = useRoute()
const workspaceSlug = computed(() => route.params.slug as string)
const { ssoError } = useWorkspaceSsoValidation(workspaceSlug)
useOnWorkspaceUpdated({ workspaceSlug })
useWorkspaceProjectsUpdatedTracking(workspaceSlug)
const token = computed(() => route.query.token as string | undefined)
const providerDetails = computed(() => {
const details = {
providerName: route.query.providerName,
clientId: route.query.clientId,
issuerUrl: route.query.issuerUrl
}
// Only return if we have any details
return Object.values(details).some(Boolean) ? details : null
})
const validationStatus = computed<{
show: boolean
color: AlertColor
title: string
message: string
}>(() => {
// Handle SSO validation result
if (route.query.ssoValidationSuccess === 'false') {
return {
show: true,
color: 'danger',
title: 'SSO Configuration Failed',
message: route.query.ssoError
? decodeURIComponent(route.query.ssoError as string)
: 'Please check your credentials and try again.'
}
}
// Handle generic SSO errors
if (route.query.ssoError) {
return {
show: true,
color: 'danger',
title: 'SSO Error',
message: decodeURIComponent(route.query.ssoError as string)
}
}
// Handle successful validation
if (route.query.ssoValidationSuccess === 'true') {
return {
show: true,
color: 'success',
title: 'SSO Configuration Successful',
message: 'Your SSO provider has been successfully configured.'
}
}
return {
show: false,
color: 'danger',
title: '',
message: ''
}
})
</script>

0 comments on commit 0c044c6

Please sign in to comment.