fix: don't show login prompt if token is defined in state
Signed-off-by: Ali Dalal <ali.dalal@bonial.com>
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder': patch
|
||||
---
|
||||
|
||||
Don't show login prompt if token is set in the state
|
||||
@@ -455,7 +455,9 @@ export interface ScaffolderUseTemplateSecrets {
|
||||
|
||||
// @public
|
||||
export const SecretsContextProvider: (
|
||||
props: PropsWithChildren<{}>,
|
||||
props: PropsWithChildren<{
|
||||
initialSecrets?: Record<string, string>;
|
||||
}>,
|
||||
) => React_2.JSX.Element;
|
||||
|
||||
// @public
|
||||
|
||||
@@ -35,4 +35,20 @@ describe('SecretsContext', () => {
|
||||
|
||||
expect(result.current.hook?.secrets.foo).toEqual('bar');
|
||||
});
|
||||
|
||||
it('should create SecretsContextProvider with initial secrets', async () => {
|
||||
const { result } = renderHook(
|
||||
() => ({
|
||||
hook: useTemplateSecrets(),
|
||||
}),
|
||||
{
|
||||
wrapper: ({ children }: React.PropsWithChildren<{}>) => (
|
||||
<SecretsContextProvider initialSecrets={{ foo: 'bar' }}>
|
||||
{children}
|
||||
</SecretsContextProvider>
|
||||
),
|
||||
},
|
||||
);
|
||||
expect(result.current.hook?.secrets.foo).toEqual('bar');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -43,8 +43,13 @@ const SecretsContext = createVersionedContext<{
|
||||
* The Context Provider that holds the state for the secrets.
|
||||
* @public
|
||||
*/
|
||||
export const SecretsContextProvider = (props: PropsWithChildren<{}>) => {
|
||||
const [secrets, setSecrets] = useState<Record<string, string>>({});
|
||||
export const SecretsContextProvider = (
|
||||
props: PropsWithChildren<{ initialSecrets?: Record<string, string> }>,
|
||||
) => {
|
||||
const { initialSecrets = {} } = props;
|
||||
const [secrets, setSecrets] = useState<Record<string, string>>({
|
||||
...initialSecrets,
|
||||
});
|
||||
|
||||
return (
|
||||
<SecretsContext.Provider
|
||||
|
||||
@@ -58,9 +58,13 @@ describe('RepoUrlPicker', () => {
|
||||
byHost: () => ({ type: 'github' }),
|
||||
};
|
||||
|
||||
const mockScmAuthApi: Partial<ScmAuthApi> = {
|
||||
getCredentials: jest.fn().mockResolvedValue({ token: 'abc123' }),
|
||||
};
|
||||
let mockScmAuthApi: Partial<ScmAuthApi>;
|
||||
|
||||
beforeEach(() => {
|
||||
mockScmAuthApi = {
|
||||
getCredentials: jest.fn().mockResolvedValue({ token: 'abc123' }),
|
||||
};
|
||||
});
|
||||
|
||||
describe('happy path rendering', () => {
|
||||
it('should render the repo url picker with minimal props', async () => {
|
||||
@@ -350,5 +354,64 @@ describe('RepoUrlPicker', () => {
|
||||
secrets: { testKey: 'abc123' },
|
||||
});
|
||||
});
|
||||
|
||||
it('should not call the scmAuthApi if secret is available in the state', async () => {
|
||||
const SecretsComponent = () => {
|
||||
const { secrets } = useTemplateSecrets();
|
||||
return (
|
||||
<div data-testid="current-secrets">{JSON.stringify({ secrets })}</div>
|
||||
);
|
||||
};
|
||||
const { getAllByRole, getByTestId } = await renderInTestApp(
|
||||
<TestApiProvider
|
||||
apis={[
|
||||
[scmIntegrationsApiRef, mockIntegrationsApi],
|
||||
[scmAuthApiRef, mockScmAuthApi],
|
||||
[scaffolderApiRef, mockScaffolderApi],
|
||||
]}
|
||||
>
|
||||
<SecretsContextProvider initialSecrets={{ testKey: 'abc123' }}>
|
||||
<Form
|
||||
validator={validator}
|
||||
schema={{ type: 'string' }}
|
||||
uiSchema={{
|
||||
'ui:field': 'RepoUrlPicker',
|
||||
'ui:options': {
|
||||
requestUserCredentials: {
|
||||
secretsKey: 'testKey',
|
||||
additionalScopes: { github: ['workflow'] },
|
||||
},
|
||||
},
|
||||
}}
|
||||
fields={{
|
||||
RepoUrlPicker: RepoUrlPicker as ScaffolderRJSFField<string>,
|
||||
}}
|
||||
/>
|
||||
<SecretsComponent />
|
||||
</SecretsContextProvider>
|
||||
</TestApiProvider>,
|
||||
);
|
||||
|
||||
const [ownerInput, repoInput] = getAllByRole('textbox');
|
||||
|
||||
await act(async () => {
|
||||
fireEvent.change(ownerInput, { target: { value: 'backstage' } });
|
||||
fireEvent.change(repoInput, { target: { value: 'repo123' } });
|
||||
|
||||
// need to wait for the debounce to finish
|
||||
await new Promise(resolve => setTimeout(resolve, 600));
|
||||
});
|
||||
|
||||
// as we already have a secret in the state, getCredentials should not be called again.
|
||||
expect(mockScmAuthApi.getCredentials).toHaveBeenCalledTimes(0);
|
||||
|
||||
const currentSecrets = JSON.parse(
|
||||
getByTestId('current-secrets').textContent!,
|
||||
);
|
||||
|
||||
expect(currentSecrets).toEqual({
|
||||
secrets: { testKey: 'abc123' },
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -51,7 +51,7 @@ export const RepoUrlPicker = (props: RepoUrlPickerProps) => {
|
||||
);
|
||||
const integrationApi = useApi(scmIntegrationsApiRef);
|
||||
const scmAuthApi = useApi(scmAuthApiRef);
|
||||
const { setSecrets } = useTemplateSecrets();
|
||||
const { secrets, setSecrets } = useTemplateSecrets();
|
||||
const allowedHosts = useMemo(
|
||||
() => uiSchema?.['ui:options']?.allowedHosts ?? [],
|
||||
[uiSchema],
|
||||
@@ -132,6 +132,11 @@ export const RepoUrlPicker = (props: RepoUrlPickerProps) => {
|
||||
return;
|
||||
}
|
||||
|
||||
// don't show login prompt if secret value is already in state
|
||||
if (secrets[requestUserCredentials.secretsKey]) {
|
||||
return;
|
||||
}
|
||||
|
||||
// previously, we were encodeURI for state.host, workspace and state.repoName separately.
|
||||
// That created an issue where GitLab workspace can be nested like groupA/subgroupB
|
||||
// when we encodeURi separately and then join, the URL will be malformed and
|
||||
|
||||
Reference in New Issue
Block a user