Skip to content

Commit

Permalink
Added Nodes Agents component
Browse files Browse the repository at this point in the history
  • Loading branch information
doracretu3pillar committed Jul 29, 2024
1 parent a3ef553 commit a0353ac
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 75 deletions.
Original file line number Diff line number Diff line change
@@ -1,69 +1,25 @@
import React, { FC, useCallback, useEffect, useMemo, useState } from 'react';
import React, { FC, useMemo } from 'react';

import { useStyles2 } from '@grafana/ui';
import { GET_NODES_CANCEL_TOKEN } from "app/percona/inventory/Inventory.constants";
import { AgentsOptions, NodesOptions } from "app/percona/inventory/Inventory.types";
import { PasswordInputField } from 'app/percona/shared/components/Form/PasswordInput';
import { SelectField } from "app/percona/shared/components/Form/SelectFieldCore";
import { PasswordInputField } from 'app/percona/shared/components/Form/PasswordInput'
import { TextInputField } from 'app/percona/shared/components/Form/TextInput';
import { useCancelToken } from "app/percona/shared/components/hooks/cancelToken.hook";
import { fetchNodesOptionsAction } from "app/percona/shared/core/reducers/nodes/nodes";
import { isApiCancelError } from "app/percona/shared/helpers/api";
import { logger } from "app/percona/shared/helpers/logger";
import Validators from 'app/percona/shared/helpers/validators';
import { validators } from 'app/percona/shared/helpers/validatorsForm';
import { useAppDispatch } from "app/store/store";

import { Messages } from '../FormParts.messages';
import { getStyles } from '../FormParts.styles';
import { MainDetailsFormPartProps } from '../FormParts.types';
import { NodesAgents } from "../NodesAgents/NodesAgents";

export const MySQLConnectionDetails: FC<MainDetailsFormPartProps> = ({ form, remoteInstanceCredentials }) => {
const styles = useStyles2(getStyles);
const formValues = form && form.getState().values;
const tlsFlag = formValues && formValues['tls'];
const dispatch = useAppDispatch();
const [generateToken] = useCancelToken();
const [selectedNode, setSelectedNode] = useState<NodesOptions| undefined>(undefined);
const [selectedAgent, setSelectedAgent] = useState<AgentsOptions | undefined>(undefined);
const [nodes, setNodes] = useState<NodesOptions[]>([]);

const loadData = useCallback(async () => {
try {
setNodes(await dispatch(fetchNodesOptionsAction({ token: generateToken(GET_NODES_CANCEL_TOKEN) })).unwrap());
} catch (e) {
if (isApiCancelError(e)) {
return;
}
logger.error(e);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

useEffect(() => {
if(nodes.length === 0) {
loadData();
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [nodes]);

const portValidators = useMemo(() => [validators.required, Validators.validatePort], []);
const userPassValidators = useMemo(() => (tlsFlag ? [] : [validators.required]), [tlsFlag]);
const maxQueryLengthValidators = useMemo(() => [Validators.min(-1)], []);

const setNodeAndAgent = (value: NodesOptions) => {
setSelectedNode(value);
if (value.agents && value.agents.length > 1) {
form?.change('agent', value.agents[1]);
} else if (value.agents && value.agents.length === 1) {
form?.change('agent', value.agents[0]);
}

if(selectedAgent && selectedAgent.value !== "pmm-server") {
form?.change('address', 'localhost');
}
}

return (
<div className={styles.groupWrapper}>
<h4 className={styles.sectionHeader}>{Messages.form.titles.mainDetails}</h4>
Expand All @@ -77,34 +33,7 @@ export const MySQLConnectionDetails: FC<MainDetailsFormPartProps> = ({ form, rem
/>
<div />
</div>
<div className={styles.group}>
<div className={styles.selectFieldWrapper}>
<SelectField
label="Nodes"
isSearchable={false}
disabled={false}
options={nodes}
name="node"
data-testid="nodes-label"
onChange={ (event) => { setNodeAndAgent(event as NodesOptions) }}
className={styles.selectField}
value={selectedNode}
/>
</div>
<div className={styles.selectFieldWrapper}>
<SelectField
label="Agents"
isSearchable={false}
disabled={!selectedNode || !selectedNode.agents || selectedNode.agents.length === 1}
options={selectedNode?.agents || []}
name="agent"
data-testid="nodes-label"
onChange={ (event) => { setSelectedAgent(event as AgentsOptions); }}
className={styles.selectField}
/>
</div>
</div>

<NodesAgents form={form} />
<div className={styles.group}>
<TextInputField
name="address"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { FormApi } from "final-form";
import React, { FC, useCallback, useEffect, useState } from "react";

import { useStyles2 } from '@grafana/ui';
import { getStyles } from "app/percona/add-instance/components/AddRemoteInstance/FormParts/FormParts.styles";
import { GET_NODES_CANCEL_TOKEN } from "app/percona/inventory/Inventory.constants";
import { AgentsOptions, NodesOptions } from "app/percona/inventory/Inventory.types";
import { SelectField } from "app/percona/shared/components/Form/SelectFieldCore";
import { useCancelToken } from "app/percona/shared/components/hooks/cancelToken.hook";
import { fetchNodesOptionsAction } from "app/percona/shared/core/reducers/nodes/nodes";
import { isApiCancelError } from "app/percona/shared/helpers/api";
import { logger } from "app/percona/shared/helpers/logger";
import { useAppDispatch } from "app/store/store";

export interface NodesAgentsProps {
form?: FormApi;
}

export const NodesAgents: FC<NodesAgentsProps> = ({ form }) => {
const styles = useStyles2(getStyles);
const dispatch = useAppDispatch();
const [generateToken] = useCancelToken();
const [selectedNode, setSelectedNode] = useState<NodesOptions| undefined>(undefined);
const [selectedAgent, setSelectedAgent] = useState<AgentsOptions | undefined>(undefined);
const [nodes, setNodes] = useState<NodesOptions[]>([]);

const loadData = useCallback(async () => {
try {
setNodes(await dispatch(fetchNodesOptionsAction({ token: generateToken(GET_NODES_CANCEL_TOKEN) })).unwrap());
} catch (e) {
if (isApiCancelError(e)) {
return;
}
logger.error(e);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

const setNodeAndAgent = (value: NodesOptions) => {
setSelectedNode(value);
if (value.agents && value.agents.length > 1) {
form?.change('agent', value.agents[1]);
} else if (value.agents && value.agents.length === 1) {
form?.change('agent', value.agents[0]);
}

if(selectedAgent && selectedAgent.value !== "pmm-server") {
form?.change('address', 'localhost');
}
}

useEffect(() => {
if(nodes.length === 0) {
loadData();
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [nodes]);

return (
<div className={styles.group}>
<div className={styles.selectFieldWrapper}>
<SelectField
label="Nodes"
isSearchable={false}
disabled={false}
options={nodes}
name="node"
data-testid="nodes-label"
onChange={ (event) => { setNodeAndAgent(event as NodesOptions) }}
className={styles.selectField}
value={selectedNode}
/>
</div>
<div className={styles.selectFieldWrapper}>
<SelectField
label="Agents"
isSearchable={false}
disabled={!selectedNode || !selectedNode.agents || selectedNode.agents.length === 1}
options={selectedNode?.agents || []}
name="agent"
data-testid="nodes-label"
onChange={ (event) => { setSelectedAgent(event as AgentsOptions); }}
className={styles.selectField}
/>
</div>
</div>
);

}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { validators } from 'app/percona/shared/helpers/validatorsForm';
import { Messages } from '../FormParts.messages';
import { getStyles } from '../FormParts.styles';
import { MainDetailsFormPartProps } from '../FormParts.types';
import { NodesAgents } from "../NodesAgents/NodesAgents";

export const PostgreSQLConnectionDetails: FC<MainDetailsFormPartProps> = ({ form, remoteInstanceCredentials }) => {
const styles = useStyles2(getStyles);
Expand All @@ -31,6 +32,7 @@ export const PostgreSQLConnectionDetails: FC<MainDetailsFormPartProps> = ({ form
/>
<div />
</div>
<NodesAgents form={form} />
<div className={styles.group}>
<TextInputField
name="address"
Expand Down

0 comments on commit a0353ac

Please sign in to comment.