Skip to content

Commit abac0ad

Browse files
committed
feat: refactor ApplicationMonitoring and ClusterForm to use isAppMetricsEnabled and toggleAppMetrics for better state management
1 parent 7fd8ddf commit abac0ad

File tree

4 files changed

+83
-43
lines changed

4 files changed

+83
-43
lines changed

src/Pages/GlobalConfigurations/ClustersAndEnvironments/ClusterForm/ApplicationMonitoring.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ import { ApplicationMonitoringProps } from './types'
66
const ApplicationMonitoring = ({
77
prometheusConfig,
88
prometheusUrl,
9-
prometheusToggleEnabled,
10-
setPrometheusToggle,
9+
isAppMetricsEnabled,
10+
toggleAppMetrics,
1111
handleOnChange,
1212
onPrometheusAuthTypeChange,
1313
isGrafanaModuleInstalled,
@@ -29,13 +29,13 @@ const ApplicationMonitoring = ({
2929
<DTSwitch
3030
name="toggle-configure-prometheus"
3131
ariaLabel="Toggle configure prometheus"
32-
isChecked={prometheusToggleEnabled}
33-
onChange={setPrometheusToggle}
32+
isChecked={isAppMetricsEnabled}
33+
onChange={toggleAppMetrics}
3434
isDisabled={!isGrafanaModuleInstalled}
3535
/>
3636
</div>
37-
{!prometheusToggleEnabled && prometheusUrl && <PrometheusWarningInfo />}
38-
{prometheusToggleEnabled && (
37+
{!isAppMetricsEnabled && prometheusUrl && <PrometheusWarningInfo />}
38+
{isAppMetricsEnabled && (
3939
<PromoetheusConfigCard
4040
prometheusConfig={prometheusConfig}
4141
handleOnChange={handleOnChange}

src/Pages/GlobalConfigurations/ClustersAndEnvironments/ClusterForm/ClusterForm.tsx

Lines changed: 54 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ const ClusterForm = ({
100100
})
101101
const [costModuleConfigErrorState, setCostModuleErrorState] = useState<string>('')
102102

103-
const [prometheusToggleEnabled, setPrometheusToggleEnabled] = useState(!!prometheusUrl)
103+
const [isAppMetricsEnabled, setIsAppMetricsEnabled] = useState(!!prometheusUrl)
104104
const [prometheusAuthenticationType, setPrometheusAuthenticationType] = useState({
105105
type: prometheusAuth?.userName ? AuthenticationType.BASIC : AuthenticationType.ANONYMOUS,
106106
})
@@ -111,6 +111,8 @@ const ClusterForm = ({
111111
const [isConnectedViaProxyTemp, setIsConnectedViaProxyTemp] = useState(!!proxyUrl)
112112
const [isConnectedViaSSHTunnelTemp, setIsConnectedViaSSHTunnelTemp] = useState(isConnectedViaSSHTunnel)
113113

114+
const isPrometheusEnabled = costModuleState.enabled || isAppMetricsEnabled
115+
114116
const getRemoteConnectionConfigType = () => {
115117
if (isConnectedViaProxyTemp) {
116118
return RemoteConnectionType.Proxy
@@ -236,25 +238,35 @@ const ClusterForm = ({
236238
isProd: state.isProd.value === 'true',
237239
active: true,
238240
remoteConnectionConfig: getRemoteConnectionConfig(state, remoteConnectionMethod, SSHConnectionType),
239-
prometheus_url: prometheusToggleEnabled ? state.endpoint.value : '',
241+
prometheus_url: isPrometheusEnabled ? state.endpoint.value : '',
240242
prometheusAuth: {
241243
userName:
242-
prometheusToggleEnabled && state.authType.value === AuthenticationType.BASIC
243-
? state.userName.value
244-
: '',
244+
isPrometheusEnabled && state.authType.value === AuthenticationType.BASIC ? state.userName.value : '',
245245
password:
246-
prometheusToggleEnabled && state.authType.value === AuthenticationType.BASIC
247-
? state.password.value
248-
: '',
249-
tlsClientKey: prometheusToggleEnabled ? state.prometheusTlsClientKey.value : '',
250-
tlsClientCert: prometheusToggleEnabled ? state.prometheusTlsClientCert.value : '',
246+
isPrometheusEnabled && state.authType.value === AuthenticationType.BASIC ? state.password.value : '',
247+
tlsClientKey: isPrometheusEnabled ? state.prometheusTlsClientKey.value : '',
248+
tlsClientCert: isPrometheusEnabled ? state.prometheusTlsClientCert.value : '',
251249
isAnonymous: state.authType.value === AuthenticationType.ANONYMOUS,
252250
},
253251
server_url: '',
254252
...(getCategoryPayload ? getCategoryPayload(selectedCategory) : null),
255253
...(clusterProvider ? { costModuleConfig: getCostModulePayload() } : null),
256254
})
257255

256+
const additionalValidations = (): boolean => {
257+
let hasError = false
258+
259+
if (costModuleState.enabled) {
260+
const costConfigError = validateCostModuleConfig()
261+
if (costConfigError) {
262+
setCostModuleErrorState(costConfigError)
263+
hasError = true
264+
}
265+
}
266+
267+
return hasError
268+
}
269+
258270
const onValidation = async (state) => {
259271
const payload = getClusterPayload(state)
260272
const urlValue = state.url.value?.trim() ?? ''
@@ -264,16 +276,15 @@ const ClusterForm = ({
264276
payload.server_url = urlValue
265277
}
266278

267-
if (costModuleState.enabled) {
268-
const costConfigError = validateCostModuleConfig()
269-
if (costConfigError) {
270-
setCostModuleErrorState(costConfigError)
271-
ToastManager.showToast({
272-
variant: ToastVariantType.error,
273-
description: 'Invalid cost visibility configuration',
274-
})
275-
return
276-
}
279+
const hasAdditionalError = additionalValidations()
280+
281+
if (hasAdditionalError) {
282+
ToastManager.showToast({
283+
variant: ToastVariantType.error,
284+
description: 'Some fields are invalid. Please correct them and try again.',
285+
})
286+
287+
return
277288
}
278289

279290
if (remoteConnectionMethod === RemoteConnectionType.Proxy) {
@@ -286,7 +297,9 @@ const ClusterForm = ({
286297
}
287298
}
288299

289-
if (state.authType.value === AuthenticationType.BASIC && prometheusToggleEnabled) {
300+
// Not adding this block in additionalValidations since there seems to be no state its error
301+
// They are both required in useForm so don't know why we have checked it here
302+
if (state.authType.value === AuthenticationType.BASIC && isPrometheusEnabled) {
290303
const isValid = state.userName?.value && state.password?.value
291304
if (!isValid) {
292305
ToastManager.showToast({
@@ -328,7 +341,7 @@ const ClusterForm = ({
328341
}
329342
}
330343

331-
const { state, handleOnChange, handleOnSubmit } = useForm(
344+
const { state, handleOnChange, handleOnSubmit, validateAllAndSetErrors } = useForm(
332345
{
333346
cluster_name: { value: clusterName, error: '' },
334347
url: { value: !id ? getServerURLFromLocalStorage(serverUrl) : serverUrl, error: '' },
@@ -368,11 +381,11 @@ const ClusterForm = ({
368381
validator: { error: 'Authentication Type is required', regex: /^(?!\s*$).+/ },
369382
},
370383
userName: {
371-
required: !!(prometheusToggleEnabled && prometheusAuthenticationType.type === AuthenticationType.BASIC),
384+
required: !!(isPrometheusEnabled && prometheusAuthenticationType.type === AuthenticationType.BASIC),
372385
validator: { error: 'username is required', regex: /^(?!\s*$).+/ },
373386
},
374387
password: {
375-
required: !!(prometheusToggleEnabled && prometheusAuthenticationType.type === AuthenticationType.BASIC),
388+
required: !!(isPrometheusEnabled && prometheusAuthenticationType.type === AuthenticationType.BASIC),
376389
validator: { error: 'password is required', regex: /^(?!\s*$).+/ },
377390
},
378391
prometheusTlsClientKey: {
@@ -438,15 +451,16 @@ const ClusterForm = ({
438451
validator: { error: 'token is required', regex: /[^]+/ },
439452
},
440453
endpoint: {
441-
required: !!prometheusToggleEnabled,
454+
required: !!isPrometheusEnabled,
442455
validator: { error: 'endpoint is required', regex: /^.*$/ },
443456
},
444457
},
445458
onValidation,
459+
'Please resolve all the errors before submitting.',
446460
)
447461

448-
const setPrometheusToggle = () => {
449-
setPrometheusToggleEnabled(!prometheusToggleEnabled)
462+
const toggleAppMetrics = () => {
463+
setIsAppMetricsEnabled((prev) => !prev)
450464
}
451465

452466
const onPrometheusAuthTypeChange = (e) => {
@@ -478,6 +492,16 @@ const ClusterForm = ({
478492
const hideConfirmationModal = () => setConfirmation(false)
479493

480494
const getTabSwitchHandler = (tab: ClusterConfigTabEnum) => () => {
495+
// This works since there is no required field in any other tab except Cluster config tab, which on creation is the default tab
496+
const hasError = validateAllAndSetErrors() || additionalValidations()
497+
if (hasError) {
498+
ToastManager.showToast({
499+
variant: ToastVariantType.error,
500+
description: 'Some fields are invalid. Please correct them and try again.',
501+
})
502+
return
503+
}
504+
481505
setClusterConfigTab(tab)
482506
}
483507

@@ -568,8 +592,8 @@ const ClusterForm = ({
568592
<ApplicationMonitoring
569593
prometheusConfig={prometheusConfig}
570594
prometheusUrl={prometheusUrl}
571-
prometheusToggleEnabled={prometheusToggleEnabled}
572-
setPrometheusToggle={setPrometheusToggle}
595+
isAppMetricsEnabled={isAppMetricsEnabled}
596+
toggleAppMetrics={toggleAppMetrics}
573597
handleOnChange={handleOnChange}
574598
onPrometheusAuthTypeChange={onPrometheusAuthTypeChange}
575599
isGrafanaModuleInstalled={isGrafanaModuleInstalled}
@@ -651,7 +675,7 @@ const ClusterForm = ({
651675
<ClusterFormNavButton
652676
isActive={clusterConfigTab === ClusterConfigTabEnum.APPLICATION_MONITORING}
653677
title="Application Monitoring"
654-
subtitle={prometheusToggleEnabled ? 'Enabled' : 'Off'}
678+
subtitle={isAppMetricsEnabled ? 'Enabled' : 'Off'}
655679
onClick={getTabSwitchHandler(ClusterConfigTabEnum.APPLICATION_MONITORING)}
656680
/>
657681
{ClusterCostConfig && id && (

src/Pages/GlobalConfigurations/ClustersAndEnvironments/ClusterForm/types.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ export interface KubeConfigEditorProps {
3535
export interface ApplicationMonitoringProps {
3636
prometheusConfig: PromoetheusConfig
3737
prometheusUrl: string
38-
prometheusToggleEnabled: boolean
39-
setPrometheusToggle: () => void
38+
isAppMetricsEnabled: boolean
39+
toggleAppMetrics: () => void
4040
handleOnChange: (event: SyntheticEvent) => void
4141
onPrometheusAuthTypeChange: (event: SyntheticEvent) => void
4242
isGrafanaModuleInstalled: boolean

src/components/common/helpers/Helpers.tsx

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,11 @@ import {
2626
ApiResourceGroupType,
2727
PluginDetailServiceParamsType,
2828
PipelineBuildStageType,
29-
SeverityCount,
3029
useMainContext,
3130
SelectPickerOptionType,
3231
InfoBlock,
33-
Badge,
34-
SeveritiesDTO,
32+
ToastManager,
33+
ToastVariantType,
3534
} from '@devtron-labs/devtron-fe-common-lib'
3635
import YAML from 'yaml'
3736
import { Link } from 'react-router-dom'
@@ -74,7 +73,7 @@ export function validateEmail(email) {
7473
/**
7574
* @deprecated use `useForm` from fe-common-lib.
7675
*/
77-
export function useForm(stateSchema, validationSchema = {}, callback) {
76+
export function useForm(stateSchema, validationSchema = {}, callback, errorMessageOnSubmit = null) {
7877
const [state, setState] = useState(stateSchema)
7978
const [disable, setDisable] = useState(true)
8079
const [isDirty, setIsDirty] = useState(false)
@@ -163,6 +162,16 @@ export function useForm(stateSchema, validationSchema = {}, callback) {
163162
[validationSchema],
164163
)
165164

165+
const validateAllAndSetErrors = (): boolean => {
166+
const newState = Object.keys(validationSchema).reduce((agg, curr) => {
167+
agg[curr] = { ...state[curr], error: validateField(curr, state[curr].value) }
168+
return agg
169+
}, state)
170+
171+
setState({ ...newState })
172+
return validateState(newState)
173+
}
174+
166175
const handleOnSubmit = (event) => {
167176
event.preventDefault()
168177
const newState = Object.keys(validationSchema).reduce((agg, curr) => {
@@ -172,10 +181,17 @@ export function useForm(stateSchema, validationSchema = {}, callback) {
172181
if (!validateState(newState)) {
173182
callback(state)
174183
} else {
184+
if (errorMessageOnSubmit) {
185+
ToastManager.showToast({
186+
variant: ToastVariantType.error,
187+
description: errorMessageOnSubmit,
188+
})
189+
}
190+
175191
setState({ ...newState })
176192
}
177193
}
178-
return { state, disable, handleOnChange, handleOnSubmit }
194+
return { state, disable, handleOnChange, handleOnSubmit, validateAllAndSetErrors }
179195
}
180196

181197
/**

0 commit comments

Comments
 (0)