[Fixed issue/1587] Got rid of react-hooks/exhaustive-deps errors (#1616)
* got rid of react-hooks/exhaustive-deps errors - part 1 * got rid of react-hooks/exhaustive-deps errors in useSearch * got rid of react-hooks/exhaustive-deps errors in Filters * got rid of react-hooks/exhaustive-deps errors in ResetOffsets * got rid of react-hooks/exhaustive-deps errors in Filters * got rid of react-hooks/exhaustive-deps errors in Breadcrumbs * got rid of react-hooks/exhaustive-deps errors in DynamicTextButton * got rid of react-hooks/exhaustive-deps errors in useDataSaver * got rid of react-hooks/exhaustive-deps errors in ResultRenderer Co-authored-by: Roman Zabaluev <rzabaluev@provectus.com>
This commit is contained in:
parent
3f0693bad6
commit
94b1f4a772
39 changed files with 166 additions and 124 deletions
|
@ -22,7 +22,8 @@
|
||||||
},
|
},
|
||||||
"plugins": [
|
"plugins": [
|
||||||
"@typescript-eslint",
|
"@typescript-eslint",
|
||||||
"prettier"
|
"prettier",
|
||||||
|
"eslint-plugin-react-hooks"
|
||||||
],
|
],
|
||||||
"extends": [
|
"extends": [
|
||||||
"airbnb",
|
"airbnb",
|
||||||
|
@ -33,6 +34,8 @@
|
||||||
"prettier"
|
"prettier"
|
||||||
],
|
],
|
||||||
"rules": {
|
"rules": {
|
||||||
|
"react-hooks/rules-of-hooks": "error",
|
||||||
|
"react-hooks/exhaustive-deps": "warn",
|
||||||
"react/no-unused-prop-types": "off",
|
"react/no-unused-prop-types": "off",
|
||||||
"react/require-default-props": "off",
|
"react/require-default-props": "off",
|
||||||
"prettier/prettier": "warn",
|
"prettier/prettier": "warn",
|
||||||
|
|
|
@ -8,14 +8,20 @@ import Alert from 'components/Alerts/Alert';
|
||||||
const Alerts: React.FC = () => {
|
const Alerts: React.FC = () => {
|
||||||
const alerts = useAppSelector(selectAll);
|
const alerts = useAppSelector(selectAll);
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const dismiss = React.useCallback((id: string) => {
|
const dismiss = React.useCallback(
|
||||||
dispatch(alertDissmissed(id));
|
(id: string) => {
|
||||||
}, []);
|
dispatch(alertDissmissed(id));
|
||||||
|
},
|
||||||
|
[dispatch]
|
||||||
|
);
|
||||||
|
|
||||||
const legacyAlerts = useAppSelector(getAlerts);
|
const legacyAlerts = useAppSelector(getAlerts);
|
||||||
const dismissLegacy = React.useCallback((id: string) => {
|
const dismissLegacy = React.useCallback(
|
||||||
dispatch(dismissAlert(id));
|
(id: string) => {
|
||||||
}, []);
|
dispatch(dismissAlert(id));
|
||||||
|
},
|
||||||
|
[dispatch]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
|
@ -36,11 +36,11 @@ const App: React.FC = () => {
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
closeSidebar();
|
closeSidebar();
|
||||||
}, [location]);
|
}, [closeSidebar, location]);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
dispatch(fetchClusters());
|
dispatch(fetchClusters());
|
||||||
}, [fetchClusters]);
|
}, [dispatch]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ThemeProvider theme={theme}>
|
<ThemeProvider theme={theme}>
|
||||||
|
|
|
@ -35,7 +35,7 @@ const Brokers: React.FC = () => {
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
dispatch(fetchClusterStats(clusterName));
|
dispatch(fetchClusterStats(clusterName));
|
||||||
}, [fetchClusterStats, clusterName]);
|
}, [clusterName, dispatch]);
|
||||||
|
|
||||||
useInterval(() => {
|
useInterval(() => {
|
||||||
fetchClusterStats(clusterName);
|
fetchClusterStats(clusterName);
|
||||||
|
|
|
@ -49,7 +49,12 @@ const Cluster: React.FC = () => {
|
||||||
hasSchemaRegistryConfigured,
|
hasSchemaRegistryConfigured,
|
||||||
isTopicDeletionAllowed,
|
isTopicDeletionAllowed,
|
||||||
}),
|
}),
|
||||||
[features]
|
[
|
||||||
|
hasKafkaConnectConfigured,
|
||||||
|
hasSchemaRegistryConfigured,
|
||||||
|
isReadOnly,
|
||||||
|
isTopicDeletionAllowed,
|
||||||
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -70,7 +70,7 @@ const Actions: React.FC<ActionsProps> = ({
|
||||||
} catch {
|
} catch {
|
||||||
// do not redirect
|
// do not redirect
|
||||||
}
|
}
|
||||||
}, [deleteConnector, clusterName, connectName, connectorName]);
|
}, [deleteConnector, clusterName, connectName, connectorName, history]);
|
||||||
|
|
||||||
const restartConnectorHandler = React.useCallback(() => {
|
const restartConnectorHandler = React.useCallback(() => {
|
||||||
restartConnector(clusterName, connectName, connectorName);
|
restartConnector(clusterName, connectName, connectorName);
|
||||||
|
|
|
@ -100,7 +100,7 @@ const Edit: React.FC<EditProps> = ({
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[updateConfig, clusterName, connectName, connectorName]
|
[updateConfig, clusterName, connectName, connectorName, history]
|
||||||
);
|
);
|
||||||
|
|
||||||
if (isConfigFetching) return <PageLoader />;
|
if (isConfigFetching) return <PageLoader />;
|
||||||
|
|
|
@ -45,7 +45,7 @@ const ListItem: React.FC<ListItemProps> = ({
|
||||||
dispatch(deleteConnector(clusterName, connect, name));
|
dispatch(deleteConnector(clusterName, connect, name));
|
||||||
}
|
}
|
||||||
setDeleteConnectorConfirmationVisible(false);
|
setDeleteConnectorConfirmationVisible(false);
|
||||||
}, [clusterName, connect, name]);
|
}, [clusterName, connect, dispatch, name]);
|
||||||
|
|
||||||
const runningTasks = React.useMemo(() => {
|
const runningTasks = React.useMemo(() => {
|
||||||
if (!tasksCount) return null;
|
if (!tasksCount) return null;
|
||||||
|
|
|
@ -101,7 +101,7 @@ const New: React.FC<NewProps> = ({
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[createConnector, clusterName]
|
[createConnector, clusterName, history]
|
||||||
);
|
);
|
||||||
|
|
||||||
if (areConnectsFetching) {
|
if (areConnectsFetching) {
|
||||||
|
|
|
@ -18,7 +18,7 @@ const ConsumerGroups: React.FC = () => {
|
||||||
const isFetched = useAppSelector(getAreConsumerGroupsFulfilled);
|
const isFetched = useAppSelector(getAreConsumerGroupsFulfilled);
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
dispatch(fetchConsumerGroups(clusterName));
|
dispatch(fetchConsumerGroups(clusterName));
|
||||||
}, [fetchConsumerGroups, clusterName]);
|
}, [clusterName, dispatch]);
|
||||||
|
|
||||||
if (isFetched) {
|
if (isFetched) {
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -47,7 +47,7 @@ const Details: React.FC = () => {
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
dispatch(fetchConsumerGroupDetails({ clusterName, consumerGroupID }));
|
dispatch(fetchConsumerGroupDetails({ clusterName, consumerGroupID }));
|
||||||
}, [fetchConsumerGroupDetails, clusterName, consumerGroupID]);
|
}, [clusterName, consumerGroupID, dispatch]);
|
||||||
|
|
||||||
const onDelete = () => {
|
const onDelete = () => {
|
||||||
setIsConfirmationModalVisible(false);
|
setIsConfirmationModalVisible(false);
|
||||||
|
@ -57,7 +57,7 @@ const Details: React.FC = () => {
|
||||||
if (isDeleted) {
|
if (isDeleted) {
|
||||||
history.push(clusterConsumerGroupsPath(clusterName));
|
history.push(clusterConsumerGroupsPath(clusterName));
|
||||||
}
|
}
|
||||||
}, [isDeleted]);
|
}, [clusterName, history, isDeleted]);
|
||||||
|
|
||||||
const onResetOffsets = () => {
|
const onResetOffsets = () => {
|
||||||
history.push(
|
history.push(
|
||||||
|
|
|
@ -59,7 +59,7 @@ const ResetOffsets: React.FC = () => {
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
dispatch(fetchConsumerGroupDetails({ clusterName, consumerGroupID }));
|
dispatch(fetchConsumerGroupDetails({ clusterName, consumerGroupID }));
|
||||||
}, [clusterName, consumerGroupID]);
|
}, [clusterName, consumerGroupID, dispatch]);
|
||||||
|
|
||||||
const [uniqueTopics, setUniqueTopics] = React.useState<string[]>([]);
|
const [uniqueTopics, setUniqueTopics] = React.useState<string[]>([]);
|
||||||
const [selectedPartitions, setSelectedPartitions] = React.useState<Option[]>(
|
const [selectedPartitions, setSelectedPartitions] = React.useState<Option[]>(
|
||||||
|
@ -96,7 +96,7 @@ const ResetOffsets: React.FC = () => {
|
||||||
setValue('topic', consumerGroup.partitions[0].topic);
|
setValue('topic', consumerGroup.partitions[0].topic);
|
||||||
setUniqueTopics(Object.keys(groupBy(consumerGroup.partitions, 'topic')));
|
setUniqueTopics(Object.keys(groupBy(consumerGroup.partitions, 'topic')));
|
||||||
}
|
}
|
||||||
}, [isFetched]);
|
}, [consumerGroup?.partitions, isFetched, setValue]);
|
||||||
|
|
||||||
const onSelectedPartitionsChange = (value: Option[]) => {
|
const onSelectedPartitionsChange = (value: Option[]) => {
|
||||||
clearErrors();
|
clearErrors();
|
||||||
|
@ -117,6 +117,7 @@ const ResetOffsets: React.FC = () => {
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
onSelectedPartitionsChange([]);
|
onSelectedPartitionsChange([]);
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [topicValue]);
|
}, [topicValue]);
|
||||||
|
|
||||||
const onSubmit = (data: FormType) => {
|
const onSubmit = (data: FormType) => {
|
||||||
|
@ -169,7 +170,7 @@ const ResetOffsets: React.FC = () => {
|
||||||
clusterConsumerGroupDetailsPath(clusterName, consumerGroupID)
|
clusterConsumerGroupDetailsPath(clusterName, consumerGroupID)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}, [isOffsetReseted]);
|
}, [clusterName, consumerGroupID, dispatch, history, isOffsetReseted]);
|
||||||
|
|
||||||
if (!isFetched || !consumerGroup) {
|
if (!isFetched || !consumerGroup) {
|
||||||
return <PageLoader />;
|
return <PageLoader />;
|
||||||
|
|
|
@ -32,7 +32,7 @@ const List: FC = () => {
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
dispatch(fetchKsqlDbTables(clusterName));
|
dispatch(fetchKsqlDbTables(clusterName));
|
||||||
}, []);
|
}, [clusterName, dispatch]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
|
@ -42,7 +42,7 @@ const Query: FC = () => {
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
return reset;
|
return reset;
|
||||||
}, []);
|
}, [reset]);
|
||||||
|
|
||||||
const { handleSubmit, setValue, control } = useForm<FormValues>({
|
const { handleSubmit, setValue, control } = useForm<FormValues>({
|
||||||
mode: 'onTouched',
|
mode: 'onTouched',
|
||||||
|
@ -53,19 +53,22 @@ const Query: FC = () => {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const submitHandler = useCallback(async (values: FormValues) => {
|
const submitHandler = useCallback(
|
||||||
dispatch(
|
async (values: FormValues) => {
|
||||||
executeKsql({
|
dispatch(
|
||||||
clusterName,
|
executeKsql({
|
||||||
ksqlCommand: {
|
clusterName,
|
||||||
...values,
|
ksqlCommand: {
|
||||||
streamsProperties: values.streamsProperties
|
...values,
|
||||||
? JSON.parse(values.streamsProperties)
|
streamsProperties: values.streamsProperties
|
||||||
: undefined,
|
? JSON.parse(values.streamsProperties)
|
||||||
},
|
: undefined,
|
||||||
})
|
},
|
||||||
);
|
})
|
||||||
}, []);
|
);
|
||||||
|
},
|
||||||
|
[clusterName, dispatch]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
|
@ -20,6 +20,7 @@ const ResultRenderer: React.FC<{ result: KsqlCommandResponse | null }> = ({
|
||||||
|
|
||||||
const { headers, rows } = rawTable;
|
const { headers, rows } = rawTable;
|
||||||
|
|
||||||
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||||
const transformedRows = React.useMemo(
|
const transformedRows = React.useMemo(
|
||||||
() =>
|
() =>
|
||||||
rows.map((row) =>
|
rows.map((row) =>
|
||||||
|
@ -31,7 +32,7 @@ const ResultRenderer: React.FC<{ result: KsqlCommandResponse | null }> = ({
|
||||||
{} as Dictionary<string>
|
{} as Dictionary<string>
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
[]
|
[rawTable.headers, rows]
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -47,14 +47,14 @@ const Details: React.FC = () => {
|
||||||
return () => {
|
return () => {
|
||||||
dispatch(resetLoaderById(SCHEMA_LATEST_FETCH_ACTION));
|
dispatch(resetLoaderById(SCHEMA_LATEST_FETCH_ACTION));
|
||||||
};
|
};
|
||||||
}, []);
|
}, [clusterName, dispatch, subject]);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
dispatch(fetchSchemaVersions({ clusterName, subject }));
|
dispatch(fetchSchemaVersions({ clusterName, subject }));
|
||||||
return () => {
|
return () => {
|
||||||
dispatch(resetLoaderById(SCHEMAS_VERSIONS_FETCH_ACTION));
|
dispatch(resetLoaderById(SCHEMAS_VERSIONS_FETCH_ACTION));
|
||||||
};
|
};
|
||||||
}, [clusterName, subject]);
|
}, [clusterName, dispatch, subject]);
|
||||||
|
|
||||||
const versions = useAppSelector((state) => selectAllSchemaVersions(state));
|
const versions = useAppSelector((state) => selectAllSchemaVersions(state));
|
||||||
const schema = useAppSelector(getSchemaLatest);
|
const schema = useAppSelector(getSchemaLatest);
|
||||||
|
@ -72,7 +72,7 @@ const Details: React.FC = () => {
|
||||||
const err = await getResponse(e as Response);
|
const err = await getResponse(e as Response);
|
||||||
dispatch(serverErrorAlertAdded(err));
|
dispatch(serverErrorAlertAdded(err));
|
||||||
}
|
}
|
||||||
}, [clusterName, subject]);
|
}, [clusterName, dispatch, history, subject]);
|
||||||
|
|
||||||
if (!isFetched || !schema) {
|
if (!isFetched || !schema) {
|
||||||
return <PageLoader />;
|
return <PageLoader />;
|
||||||
|
|
|
@ -47,7 +47,7 @@ const Edit: React.FC = () => {
|
||||||
return () => {
|
return () => {
|
||||||
dispatch(resetLoaderById(SCHEMA_LATEST_FETCH_ACTION));
|
dispatch(resetLoaderById(SCHEMA_LATEST_FETCH_ACTION));
|
||||||
};
|
};
|
||||||
}, [clusterName, subject]);
|
}, [clusterName, dispatch, subject]);
|
||||||
|
|
||||||
const schema = useAppSelector((state) => getSchemaLatest(state));
|
const schema = useAppSelector((state) => getSchemaLatest(state));
|
||||||
const isFetched = useAppSelector(getAreSchemaLatestFulfilled);
|
const isFetched = useAppSelector(getAreSchemaLatestFulfilled);
|
||||||
|
@ -58,44 +58,56 @@ const Edit: React.FC = () => {
|
||||||
: JSON.stringify(JSON.parse(schema?.schema || '{}'), null, '\t');
|
: JSON.stringify(JSON.parse(schema?.schema || '{}'), null, '\t');
|
||||||
}, [schema]);
|
}, [schema]);
|
||||||
|
|
||||||
const onSubmit = React.useCallback(async (props: NewSchemaSubjectRaw) => {
|
const onSubmit = React.useCallback(
|
||||||
if (!schema) return;
|
async (props: NewSchemaSubjectRaw) => {
|
||||||
|
if (!schema) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (dirtyFields.newSchema || dirtyFields.schemaType) {
|
if (dirtyFields.newSchema || dirtyFields.schemaType) {
|
||||||
const resp = await schemasApiClient.createNewSchema({
|
const resp = await schemasApiClient.createNewSchema({
|
||||||
clusterName,
|
clusterName,
|
||||||
newSchemaSubject: {
|
newSchemaSubject: {
|
||||||
...schema,
|
...schema,
|
||||||
schema: props.newSchema || schema.schema,
|
schema: props.newSchema || schema.schema,
|
||||||
schemaType: props.schemaType || schema.schemaType,
|
schemaType: props.schemaType || schema.schemaType,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
dispatch(schemaAdded(resp));
|
dispatch(schemaAdded(resp));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dirtyFields.compatibilityLevel) {
|
||||||
|
await schemasApiClient.updateSchemaCompatibilityLevel({
|
||||||
|
clusterName,
|
||||||
|
subject,
|
||||||
|
compatibilityLevel: {
|
||||||
|
compatibility: props.compatibilityLevel,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
dispatch(
|
||||||
|
schemaUpdated({
|
||||||
|
...schema,
|
||||||
|
compatibilityLevel: props.compatibilityLevel,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
history.push(clusterSchemaPath(clusterName, subject));
|
||||||
|
} catch (e) {
|
||||||
|
const err = await getResponse(e as Response);
|
||||||
|
dispatch(serverErrorAlertAdded(err));
|
||||||
}
|
}
|
||||||
|
},
|
||||||
if (dirtyFields.compatibilityLevel) {
|
[
|
||||||
await schemasApiClient.updateSchemaCompatibilityLevel({
|
clusterName,
|
||||||
clusterName,
|
dirtyFields.compatibilityLevel,
|
||||||
subject,
|
dirtyFields.newSchema,
|
||||||
compatibilityLevel: {
|
dirtyFields.schemaType,
|
||||||
compatibility: props.compatibilityLevel,
|
dispatch,
|
||||||
},
|
history,
|
||||||
});
|
schema,
|
||||||
dispatch(
|
subject,
|
||||||
schemaUpdated({
|
]
|
||||||
...schema,
|
);
|
||||||
compatibilityLevel: props.compatibilityLevel,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
history.push(clusterSchemaPath(clusterName, subject));
|
|
||||||
} catch (e) {
|
|
||||||
const err = await getResponse(e as Response);
|
|
||||||
dispatch(serverErrorAlertAdded(err));
|
|
||||||
}
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
if (!isFetched || !schema) {
|
if (!isFetched || !schema) {
|
||||||
return <PageLoader />;
|
return <PageLoader />;
|
||||||
|
|
|
@ -48,7 +48,7 @@ const GlobalSchemaSelector: React.FC = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
fetchData();
|
fetchData();
|
||||||
}, []);
|
}, [clusterName]);
|
||||||
|
|
||||||
const handleChangeCompatibilityLevel = (level: string | number) => {
|
const handleChangeCompatibilityLevel = (level: string | number) => {
|
||||||
setNextCompatibilityLevel(level as CompatibilityLevelCompatibilityEnum);
|
setNextCompatibilityLevel(level as CompatibilityLevelCompatibilityEnum);
|
||||||
|
|
|
@ -41,7 +41,7 @@ const List: React.FC = () => {
|
||||||
return () => {
|
return () => {
|
||||||
dispatch(resetLoaderById(SCHEMAS_FETCH_ACTION));
|
dispatch(resetLoaderById(SCHEMAS_FETCH_ACTION));
|
||||||
};
|
};
|
||||||
}, [clusterName, page, perPage, searchText]);
|
}, [clusterName, dispatch, page, perPage, searchText]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
|
@ -55,7 +55,7 @@ const New: React.FC = () => {
|
||||||
dispatch(serverErrorAlertAdded(err));
|
dispatch(serverErrorAlertAdded(err));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[clusterName]
|
[clusterName, dispatch, history]
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -93,7 +93,7 @@ const List: React.FC<TopicsListProps> = ({
|
||||||
const handleSwitch = React.useCallback(() => {
|
const handleSwitch = React.useCallback(() => {
|
||||||
setShowInternal(!showInternal);
|
setShowInternal(!showInternal);
|
||||||
history.push(`${pathname}?page=1&perPage=${perPage || PER_PAGE}`);
|
history.push(`${pathname}?page=1&perPage=${perPage || PER_PAGE}`);
|
||||||
}, [showInternal]);
|
}, [history, pathname, perPage, showInternal]);
|
||||||
|
|
||||||
const [confirmationModal, setConfirmationModal] = React.useState<
|
const [confirmationModal, setConfirmationModal] = React.useState<
|
||||||
'' | 'deleteTopics' | 'purgeMessages'
|
'' | 'deleteTopics' | 'purgeMessages'
|
||||||
|
@ -127,18 +127,18 @@ const List: React.FC<TopicsListProps> = ({
|
||||||
deleteTopics(clusterName, Array.from(selectedTopics));
|
deleteTopics(clusterName, Array.from(selectedTopics));
|
||||||
closeConfirmationModal();
|
closeConfirmationModal();
|
||||||
clearSelectedTopics();
|
clearSelectedTopics();
|
||||||
}, [clusterName, selectedTopics]);
|
}, [clusterName, deleteTopics, selectedTopics]);
|
||||||
const purgeMessagesHandler = React.useCallback(() => {
|
const purgeMessagesHandler = React.useCallback(() => {
|
||||||
clearTopicsMessages(clusterName, Array.from(selectedTopics));
|
clearTopicsMessages(clusterName, Array.from(selectedTopics));
|
||||||
closeConfirmationModal();
|
closeConfirmationModal();
|
||||||
clearSelectedTopics();
|
clearSelectedTopics();
|
||||||
}, [clusterName, selectedTopics]);
|
}, [clearTopicsMessages, clusterName, selectedTopics]);
|
||||||
const searchHandler = React.useCallback(
|
const searchHandler = React.useCallback(
|
||||||
(searchString: string) => {
|
(searchString: string) => {
|
||||||
setTopicsSearch(searchString);
|
setTopicsSearch(searchString);
|
||||||
history.push(`${pathname}?page=1&perPage=${perPage || PER_PAGE}`);
|
history.push(`${pathname}?page=1&perPage=${perPage || PER_PAGE}`);
|
||||||
},
|
},
|
||||||
[search, pathname, perPage]
|
[setTopicsSearch, history, pathname, perPage]
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -70,11 +70,11 @@ const ListItem: React.FC<ListItemProps> = ({
|
||||||
|
|
||||||
const deleteTopicHandler = React.useCallback(() => {
|
const deleteTopicHandler = React.useCallback(() => {
|
||||||
deleteTopic(clusterName, name);
|
deleteTopic(clusterName, name);
|
||||||
}, [clusterName, name]);
|
}, [clusterName, deleteTopic, name]);
|
||||||
|
|
||||||
const clearTopicMessagesHandler = React.useCallback(() => {
|
const clearTopicMessagesHandler = React.useCallback(() => {
|
||||||
clearTopicMessages(clusterName, name);
|
clearTopicMessages(clusterName, name);
|
||||||
}, [clusterName, name]);
|
}, [clearTopicMessages, clusterName, name]);
|
||||||
const [vElipsisVisble, setVElipsisVisble] = React.useState(false);
|
const [vElipsisVisble, setVElipsisVisble] = React.useState(false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -27,7 +27,7 @@ const TopicConsumerGroups: React.FC<Props> = ({
|
||||||
}) => {
|
}) => {
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
fetchTopicConsumerGroups(clusterName, topicName);
|
fetchTopicConsumerGroups(clusterName, topicName);
|
||||||
}, []);
|
}, [clusterName, fetchTopicConsumerGroups, topicName]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
|
|
|
@ -64,19 +64,19 @@ const Details: React.FC<Props> = ({
|
||||||
React.useState(false);
|
React.useState(false);
|
||||||
const deleteTopicHandler = React.useCallback(() => {
|
const deleteTopicHandler = React.useCallback(() => {
|
||||||
deleteTopic(clusterName, topicName);
|
deleteTopic(clusterName, topicName);
|
||||||
}, [clusterName, topicName]);
|
}, [clusterName, deleteTopic, topicName]);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (isDeleted) {
|
if (isDeleted) {
|
||||||
dispatch(deleteTopicAction.cancel());
|
dispatch(deleteTopicAction.cancel());
|
||||||
history.push(clusterTopicsPath(clusterName));
|
history.push(clusterTopicsPath(clusterName));
|
||||||
}
|
}
|
||||||
}, [isDeleted]);
|
}, [clusterName, dispatch, history, isDeleted]);
|
||||||
|
|
||||||
const clearTopicMessagesHandler = React.useCallback(() => {
|
const clearTopicMessagesHandler = React.useCallback(() => {
|
||||||
clearTopicMessages(clusterName, topicName);
|
clearTopicMessages(clusterName, topicName);
|
||||||
setClearTopicConfirmationVisible(false);
|
setClearTopicConfirmationVisible(false);
|
||||||
}, [clusterName, topicName]);
|
}, [clearTopicMessages, clusterName, topicName]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
|
|
|
@ -126,7 +126,7 @@ const Filters: React.FC<FiltersProps> = ({
|
||||||
[partitions]
|
[partitions]
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleFiltersSubmit = () => {
|
const handleFiltersSubmit = React.useCallback(() => {
|
||||||
setAttempt(attempt + 1);
|
setAttempt(attempt + 1);
|
||||||
|
|
||||||
const props: Query = {
|
const props: Query = {
|
||||||
|
@ -166,7 +166,8 @@ const Filters: React.FC<FiltersProps> = ({
|
||||||
history.push({
|
history.push({
|
||||||
search: `?${qs}`,
|
search: `?${qs}`,
|
||||||
});
|
});
|
||||||
};
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, []);
|
||||||
|
|
||||||
const toggleSeekDirection = (val: string) => {
|
const toggleSeekDirection = (val: string) => {
|
||||||
const nextSeekDirectionValue =
|
const nextSeekDirectionValue =
|
||||||
|
@ -224,17 +225,26 @@ const Filters: React.FC<FiltersProps> = ({
|
||||||
sse.close();
|
sse.close();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}, [clusterName, topicName, location]);
|
}, [
|
||||||
|
clusterName,
|
||||||
|
topicName,
|
||||||
|
location,
|
||||||
|
setIsFetching,
|
||||||
|
resetMessages,
|
||||||
|
addMessage,
|
||||||
|
updatePhase,
|
||||||
|
updateMeta,
|
||||||
|
]);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (location.search.length === 0) {
|
if (location.search.length === 0) {
|
||||||
handleFiltersSubmit();
|
handleFiltersSubmit();
|
||||||
}
|
}
|
||||||
}, [location]);
|
}, [handleFiltersSubmit, location]);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
handleFiltersSubmit();
|
handleFiltersSubmit();
|
||||||
}, [seekDirection]);
|
}, [handleFiltersSubmit, seekDirection]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<S.FiltersWrapper>
|
<S.FiltersWrapper>
|
||||||
|
|
|
@ -27,7 +27,7 @@ const MessagesTable: React.FC = () => {
|
||||||
|
|
||||||
const searchParams = React.useMemo(
|
const searchParams = React.useMemo(
|
||||||
() => new URLSearchParams(location.search),
|
() => new URLSearchParams(location.search),
|
||||||
[location, history]
|
[location]
|
||||||
);
|
);
|
||||||
|
|
||||||
const messages = useSelector(getTopicMessges);
|
const messages = useSelector(getTopicMessges);
|
||||||
|
|
|
@ -88,10 +88,7 @@ const Edit: React.FC<Props> = ({
|
||||||
fetchTopicConfig,
|
fetchTopicConfig,
|
||||||
updateTopic,
|
updateTopic,
|
||||||
}) => {
|
}) => {
|
||||||
const defaultValues = React.useMemo(
|
const defaultValues = React.useMemo(() => topicParams(topic), [topic]);
|
||||||
() => topicParams(topic),
|
|
||||||
[topicParams, topic]
|
|
||||||
);
|
|
||||||
const methods = useForm<TopicFormData>({
|
const methods = useForm<TopicFormData>({
|
||||||
defaultValues,
|
defaultValues,
|
||||||
resolver: yupResolver(topicFormValidationSchema),
|
resolver: yupResolver(topicFormValidationSchema),
|
||||||
|
@ -109,7 +106,7 @@ const Edit: React.FC<Props> = ({
|
||||||
const { name } = methods.getValues();
|
const { name } = methods.getValues();
|
||||||
history.push(clusterTopicPath(clusterName, name));
|
history.push(clusterTopicPath(clusterName, name));
|
||||||
}
|
}
|
||||||
}, [isSubmitting, isTopicUpdated, clusterTopicPath, clusterName, methods]);
|
}, [isSubmitting, isTopicUpdated, clusterName, methods, history]);
|
||||||
|
|
||||||
if (!isFetched || !topic || !topic.config) {
|
if (!isFetched || !topic || !topic.config) {
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -41,7 +41,7 @@ const SendMessage: React.FC = () => {
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
dispatch(fetchTopicMessageSchema(clusterName, topicName));
|
dispatch(fetchTopicMessageSchema(clusterName, topicName));
|
||||||
}, []);
|
}, [clusterName, dispatch, topicName]);
|
||||||
|
|
||||||
const messageSchema = useAppSelector((state) =>
|
const messageSchema = useAppSelector((state) =>
|
||||||
getMessageSchemaByTopicName(state, topicName)
|
getMessageSchemaByTopicName(state, topicName)
|
||||||
|
|
|
@ -54,7 +54,7 @@ const CustomParamField: React.FC<Props> = ({
|
||||||
shouldValidate: true,
|
shouldValidate: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [nameValue]);
|
}, [existingFields, index, nameValue, setExistingFields, setValue]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<C.Column>
|
<C.Column>
|
||||||
|
|
|
@ -15,6 +15,7 @@ const BreadcrumbRouteInternal: React.FC = () => {
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
context.handleRouteChange({ ...match, url: location.pathname });
|
context.handleRouteChange({ ...match, url: location.pathname });
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [location.pathname]);
|
}, [location.pathname]);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -13,7 +13,7 @@ const Breadcrumb: React.FC = () => {
|
||||||
|
|
||||||
const links = React.useMemo(
|
const links = React.useMemo(
|
||||||
() => breadcrumbContext.path.slice(basePathEntriesLength),
|
() => breadcrumbContext.path.slice(basePathEntriesLength),
|
||||||
[breadcrumbContext.link]
|
[breadcrumbContext.path]
|
||||||
);
|
);
|
||||||
|
|
||||||
const getPathPredicate = React.useCallback(
|
const getPathPredicate = React.useCallback(
|
||||||
|
|
|
@ -21,7 +21,7 @@ const BytesFormatted: React.FC<Props> = ({ value, precision = 0 }) => {
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return `-Bytes`;
|
return `-Bytes`;
|
||||||
}
|
}
|
||||||
}, [value]);
|
}, [precision, value]);
|
||||||
|
|
||||||
return <span>{formatedValue}</span>;
|
return <span>{formatedValue}</span>;
|
||||||
};
|
};
|
||||||
|
|
|
@ -19,14 +19,14 @@ const ConfirmationModal: React.FC<ConfirmationModalProps> = ({
|
||||||
onConfirm,
|
onConfirm,
|
||||||
isConfirming = false,
|
isConfirming = false,
|
||||||
}) => {
|
}) => {
|
||||||
if (!isOpen) return null;
|
|
||||||
|
|
||||||
const cancelHandler = React.useCallback(() => {
|
const cancelHandler = React.useCallback(() => {
|
||||||
if (!isConfirming) {
|
if (!isConfirming) {
|
||||||
onCancel();
|
onCancel();
|
||||||
}
|
}
|
||||||
}, [isConfirming, onCancel]);
|
}, [isConfirming, onCancel]);
|
||||||
|
|
||||||
|
if (!isOpen) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ConfirmationModalWrapper>
|
<ConfirmationModalWrapper>
|
||||||
<div onClick={cancelHandler} aria-hidden="true" />
|
<div onClick={cancelHandler} aria-hidden="true" />
|
||||||
|
|
|
@ -22,7 +22,7 @@ const Dropdown: React.FC<DropdownProps> = ({ label, right, up, children }) => {
|
||||||
'is-right': right,
|
'is-right': right,
|
||||||
'is-up': up,
|
'is-up': up,
|
||||||
}),
|
}),
|
||||||
[active]
|
[active, right, up]
|
||||||
);
|
);
|
||||||
return (
|
return (
|
||||||
<div className={classNames} ref={wrapperRef}>
|
<div className={classNames} ref={wrapperRef}>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React, { useCallback } from 'react';
|
import React, { useCallback, useRef } from 'react';
|
||||||
import cx from 'classnames';
|
import cx from 'classnames';
|
||||||
|
|
||||||
interface DynamicTextButtonProps {
|
interface DynamicTextButtonProps {
|
||||||
|
@ -18,15 +18,15 @@ const DynamicTextButton: React.FC<DynamicTextButtonProps> = ({
|
||||||
}) => {
|
}) => {
|
||||||
const [clicked, setClicked] = React.useState(false);
|
const [clicked, setClicked] = React.useState(false);
|
||||||
|
|
||||||
let timeout: number;
|
const timeout = useRef(0);
|
||||||
|
|
||||||
const clickHandler = useCallback(() => {
|
const clickHandler = useCallback(() => {
|
||||||
onClick();
|
onClick();
|
||||||
setClicked(true);
|
setClicked(true);
|
||||||
timeout = window.setTimeout(() => setClicked(false), delay);
|
timeout.current = window.setTimeout(() => setClicked(false), delay);
|
||||||
}, []);
|
}, [delay, onClick]);
|
||||||
|
|
||||||
React.useEffect(() => () => window.clearTimeout(timeout), []);
|
React.useEffect(() => () => window.clearTimeout(timeout.current));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
|
|
|
@ -68,7 +68,7 @@ const Pagination: React.FC<PaginationProps> = ({ totalPages }) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
return p;
|
return p;
|
||||||
}, []);
|
}, [currentPage, totalPages]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<S.Wrapper role="navigation" aria-label="pagination">
|
<S.Wrapper role="navigation" aria-label="pagination">
|
||||||
|
|
|
@ -21,10 +21,13 @@ const Tabs: React.FC<TabsProps> = ({
|
||||||
setSelectedIndex(defaultSelectedIndex);
|
setSelectedIndex(defaultSelectedIndex);
|
||||||
}, [defaultSelectedIndex]);
|
}, [defaultSelectedIndex]);
|
||||||
|
|
||||||
const handleChange = React.useCallback((index: number) => {
|
const handleChange = React.useCallback(
|
||||||
setSelectedIndex(index);
|
(index: number) => {
|
||||||
onChange?.(index);
|
setSelectedIndex(index);
|
||||||
}, []);
|
onChange?.(index);
|
||||||
|
},
|
||||||
|
[onChange]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
|
@ -25,7 +25,7 @@ describe('useDataSaver hook', () => {
|
||||||
|
|
||||||
const HookWrapper: React.FC = () => {
|
const HookWrapper: React.FC = () => {
|
||||||
const { saveFile } = useDataSaver('message', content);
|
const { saveFile } = useDataSaver('message', content);
|
||||||
useEffect(() => saveFile(), []);
|
useEffect(() => saveFile(), [saveFile]);
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -52,7 +52,7 @@ describe('useDataSaver hook', () => {
|
||||||
|
|
||||||
const HookWrapper: React.FC = () => {
|
const HookWrapper: React.FC = () => {
|
||||||
const { saveFile } = useDataSaver('message', 'content');
|
const { saveFile } = useDataSaver('message', 'content');
|
||||||
useEffect(() => saveFile(), []);
|
useEffect(() => saveFile(), [saveFile]);
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -81,7 +81,7 @@ describe('useDataSaver hook', () => {
|
||||||
it('data with type Object', () => {
|
it('data with type Object', () => {
|
||||||
const HookWrapper: React.FC = () => {
|
const HookWrapper: React.FC = () => {
|
||||||
const { copyToClipboard } = useDataSaver('topic', content);
|
const { copyToClipboard } = useDataSaver('topic', content);
|
||||||
useEffect(() => copyToClipboard(), []);
|
useEffect(() => copyToClipboard(), [copyToClipboard]);
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
render(<HookWrapper />);
|
render(<HookWrapper />);
|
||||||
|
@ -96,7 +96,7 @@ describe('useDataSaver hook', () => {
|
||||||
'topic',
|
'topic',
|
||||||
'{ title: "title", }'
|
'{ title: "title", }'
|
||||||
);
|
);
|
||||||
useEffect(() => copyToClipboard(), []);
|
useEffect(() => copyToClipboard(), [copyToClipboard]);
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
render(<HookWrapper />);
|
render(<HookWrapper />);
|
||||||
|
|
|
@ -21,7 +21,7 @@ const useSearch = (initValue = ''): [string, (value: string) => void] => {
|
||||||
queryParams.set(SEARCH_QUERY_ARG, initValue.trim());
|
queryParams.set(SEARCH_QUERY_ARG, initValue.trim());
|
||||||
history.push({ pathname, search: queryParams.toString() });
|
history.push({ pathname, search: queryParams.toString() });
|
||||||
}
|
}
|
||||||
}, []);
|
}, [history, initValue, pathname, q, queryParams]);
|
||||||
|
|
||||||
const handleChange = useCallback(
|
const handleChange = useCallback(
|
||||||
(value: string) => {
|
(value: string) => {
|
||||||
|
@ -39,7 +39,7 @@ const useSearch = (initValue = ''): [string, (value: string) => void] => {
|
||||||
history.replace({ pathname, search: queryParams.toString() });
|
history.replace({ pathname, search: queryParams.toString() });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[history, pathname, queryParams, q]
|
[q, page, history, pathname, queryParams]
|
||||||
);
|
);
|
||||||
|
|
||||||
return [q || initValue.trim() || '', handleChange];
|
return [q || initValue.trim() || '', handleChange];
|
||||||
|
|
Loading…
Add table
Reference in a new issue