Skip to content

Commit 23d3243

Browse files
committed
Refactor button to open test URL
1 parent 190d1c3 commit 23d3243

6 files changed

Lines changed: 95 additions & 141 deletions

File tree

packages/localizations/src/en-US.ts

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -275,9 +275,7 @@ export const enUS: LocalizationResource = {
275275
error__noSuccessfulTestRun:
276276
'You need at least one successful test run before you can continue. Generate a test SSO URL and complete the sign-in flow.',
277277
testUrl: {
278-
title: 'Test your SSO URL',
279-
subtitle: 'Generate and copy a test SSO URL to authenticate with.',
280-
actionLabel__copy: 'Copy test URL',
278+
actionLabel__open: 'Open test URL',
281279
},
282280
testResults: {
283281
title: 'Test results',
@@ -340,8 +338,6 @@ export const enUS: LocalizationResource = {
340338
configureStep: {
341339
attributeMapping: {
342340
title: 'We expect your SAML responses to have the following specific attributes:',
343-
paragraph:
344-
"These are the defaults and probably won't need you to change them. However, many SAML configuration errors are due to incorrect attribute mappings, so it's worth double-checking. Here's how:",
345341
columns: {
346342
attribute: 'Attribute',
347343
claimName: 'Claim Name',
@@ -409,10 +405,10 @@ export const enUS: LocalizationResource = {
409405
step2: 'Complete the form with any comments and select <bold>Finish</bold>.',
410406
},
411407
configureAttributes: {
412-
headerSubtitle: 'Map users attributes from Okta to Clerk',
413-
step1: 'In the Okta dashboard, find the <bold>Attribute Statements</bold> section.',
414-
step2:
415-
'Select <bold>Add Expression</bold> for each attribute, and enter the following name and expression pairs:',
408+
headerSubtitle: 'Map user attributes from Okta to Clerk',
409+
step1:
410+
'Open the <bold>Sign On</bold> tab of your Okta application and locate the <bold>Attribute Statements</bold> section. If you don’t see it, click <bold>Show legacy configuration</bold>, then <bold>Edit</bold>.',
411+
step2: 'Select <bold>Add Expression</bold> for each row below, then enter the matching name and value:',
416412
pairs: {
417413
conjunction: ' and ',
418414
email: {

packages/shared/src/types/localization.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1340,9 +1340,7 @@ export type __internal_LocalizationResource = {
13401340
subtitle: LocalizationValue;
13411341
error__noSuccessfulTestRun: LocalizationValue;
13421342
testUrl: {
1343-
title: LocalizationValue;
1344-
subtitle: LocalizationValue;
1345-
actionLabel__copy: LocalizationValue;
1343+
actionLabel__open: LocalizationValue;
13461344
};
13471345
testResults: {
13481346
title: LocalizationValue;

packages/ui/src/components/ConfigureSSO/steps/ConfigureStep.tsx

Lines changed: 32 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -418,48 +418,38 @@ export const ConfigureAttributesSubStep = (): JSX.Element => {
418418
);
419419
};
420420

421-
const OktaConfigureAttributesStepContent = (): JSX.Element => {
422-
return (
423-
<>
424-
<Text
425-
as='p'
426-
colorScheme='secondary'
427-
localizationKey={localizationKeys('configureSSO.configureStep.attributeMapping.paragraph')}
428-
/>
429-
430-
<Col
431-
elementDescriptor={descriptors.configureSSOInstructionsList}
432-
as='ol'
433-
sx={theme => ({
434-
gap: theme.space.$1x5,
435-
margin: 0,
436-
paddingInlineStart: theme.space.$5,
437-
listStyleType: 'decimal',
438-
})}
439-
>
440-
<Text
441-
elementDescriptor={descriptors.configureSSOInstructionsListItem}
442-
as='li'
443-
colorScheme='secondary'
444-
localizationKey={localizationKeys('configureSSO.configureStep.samlOkta.configureAttributes.step1')}
445-
/>
446-
{/*
447-
* The actual name/expression pairs that step 2 refers to are
448-
* rendered by the `AttributeMappingTable` immediately below this
449-
* component — keeping them in a single tabular surface instead of
450-
* an inline badge list matches the design (see Okta screenshot:
451-
* "Create the following attribute mapping statements:" + table).
452-
*/}
453-
<Text
454-
elementDescriptor={descriptors.configureSSOInstructionsListItem}
455-
as='li'
456-
colorScheme='secondary'
457-
localizationKey={localizationKeys('configureSSO.configureStep.samlOkta.configureAttributes.step2')}
458-
/>
459-
</Col>
460-
</>
461-
);
462-
};
421+
const OktaConfigureAttributesStepContent = (): JSX.Element => (
422+
<Col
423+
elementDescriptor={descriptors.configureSSOInstructionsList}
424+
as='ol'
425+
sx={theme => ({
426+
gap: theme.space.$1x5,
427+
margin: 0,
428+
paddingInlineStart: theme.space.$5,
429+
listStyleType: 'decimal',
430+
})}
431+
>
432+
<Text
433+
elementDescriptor={descriptors.configureSSOInstructionsListItem}
434+
as='li'
435+
colorScheme='secondary'
436+
localizationKey={localizationKeys('configureSSO.configureStep.samlOkta.configureAttributes.step1')}
437+
/>
438+
{/*
439+
* The actual name/expression pairs that step 2 refers to are rendered
440+
* by the `AttributeMappingTable` immediately below this component —
441+
* keeping them in a single tabular surface instead of an inline badge
442+
* list matches the design (see Okta screenshot: "Create the following
443+
* attribute mapping statements:" + table).
444+
*/}
445+
<Text
446+
elementDescriptor={descriptors.configureSSOInstructionsListItem}
447+
as='li'
448+
colorScheme='secondary'
449+
localizationKey={localizationKeys('configureSSO.configureStep.samlOkta.configureAttributes.step2')}
450+
/>
451+
</Col>
452+
);
463453

464454
const AttributeMappingTable = ({ config }: { config: AttributeMappingTableConfig }): JSX.Element => (
465455
<Table

packages/ui/src/components/ConfigureSSO/steps/TestConfigurationStep.tsx

Lines changed: 55 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
Badge,
99
Box,
1010
Button,
11+
Col,
1112
Dd,
1213
descriptors,
1314
Dl,
@@ -31,9 +32,8 @@ import { useCardState } from '@/elements/contexts';
3132
import { Drawer } from '@/elements/Drawer';
3233
import { IconButton } from '@/elements/IconButton';
3334
import { Pagination } from '@/elements/Pagination';
34-
import { ProfileSection } from '@/elements/Section';
3535
import { useClipboard } from '@/hooks';
36-
import { Check, Copy, RotateLeftRight } from '@/icons';
36+
import { Check, Copy, LinkIcon, RotateLeftRight } from '@/icons';
3737
import { common, mqu } from '@/styledSystem';
3838
import { handleError } from '@/utils/errorHandler';
3939

@@ -76,10 +76,7 @@ export const TestConfigurationStep = (): JSX.Element => {
7676
elementDescriptor={descriptors.configureSSOStep}
7777
elementId={descriptors.configureSSOStep.setId('test')}
7878
>
79-
<Step.Header
80-
title={localizationKeys('configureSSO.testConfigurationStep.title')}
81-
description={localizationKeys('configureSSO.testConfigurationStep.subtitle')}
82-
/>
79+
<Step.Header title={localizationKeys('configureSSO.testConfigurationStep.title')} />
8380

8481
<Step.Body>
8582
<Step.Section
@@ -89,74 +86,50 @@ export const TestConfigurationStep = (): JSX.Element => {
8986
borderBottomColor: theme.colors.$borderAlpha100,
9087
})}
9188
>
92-
<ProfileSection.Root
93-
title={localizationKeys('configureSSO.testConfigurationStep.testUrl.title')}
94-
id='testSsoUrl'
95-
centered={false}
96-
sx={t => ({
97-
borderTopWidth: 0,
98-
paddingTop: 0,
99-
paddingBottom: 0,
100-
flexDirection: 'column-reverse',
101-
gap: t.space.$1,
102-
})}
103-
>
89+
<Col gap={3}>
10490
<Text
105-
colorScheme='secondary'
106-
localizationKey={localizationKeys('configureSSO.testConfigurationStep.testUrl.subtitle')}
91+
as='p'
92+
localizationKey={localizationKeys('configureSSO.testConfigurationStep.subtitle')}
10793
/>
108-
<ProfileSection.Item
109-
id='testSsoUrl'
110-
sx={{ paddingInlineStart: 0 }}
111-
>
112-
<Flex gap={2}>
113-
<CopyTestUrlButton onTestRunCreated={handleTestRunCreated} />
114-
115-
<Button
116-
elementDescriptor={descriptors.configureSSOTestRefreshButton}
117-
variant='bordered'
118-
colorScheme='secondary'
119-
size='xs'
120-
onClick={() => void revalidateTestRuns()}
121-
isDisabled={areTestRunsLoading}
122-
sx={t => ({ gap: t.space.$1x5 })}
123-
>
124-
<Icon
125-
icon={RotateLeftRight}
126-
size='sm'
127-
colorScheme='neutral'
128-
/>
129-
<Text
130-
as='span'
131-
localizationKey={localizationKeys(
132-
'configureSSO.testConfigurationStep.testResults.actionLabel__refresh',
133-
)}
134-
/>
135-
</Button>
136-
</Flex>
137-
</ProfileSection.Item>
138-
</ProfileSection.Root>
94+
95+
<OpenTestUrlButton onTestRunCreated={handleTestRunCreated} />
96+
</Col>
13997
</Step.Section>
14098

141-
<Step.Section sx={{ flex: 1, minHeight: 0 }}>
142-
<ProfileSection.Root
143-
title={localizationKeys('configureSSO.testConfigurationStep.testResults.title')}
144-
id='testResults'
145-
centered={false}
146-
sx={t => ({
147-
borderTopWidth: 0,
148-
paddingTop: 0,
149-
paddingBottom: 0,
150-
flexDirection: 'column-reverse',
151-
gap: t.space.$2,
152-
flex: 1,
153-
minHeight: 0,
154-
'& > *:first-of-type': {
155-
flex: 1,
156-
minHeight: 0,
157-
},
158-
})}
99+
<Step.Section sx={t => ({ flex: 1, minHeight: 0, gap: t.space.$3 })}>
100+
<Flex
101+
align='center'
102+
justify='between'
103+
sx={t => ({ gap: t.space.$2, flexShrink: 0 })}
159104
>
105+
<Text
106+
variant='subtitle'
107+
localizationKey={localizationKeys('configureSSO.testConfigurationStep.testResults.title')}
108+
/>
109+
<Button
110+
elementDescriptor={descriptors.configureSSOTestRefreshButton}
111+
variant='bordered'
112+
colorScheme='secondary'
113+
size='xs'
114+
onClick={() => void revalidateTestRuns()}
115+
isDisabled={areTestRunsLoading}
116+
sx={t => ({ gap: t.space.$1x5 })}
117+
>
118+
<Icon
119+
icon={RotateLeftRight}
120+
size='sm'
121+
colorScheme='neutral'
122+
/>
123+
<Text
124+
as='span'
125+
localizationKey={localizationKeys(
126+
'configureSSO.testConfigurationStep.testResults.actionLabel__refresh',
127+
)}
128+
/>
129+
</Button>
130+
</Flex>
131+
132+
<Col sx={{ flex: 1, minHeight: 0 }}>
160133
<TestResultsTable
161134
rows={testRuns ?? []}
162135
isPolling={isPolling}
@@ -168,7 +141,7 @@ export const TestConfigurationStep = (): JSX.Element => {
168141
onPageChange={setCurrentPage}
169142
onTestRunCreated={handleTestRunCreated}
170143
/>
171-
</ProfileSection.Root>
144+
</Col>
172145
</Step.Section>
173146
</Step.Body>
174147

@@ -369,7 +342,7 @@ const TestResultsTable = ({
369342
justify='center'
370343
sx={t => ({ padding: `${t.space.$10} 0`, flex: 1 })}
371344
>
372-
<CopyTestUrlButton onTestRunCreated={onTestRunCreated} />
345+
<OpenTestUrlButton onTestRunCreated={onTestRunCreated} />
373346
</Flex>
374347
</Td>
375348
</Tr>
@@ -717,20 +690,18 @@ const TestRunStatusCell = ({ testRun }: { testRun: EnterpriseConnectionTestRunRe
717690
);
718691
};
719692

720-
type CopyTestUrlButtonProps = {
693+
type OpenTestUrlButtonProps = {
721694
onTestRunCreated?: (testUrl: string) => void;
722695
};
723696

724-
const CopyTestUrlButton = ({ onTestRunCreated }: CopyTestUrlButtonProps): JSX.Element => {
697+
const OpenTestUrlButton = ({ onTestRunCreated }: OpenTestUrlButtonProps): JSX.Element => {
725698
const { user } = useUser();
726699
const card = useCardState();
727700
const { enterpriseConnection } = useConfigureSSO();
728701

729-
const [testUrl, setTestUrl] = useState('');
730702
const [isCreatingTestRun, setIsCreatingTestRun] = useState(false);
731-
const { onCopy, hasCopied } = useClipboard(testUrl);
732703

733-
const createTestRun = () => {
704+
const openTestRun = () => {
734705
if (!user || !enterpriseConnection) {
735706
return;
736707
}
@@ -740,26 +711,25 @@ const CopyTestUrlButton = ({ onTestRunCreated }: CopyTestUrlButtonProps): JSX.El
740711
user
741712
.createEnterpriseConnectionTestRun(enterpriseConnection.id)
742713
.then(({ url }) => {
743-
setTestUrl(url);
744-
onCopy(url);
745714
onTestRunCreated?.(url);
715+
// `noopener,noreferrer` so the IdP can't reach back into the dashboard
716+
// via `window.opener` once it lands the SAML response.
717+
window.open(url, '_blank', 'noopener,noreferrer');
746718
})
747719
.catch(err => handleError(err as Error, [], card.setError))
748720
.finally(() => setIsCreatingTestRun(false));
749721
};
750722

751723
return (
752724
<Button
753-
elementDescriptor={descriptors.configureSSOTestUrlCopyButton}
725+
elementDescriptor={descriptors.configureSSOTestUrlOpenButton}
754726
id='testSsoUrl'
755727
variant='bordered'
756728
colorScheme='secondary'
757729
size='xs'
758-
onClick={createTestRun}
730+
onClick={openTestRun}
759731
isDisabled={isCreatingTestRun}
760-
sx={t => ({
761-
gap: t.space.$1x5,
762-
})}
732+
sx={t => ({ gap: t.space.$1x5, width: 'fit-content' })}
763733
>
764734
{isCreatingTestRun ? (
765735
<Spinner
@@ -768,14 +738,14 @@ const CopyTestUrlButton = ({ onTestRunCreated }: CopyTestUrlButtonProps): JSX.El
768738
/>
769739
) : (
770740
<Icon
771-
icon={hasCopied ? Check : Copy}
741+
icon={LinkIcon}
772742
size='sm'
773743
colorScheme='neutral'
774744
/>
775745
)}
776746
<Text
777747
as='span'
778-
localizationKey={localizationKeys('configureSSO.testConfigurationStep.testUrl.actionLabel__copy')}
748+
localizationKey={localizationKeys('configureSSO.testConfigurationStep.testUrl.actionLabel__open')}
779749
/>
780750
</Button>
781751
);

packages/ui/src/customizables/elementDescriptors.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -582,7 +582,7 @@ export const APPEARANCE_KEYS = containsAllElementsConfigKeys([
582582
'configureSSOCertificateFileName',
583583
'configureSSOCertificateRemoveButton',
584584

585-
'configureSSOTestUrlCopyButton',
585+
'configureSSOTestUrlOpenButton',
586586
'configureSSOTestRefreshButton',
587587
'configureSSOTestResultsTable',
588588
'configureSSOTestResultsRow',

packages/ui/src/internal/appearance.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -718,7 +718,7 @@ export type ElementsConfig = {
718718
configureSSOCertificateFileName: WithOptions;
719719
configureSSOCertificateRemoveButton: WithOptions;
720720

721-
configureSSOTestUrlCopyButton: WithOptions;
721+
configureSSOTestUrlOpenButton: WithOptions;
722722
configureSSOTestRefreshButton: WithOptions;
723723
configureSSOTestResultsTable: WithOptions;
724724
configureSSOTestResultsRow: WithOptions;

0 commit comments

Comments
 (0)