Skip to content

Commit f70eb97

Browse files
Merge pull request #633 from devtron-labs/feat/devtron-license-helpers
feat: add country selector, flag image and phone input components
2 parents b702ed5 + 5e7e65b commit f70eb97

35 files changed

+363
-74
lines changed

package-lock.json

Lines changed: 11 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@devtron-labs/devtron-fe-common-lib",
3-
"version": "1.9.5",
3+
"version": "1.9.5-beta-11",
44
"description": "Supporting common component library",
55
"type": "module",
66
"main": "dist/index.js",
@@ -123,6 +123,7 @@
123123
"react-dates": "^21.8.0",
124124
"react-diff-viewer-continued": "^3.4.0",
125125
"react-draggable": "^4.4.5",
126+
"react-international-phone": "^4.5.0",
126127
"react-monaco-editor": "^0.54.0",
127128
"react-virtualized-sticky-tree": "^3.0.0-beta18",
128129
"sass": "^1.69.7",

src/Assets/IconV2/ic-caret-left.svg

Lines changed: 3 additions & 0 deletions
Loading

src/Common/API/CoreAPI.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ class CoreAPI {
2525
signal,
2626
preventAutoLogout = false,
2727
preventLicenseRedirect = false,
28+
shouldParseServerErrorForUnauthorizedUser = false,
2829
isMultipartRequest,
2930
}: FetchAPIParamsType<K>): Promise<ResponseType> => {
3031
const options: RequestInit = {
@@ -60,6 +61,11 @@ class CoreAPI {
6061
const contentType = response.headers.get('Content-Type')
6162
if (response.status === API_STATUS_CODES.UNAUTHORIZED) {
6263
if (preventAutoLogout) {
64+
if (shouldParseServerErrorForUnauthorizedUser) {
65+
await handleServerError(contentType, response)
66+
// Won't reach here as handleServerError will throw an error
67+
return null
68+
}
6369
throw new ServerErrors({
6470
code: API_STATUS_CODES.UNAUTHORIZED,
6571
errors: [
@@ -161,6 +167,7 @@ class CoreAPI {
161167
signal,
162168
preventAutoLogout: options?.preventAutoLogout || false,
163169
preventLicenseRedirect: options?.preventLicenseRedirect || false,
170+
shouldParseServerErrorForUnauthorizedUser: options?.shouldParseServerErrorForUnauthorizedUser,
164171
isMultipartRequest,
165172
}),
166173
timeoutPromise,

src/Common/API/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,6 @@ export interface FetchInTimeParamsType<Data = object> {
2323

2424
export interface FetchAPIParamsType<Data = object>
2525
extends Omit<FetchInTimeParamsType<Data>, 'options'>,
26-
Pick<APIOptions, 'preventAutoLogout' | 'preventLicenseRedirect'> {
26+
Pick<APIOptions, 'preventAutoLogout' | 'preventLicenseRedirect' | 'shouldParseServerErrorForUnauthorizedUser'> {
2727
signal: AbortSignal
2828
}

src/Common/Constants.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export const FALLBACK_REQUEST_TIMEOUT = 60000
1818
export const Host = window?.__ORCHESTRATOR_ROOT__ ?? '/orchestrator'
1919

2020
export const DOCUMENTATION_HOME_PAGE = 'https://docs.devtron.ai'
21+
export const DEVTRON_HOME_PAGE = 'https://devtron.ai/'
2122
export const DOCUMENTATION_VERSION = '/v/v0.7'
2223
export const DISCORD_LINK = 'https://discord.devtron.ai/'
2324
export const DEFAULT_JSON_SCHEMA_URI = 'https://json-schema.org/draft/2020-12/schema'
@@ -367,6 +368,7 @@ export const API_STATUS_CODES = {
367368
PERMISSION_DENIED: 403,
368369
NOT_FOUND: 404,
369370
REQUEST_TIMEOUT: 408,
371+
CONFLICT: 409,
370372
EXPECTATION_FAILED: 417,
371373
UNPROCESSABLE_ENTITY: 422,
372374
LOCKED: 423,

src/Common/Types.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,10 @@ export interface APIOptions {
7373
* @default false
7474
*/
7575
preventLicenseRedirect?: boolean
76+
/**
77+
* @default false
78+
*/
79+
shouldParseServerErrorForUnauthorizedUser?: boolean
7680
}
7781

7882
export interface OptionType<T = string, K = string> {
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import { useMemo } from 'react'
2+
import { SelectPicker, SelectPickerProps } from '../SelectPicker'
3+
import { CountrySelectProps } from './types'
4+
import { getCountryOptions } from './utils'
5+
import { FlagImage } from '../FlagImage'
6+
7+
const CountrySelect = ({
8+
selectedCountry,
9+
label,
10+
required,
11+
error,
12+
handleChange,
13+
placeholder,
14+
name,
15+
variant = 'default',
16+
size,
17+
onMenuClose,
18+
onMenuOpen,
19+
}: CountrySelectProps) => {
20+
const countryOptions = useMemo(() => getCountryOptions(variant), [variant])
21+
22+
const onChange = (option: (typeof countryOptions)[number]) => {
23+
handleChange(option.value.iso2)
24+
}
25+
26+
const selectedOption: (typeof countryOptions)[number] = selectedCountry
27+
? countryOptions.find((option) => option.value.iso2 === selectedCountry) || null
28+
: null
29+
30+
const filterOption: SelectPickerProps<(typeof countryOptions)[number]['value']>['filterOption'] = (
31+
option,
32+
searchText,
33+
) => {
34+
const searchValue = searchText.toLowerCase()
35+
const searchCriterion = [option.data.value.name.toLowerCase(), `+${option.data.value.dialCode.toLowerCase()}`]
36+
37+
return searchCriterion.some((criterion) => criterion.includes(searchValue))
38+
}
39+
40+
const getOptionValue: SelectPickerProps<(typeof countryOptions)[number]['value']>['getOptionValue'] = (option) =>
41+
option.value.iso2
42+
43+
return (
44+
<SelectPicker<(typeof countryOptions)[number]['value'], false>
45+
inputId={`select-picker__country-select--${name}`}
46+
value={selectedOption}
47+
onChange={onChange}
48+
error={error}
49+
required={required}
50+
label={label}
51+
options={countryOptions}
52+
placeholder={placeholder}
53+
size={size}
54+
filterOption={filterOption}
55+
getOptionValue={getOptionValue}
56+
onMenuClose={onMenuClose}
57+
onMenuOpen={onMenuOpen}
58+
icon={
59+
variant === 'selectPhoneCode' && selectedOption?.value?.iso2 ? (
60+
<FlagImage country={selectedOption?.value?.iso2} />
61+
) : null
62+
}
63+
controlShouldRenderValue={variant !== 'selectPhoneCode'}
64+
fullWidth
65+
/>
66+
)
67+
}
68+
69+
export default CountrySelect
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { default as CountrySelect } from './CountrySelect.component'
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { CountryISO2Type } from '@Shared/index'
2+
import { SelectPickerProps } from '../SelectPicker'
3+
4+
export interface CountrySelectProps
5+
extends Pick<
6+
SelectPickerProps,
7+
'required' | 'label' | 'error' | 'placeholder' | 'size' | 'onMenuOpen' | 'onMenuClose'
8+
>,
9+
Required<Pick<SelectPickerProps, 'name'>> {
10+
selectedCountry: CountryISO2Type
11+
handleChange: (iso2: CountryISO2Type) => void
12+
variant?: 'default' | 'selectPhoneCode'
13+
}

0 commit comments

Comments
 (0)