Skip to content

Commit 5273dc3

Browse files
committed
ui: add optional Custom Domain input in GH integration
1 parent 8a545c0 commit 5273dc3

File tree

2 files changed

+66
-7
lines changed

2 files changed

+66
-7
lines changed

web-server/src/content/Dashboards/ConfigureGithubModalBody.tsx

Lines changed: 50 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,12 @@ export const ConfigureGithubModalBody: FC<{
2525
const token = useEasyState('');
2626
const { orgId } = useAuth();
2727
const { enqueueSnackbar } = useSnackbar();
28+
const customDomain = useEasyState('');
2829
const dispatch = useDispatch();
2930
const isLoading = useBoolState();
3031

3132
const showError = useEasyState<string>('');
33+
const showDomainError = useEasyState<string>('');
3234

3335
const setError = useCallback(
3436
(error: string) => {
@@ -42,20 +44,24 @@ export const ConfigureGithubModalBody: FC<{
4244
token.set(e);
4345
showError.set('');
4446
};
47+
const handleDomainChange = (e: string) => {
48+
customDomain.set(e);
49+
showDomainError.set('');
50+
};
4551

4652
const handleSubmission = useCallback(async () => {
4753
if (!token.value) {
4854
setError('Please enter a valid token');
4955
return;
5056
}
5157
depFn(isLoading.true);
52-
checkGitHubValidity(token.value)
58+
checkGitHubValidity(token.value, customDomain.valueRef.current)
5359
.then(async (isValid) => {
5460
if (!isValid) throw new Error('Invalid token');
5561
})
5662
.then(async () => {
5763
try {
58-
const res = await getMissingPATScopes(token.value);
64+
const res = await getMissingPATScopes(token.value, customDomain.valueRef.current);
5965
if (res.length) {
6066
throw new Error(`Token is missing scopes: ${res.join(', ')}`);
6167
}
@@ -66,7 +72,9 @@ export const ConfigureGithubModalBody: FC<{
6672
})
6773
.then(async () => {
6874
try {
69-
return await linkProvider(token.value, orgId, Integration.GITHUB);
75+
return await linkProvider(token.value, orgId, Integration.GITHUB, {
76+
custom_domain: customDomain.valueRef.current
77+
});
7078
} catch (e: any) {
7179
throw new Error(
7280
`Failed to link Github${e?.message ? `: ${e?.message}` : ''}`,
@@ -102,6 +110,13 @@ export const ConfigureGithubModalBody: FC<{
102110
setError,
103111
token.value
104112
]);
113+
const isDomainInputFocus = useBoolState(false);
114+
115+
const focusDomainInput = useCallback(() => {
116+
if (!customDomain.value)
117+
document.getElementById('gitlab-custom-domain')?.focus();
118+
else handleSubmission();
119+
}, [customDomain.value, handleSubmission]);
105120

106121
return (
107122
<FlexBox gap2>
@@ -115,6 +130,7 @@ export const ConfigureGithubModalBody: FC<{
115130
e.stopPropagation();
116131
e.nativeEvent.stopImmediatePropagation();
117132
handleSubmission();
133+
focusDomainInput();
118134
return;
119135
}
120136
}}
@@ -150,6 +166,37 @@ export const ConfigureGithubModalBody: FC<{
150166
</Line>
151167
</FlexBox>
152168
</FlexBox>
169+
<FlexBox gap2 col>
170+
<FlexBox alignBase gap1>
171+
Custom domain
172+
</FlexBox>
173+
<TextField
174+
id="github-custom-domain"
175+
onKeyDown={(e) => {
176+
if (e.key === 'Enter') {
177+
e.preventDefault();
178+
e.stopPropagation();
179+
e.nativeEvent.stopImmediatePropagation();
180+
handleSubmission();
181+
return;
182+
}
183+
}}
184+
error={!!showDomainError.value}
185+
sx={{ width: '100%' }}
186+
value={customDomain.value}
187+
onChange={(e) => handleDomainChange(e.currentTarget.value)}
188+
label={
189+
isDomainInputFocus.value || customDomain.value
190+
? 'Custom Domain'
191+
: '(Optional)'
192+
}
193+
onFocus={isDomainInputFocus.true}
194+
onBlur={isDomainInputFocus.false}
195+
/>
196+
</FlexBox>
197+
<Line error tiny mt={1} minHeight={'18px'}>
198+
{showDomainError.value}
199+
</Line>
153200

154201
<FlexBox justifyBetween alignCenter mt={'auto'}>
155202
<FlexBox col sx={{ opacity: 0.8 }}>

web-server/src/utils/auth.ts

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import { isNil, reject } from 'ramda';
33

44
import { Integration } from '@/constants/integrations';
55

6+
const DEFAULT_GH_URL = 'https://api.github.com';
7+
68
export const unlinkProvider = async (orgId: string, provider: Integration) => {
79
return await axios.delete(`/api/resources/orgs/${orgId}/integration`, {
810
params: { provider }
@@ -28,10 +30,17 @@ export const linkProvider = async (
2830
// GitHub functions
2931

3032
export async function checkGitHubValidity(
31-
good_stuff: string
33+
good_stuff: string,
34+
customDomain?: string
3235
): Promise<boolean> {
3336
try {
34-
await axios.get('https://api.github.com/user', {
37+
// if customDomain is provded, the host will be customDomain/api/v3
38+
// else it will be api.github.com(default)
39+
const baseUrl = customDomain
40+
? `${customDomain}/api/v3`
41+
: DEFAULT_GH_URL;
42+
43+
await axios.get(`${baseUrl}/user`, {
3544
headers: {
3645
Authorization: `token ${good_stuff}`
3746
}
@@ -43,9 +52,12 @@ export async function checkGitHubValidity(
4352
}
4453

4554
const PAT_SCOPES = ['read:org', 'read:user', 'repo', 'workflow'];
46-
export const getMissingPATScopes = async (pat: string) => {
55+
export const getMissingPATScopes = async (pat: string, customDomain?: string) => {
56+
const baseUrl = customDomain
57+
? `${customDomain}/api/v3`
58+
: DEFAULT_GH_URL;
4759
try {
48-
const response = await axios.get('https://api.github.com', {
60+
const response = await axios.get(baseUrl, {
4961
headers: {
5062
Authorization: `token ${pat}`
5163
}

0 commit comments

Comments
 (0)