Skip to content

Commit 4967c0b

Browse files
#RI-5227 - auto create free db (#2856)
* #RI-5227 - auto create free db --------- Co-authored-by: Amir Allayarov <[email protected]>
1 parent c5ab762 commit 4967c0b

File tree

12 files changed

+401
-20
lines changed

12 files changed

+401
-20
lines changed

redisinsight/ui/src/components/oauth/oauth-select-account-dialog/OAuthSelectAccountDialog.tsx

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { useHistory } from 'react-router-dom'
1515

1616
import {
1717
activateAccount,
18+
createFreeDbJob,
1819
fetchPlans,
1920
oauthCloudPlanSelector,
2021
oauthCloudSelector,
@@ -26,8 +27,9 @@ import { Nullable } from 'uiSrc/utils'
2627
import { cloudSelector, fetchSubscriptionsRedisCloud } from 'uiSrc/slices/instances/cloud'
2728
import { TelemetryEvent, sendEventTelemetry } from 'uiSrc/telemetry'
2829
import { Pages } from 'uiSrc/constants'
29-
import { removeInfiniteNotification } from 'uiSrc/slices/app/notifications'
30-
import { InfiniteMessagesIds } from 'uiSrc/components/notifications/components'
30+
import { addInfiniteNotification, removeInfiniteNotification } from 'uiSrc/slices/app/notifications'
31+
import { INFINITE_MESSAGES, InfiniteMessagesIds } from 'uiSrc/components/notifications/components'
32+
import { CloudJobName, CloudJobStep } from 'uiSrc/electron/constants'
3133

3234
import styles from './styles.module.scss'
3335

@@ -36,7 +38,7 @@ interface FormValues {
3638
}
3739

3840
const OAuthSelectAccountDialog = () => {
39-
const { isAutodiscoverySSO } = useSelector(cloudSelector)
41+
const { isAutodiscoverySSO, isRecommendedSettings } = useSelector(cloudSelector)
4042
const { accounts = [], currentAccountId } = useSelector(oauthCloudUserDataSelector) ?? {}
4143
const { isOpenSelectAccountDialog } = useSelector(oauthCloudSelector)
4244
const { loading } = useSelector(oauthCloudUserSelector)
@@ -75,6 +77,20 @@ const OAuthSelectAccountDialog = () => {
7577
}
7678
))
7779
dispatch(setSelectAccountDialogState(false))
80+
} else if (isRecommendedSettings) {
81+
dispatch(createFreeDbJob({
82+
name: CloudJobName.CreateFreeSubscriptionAndDatabase,
83+
resources: {
84+
isRecommendedSettings
85+
},
86+
onSuccessAction: () => {
87+
dispatch(setSelectAccountDialogState(false))
88+
dispatch(addInfiniteNotification(INFINITE_MESSAGES.PENDING_CREATE_DB(CloudJobStep.Credentials)))
89+
},
90+
onFailAction: () => {
91+
dispatch(removeInfiniteNotification(InfiniteMessagesIds.oAuthProgress))
92+
}
93+
}))
7894
} else {
7995
dispatch(fetchPlans())
8096
}
@@ -86,7 +102,7 @@ const OAuthSelectAccountDialog = () => {
86102
accountsCount: accounts.length
87103
},
88104
})
89-
}, [isAutodiscoverySSO, accounts])
105+
}, [isAutodiscoverySSO, isRecommendedSettings, accounts])
90106

91107
const onActivateAccountFail = useCallback((error: string) => {
92108
sendEventTelemetry({

redisinsight/ui/src/components/oauth/oauth-social/OAuthSocial.spec.tsx

Lines changed: 77 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@ import { cleanup, fireEvent, mockedStore, render, waitForEuiToolTipVisible, act
44
import { TelemetryEvent, sendEventTelemetry } from 'uiSrc/telemetry'
55
import { CloudAuthSocial, IpcInvokeEvent } from 'uiSrc/electron/constants'
66
import { setOAuthCloudSource, signIn, oauthCloudPAgreementSelector } from 'uiSrc/slices/oauth/cloud'
7-
import { setIsAutodiscoverySSO } from 'uiSrc/slices/instances/cloud'
7+
import { setIsAutodiscoverySSO, setIsRecommendedSettingsSSO } from 'uiSrc/slices/instances/cloud'
88
import { OAuthSocialSource } from 'uiSrc/slices/interfaces'
9+
import { appFeatureFlagsFeaturesSelector } from 'uiSrc/slices/app/features'
10+
import { FeatureFlags } from 'uiSrc/constants'
911
import OAuthSocial, { OAuthSocialType } from './OAuthSocial'
1012

1113
jest.mock('uiSrc/telemetry', () => ({
@@ -21,6 +23,12 @@ jest.mock('uiSrc/slices/oauth/cloud', () => ({
2123
oauthCloudPAgreementSelector: jest.fn().mockReturnValue(true),
2224
}))
2325

26+
jest.mock('uiSrc/slices/app/features', () => ({
27+
...jest.requireActual('uiSrc/slices/app/features'),
28+
appFeatureFlagsFeaturesSelector: jest.fn().mockReturnValue({
29+
}),
30+
}))
31+
2432
let store: typeof mockedStore
2533
const invokeMock = jest.fn()
2634
beforeEach(() => {
@@ -50,13 +58,14 @@ describe('OAuthSocial', () => {
5058
eventData: {
5159
accountOption: 'Google',
5260
action: 'create',
61+
recommendedSettings: null
5362
}
5463
})
5564

5665
expect(invokeMock).toBeCalledTimes(1)
5766
expect(invokeMock).toBeCalledWith(IpcInvokeEvent.cloudOauth, { action: 'create', strategy: CloudAuthSocial.Google })
5867

59-
const expectedActions = [signIn(), setIsAutodiscoverySSO(false)]
68+
const expectedActions = [signIn(), setIsAutodiscoverySSO(false), setIsRecommendedSettingsSSO(undefined)]
6069
expect(store.getActions()).toEqual(expectedActions)
6170

6271
invokeMock.mockRestore();
@@ -76,20 +85,85 @@ describe('OAuthSocial', () => {
7685
eventData: {
7786
accountOption: 'GitHub',
7887
action: 'create',
88+
recommendedSettings: null
7989
}
8090
})
8191

8292
expect(invokeMock).toBeCalledTimes(1)
8393
expect(invokeMock).toBeCalledWith(IpcInvokeEvent.cloudOauth, { action: 'create', strategy: CloudAuthSocial.Github })
8494
invokeMock.mockRestore()
8595

86-
const expectedActions = [signIn(), setIsAutodiscoverySSO(false)]
96+
const expectedActions = [signIn(), setIsAutodiscoverySSO(false), setIsRecommendedSettingsSSO(undefined)]
8797
expect(store.getActions()).toEqual(expectedActions)
8898

8999
invokeMock.mockRestore();
90100
(sendEventTelemetry as jest.Mock).mockRestore()
91101
})
92102

103+
describe('Recommended Settings Enabled', () => {
104+
beforeEach(() => {
105+
(appFeatureFlagsFeaturesSelector as jest.Mock).mockReturnValue({
106+
[FeatureFlags.cloudSsoRecommendedSettings]: {
107+
flag: true
108+
}
109+
})
110+
})
111+
it('should send telemetry after click on google btn', async () => {
112+
const sendEventTelemetryMock = jest.fn();
113+
(sendEventTelemetry as jest.Mock).mockImplementation(() => sendEventTelemetryMock)
114+
115+
const { queryByTestId } = render(<OAuthSocial />)
116+
117+
fireEvent.click(queryByTestId('google-oauth') as HTMLButtonElement)
118+
119+
expect(sendEventTelemetry).toBeCalledWith({
120+
event: TelemetryEvent.CLOUD_SIGN_IN_SOCIAL_ACCOUNT_SELECTED,
121+
eventData: {
122+
accountOption: 'Google',
123+
action: 'create',
124+
recommendedSettings: 'enabled'
125+
}
126+
})
127+
128+
expect(invokeMock).toBeCalledTimes(1)
129+
expect(invokeMock).toBeCalledWith(IpcInvokeEvent.cloudOauth, { action: 'create', strategy: CloudAuthSocial.Google })
130+
131+
const expectedActions = [signIn(), setIsAutodiscoverySSO(false), setIsRecommendedSettingsSSO(true)]
132+
expect(store.getActions()).toEqual(expectedActions)
133+
134+
invokeMock.mockRestore();
135+
(sendEventTelemetry as jest.Mock).mockRestore()
136+
})
137+
138+
it('should send telemetry after click on github btn', async () => {
139+
const sendEventTelemetryMock = jest.fn();
140+
(sendEventTelemetry as jest.Mock).mockImplementation(() => sendEventTelemetryMock)
141+
142+
const { queryByTestId } = render(<OAuthSocial />)
143+
144+
fireEvent.click(queryByTestId('github-oauth') as HTMLButtonElement)
145+
146+
expect(sendEventTelemetry).toBeCalledWith({
147+
event: TelemetryEvent.CLOUD_SIGN_IN_SOCIAL_ACCOUNT_SELECTED,
148+
eventData: {
149+
accountOption: 'GitHub',
150+
action: 'create',
151+
recommendedSettings: 'enabled'
152+
}
153+
})
154+
155+
expect(invokeMock).toBeCalledTimes(1)
156+
expect(invokeMock).toBeCalledWith(IpcInvokeEvent.cloudOauth, { action: 'create', strategy: CloudAuthSocial.Github })
157+
invokeMock.mockRestore()
158+
159+
const expectedActions = [signIn(), setIsAutodiscoverySSO(false), setIsRecommendedSettingsSSO(true)]
160+
expect(store.getActions()).toEqual(expectedActions)
161+
162+
invokeMock.mockRestore();
163+
(sendEventTelemetry as jest.Mock).mockRestore()
164+
})
165+
})
166+
93167
describe('Autodiscovery', () => {
94168
it('should send telemetry after click on google btn', async () => {
95169
const sendEventTelemetryMock = jest.fn();

redisinsight/ui/src/components/oauth/oauth-social/OAuthSocial.tsx

Lines changed: 55 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,22 @@
1-
import React from 'react'
2-
import { EuiButtonIcon, EuiText, EuiTitle, EuiToolTip } from '@elastic/eui'
1+
import React, { useState } from 'react'
2+
import { EuiButtonIcon, EuiCheckbox, EuiIcon, EuiText, EuiTitle, EuiToolTip } from '@elastic/eui'
33
import cx from 'classnames'
44
import { useDispatch, useSelector } from 'react-redux'
55

66
import { ipcAuthGithub, ipcAuthGoogle } from 'uiSrc/electron/utils'
77
import { TelemetryEvent, sendEventTelemetry } from 'uiSrc/telemetry'
88
import { setOAuthCloudSource, signIn, oauthCloudPAgreementSelector } from 'uiSrc/slices/oauth/cloud'
9-
import { OAuthAgreement } from 'uiSrc/components'
9+
import { FeatureFlagComponent, OAuthAgreement } from 'uiSrc/components'
10+
import { setIsRecommendedSettingsSSO, setIsAutodiscoverySSO } from 'uiSrc/slices/instances/cloud'
11+
import { OAuthSocialSource } from 'uiSrc/slices/interfaces'
12+
import { FeatureFlags } from 'uiSrc/constants'
13+
import { appFeatureFlagsFeaturesSelector } from 'uiSrc/slices/app/features'
1014

1115
import { ReactComponent as GoogleIcon } from 'uiSrc/assets/img/oauth/google.svg'
1216
import { ReactComponent as GithubIcon } from 'uiSrc/assets/img/oauth/github.svg'
1317
import { ReactComponent as GoogleSmallIcon } from 'uiSrc/assets/img/oauth/google_small.svg'
1418
import { ReactComponent as GithubSmallIcon } from 'uiSrc/assets/img/oauth/github_small.svg'
1519

16-
import { setIsAutodiscoverySSO } from 'uiSrc/slices/instances/cloud'
17-
import { OAuthSocialSource } from 'uiSrc/slices/interfaces'
1820
import styles from './styles.module.scss'
1921

2022
export enum OAuthSocialType {
@@ -29,6 +31,10 @@ interface Props {
2931

3032
const OAuthSocial = ({ type = OAuthSocialType.Modal, hideTitle = false }: Props) => {
3133
const agreement = useSelector(oauthCloudPAgreementSelector)
34+
const {
35+
[FeatureFlags.cloudSsoRecommendedSettings]: isRecommendedFeatureEnabled
36+
} = useSelector(appFeatureFlagsFeaturesSelector)
37+
const [isRecommended, setIsRecommended] = useState(isRecommendedFeatureEnabled?.flag ? true : undefined)
3238

3339
const dispatch = useDispatch()
3440
const isAutodiscovery = type === OAuthSocialType.Autodiscovery
@@ -39,9 +45,23 @@ const OAuthSocial = ({ type = OAuthSocialType.Modal, hideTitle = false }: Props)
3945
eventData: {
4046
accountOption,
4147
action: getAction(),
48+
recommendedSettings: isAutodiscovery
49+
? undefined
50+
: (!isRecommendedFeatureEnabled?.flag
51+
? null
52+
: (isRecommended ? 'enabled' : 'disabled'))
4253
}
4354
})
4455

56+
const handleClickSso = () => {
57+
dispatch(signIn())
58+
dispatch(setIsAutodiscoverySSO(isAutodiscovery))
59+
isAutodiscovery && dispatch(setOAuthCloudSource(OAuthSocialSource.Autodiscovery))
60+
if (!isAutodiscovery) {
61+
dispatch(setIsRecommendedSettingsSSO(isRecommended))
62+
}
63+
}
64+
4565
const socialLinks = [
4666
{
4767
className: styles.googleButton,
@@ -76,9 +96,7 @@ const OAuthSocial = ({ type = OAuthSocialType.Modal, hideTitle = false }: Props)
7696
disabled={!agreement}
7797
className={cx(styles.button, className)}
7898
onClick={() => {
79-
dispatch(signIn())
80-
dispatch(setIsAutodiscoverySSO(isAutodiscovery))
81-
isAutodiscovery && dispatch(setOAuthCloudSource(OAuthSocialSource.Autodiscovery))
99+
handleClickSso()
82100
onButtonClick()
83101
}}
84102
data-testid={label}
@@ -87,11 +105,40 @@ const OAuthSocial = ({ type = OAuthSocialType.Modal, hideTitle = false }: Props)
87105
</EuiToolTip>
88106
))
89107

108+
const RecommendedSettingsCheckBox = () => (
109+
<FeatureFlagComponent name={FeatureFlags.cloudSsoRecommendedSettings}>
110+
<div className={styles.recommendedSettings}>
111+
<EuiCheckbox
112+
id="ouath-recommended-settings"
113+
name="recommended-settings"
114+
label="Use recommended settings"
115+
checked={isRecommended}
116+
onChange={(e) => setIsRecommended(e.target.checked)}
117+
data-testid="oauth-recommended-settings-checkbox"
118+
/>
119+
<EuiToolTip
120+
content={(
121+
<>
122+
The database will be automatically created using a pre-selected provider and region.
123+
<br />
124+
You can change it by signing in to Redis Cloud.
125+
</>
126+
)}
127+
position="top"
128+
anchorClassName={styles.recommendedSettingsToolTip}
129+
>
130+
<EuiIcon type="iInCircle" size="s" />
131+
</EuiToolTip>
132+
</div>
133+
</FeatureFlagComponent>
134+
)
135+
90136
if (!isAutodiscovery) {
91137
return (
92138
<div className={cx(styles.container)}>
93139
{buttons}
94140
<div className={styles.containerAgreement}>
141+
<RecommendedSettingsCheckBox />
95142
<OAuthAgreement />
96143
</div>
97144
</div>

redisinsight/ui/src/components/oauth/oauth-social/styles.module.scss

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,3 +76,38 @@
7676
margin-top: 16px;
7777
text-align: left;
7878
}
79+
80+
.recommendedSettings {
81+
display: flex;
82+
align-items: center;
83+
84+
.recommendedSettingsToolTip {
85+
display: inline-flex;
86+
margin-left: 4px;
87+
margin-bottom: 4px;
88+
89+
:global {
90+
svg {
91+
width: 14px;
92+
height: 14px;
93+
}
94+
}
95+
}
96+
97+
:global(.euiCheckbox) {
98+
margin-bottom: 6px;
99+
100+
:global(.euiCheckbox__label) {
101+
font: normal normal normal 10px/15px Graphik, sans-serif !important;
102+
color: var(--htmlColor) !important;
103+
padding-left: 16px !important;
104+
}
105+
106+
:global(.euiCheckbox__square) {
107+
width: 12px;
108+
height: 12px;
109+
padding: 0 !important;
110+
border-width: 1px !important;
111+
}
112+
}
113+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
export enum FeatureFlags {
22
insightsRecommendations = 'insightsRecommendations',
33
cloudSso = 'cloudSso',
4+
cloudSsoRecommendedSettings = 'cloudSsoRecommendedSettings',
45
}

0 commit comments

Comments
 (0)