diff --git a/webapp/channels/src/components/admin_console/__snapshots__/database_settings.test.tsx.snap b/webapp/channels/src/components/admin_console/__snapshots__/database_settings.test.tsx.snap
index d9cfebf403..6e3218c0e1 100644
--- a/webapp/channels/src/components/admin_console/__snapshots__/database_settings.test.tsx.snap
+++ b/webapp/channels/src/components/admin_console/__snapshots__/database_settings.test.tsx.snap
@@ -381,7 +381,7 @@ exports[`components/DatabaseSettings should match snapshot 1`] = `
+`;
diff --git a/webapp/channels/src/components/admin_console/database/migrations_table.test.tsx b/webapp/channels/src/components/admin_console/database/migrations_table.test.tsx
new file mode 100644
index 0000000000..dafd28c90e
--- /dev/null
+++ b/webapp/channels/src/components/admin_console/database/migrations_table.test.tsx
@@ -0,0 +1,79 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
+
+import {act, screen, waitFor} from '@testing-library/react';
+import {shallow} from 'enzyme';
+import React from 'react';
+import {FormattedMessage} from 'react-intl';
+
+import type {SchemaMigration} from '@mattermost/types/admin';
+
+import type {ActionResult} from 'mattermost-redux/types/actions';
+
+import {renderWithContext} from 'tests/react_testing_utils';
+
+import MigrationsTable from './migrations_table';
+
+const migrationsMockData: SchemaMigration[] = [];
+
+describe('components/MigrationsTable', () => {
+ const createHelpText = (
+
+ );
+
+ const baseProps = {
+ createHelpText,
+ className: '',
+ actions: {
+ getAppliedSchemaMigrations: (jest.fn()).mockResolvedValue({
+ data: migrationsMockData,
+ } as ActionResult),
+ },
+ };
+
+ test('should match snapshot when there are no migrations', () => {
+ const wrapper = shallow(
+ );
+
+ expect(wrapper).toMatchSnapshot();
+ });
+
+ test('should have called actions.getAppliedSchemaMigrations only when first rendered', async () => {
+ const mockMigrations = [
+ {version: '1.0', name: 'Initial migration'},
+ {version: '1.1', name: 'Add users table'},
+ ];
+ const withDataProps = {
+ ...baseProps,
+ actions: {
+ getAppliedSchemaMigrations: (jest.fn()).mockResolvedValue({
+ data: mockMigrations,
+ } as ActionResult),
+ },
+ };
+
+ const view = renderWithContext();
+
+ await waitFor(() => {
+ expect(withDataProps.actions.getAppliedSchemaMigrations).toHaveBeenCalledTimes(1);
+ });
+
+ act(() => {
+ const newProps = {...withDataProps, className: 'foo'};
+ view.rerender();
+ });
+
+ await waitFor(() => {
+ expect(withDataProps.actions.getAppliedSchemaMigrations).toHaveBeenCalledTimes(1);
+ mockMigrations.forEach((migration) => {
+ expect(screen.getByText(migration.version)).toBeInTheDocument();
+ expect(screen.getByText(migration.name)).toBeInTheDocument();
+ });
+ });
+ });
+});
diff --git a/webapp/channels/src/components/admin_console/database/migrations_table.tsx b/webapp/channels/src/components/admin_console/database/migrations_table.tsx
index 8c2dac0e1b..ac4b63bbd2 100644
--- a/webapp/channels/src/components/admin_console/database/migrations_table.tsx
+++ b/webapp/channels/src/components/admin_console/database/migrations_table.tsx
@@ -2,7 +2,7 @@
// See LICENSE.txt for license information.
import classNames from 'classnames';
-import React from 'react';
+import React, {useEffect, useMemo, useState} from 'react';
import {FormattedMessage} from 'react-intl';
import type {SchemaMigration} from '@mattermost/types/admin';
@@ -11,7 +11,7 @@ import type {ActionResult} from 'mattermost-redux/types/actions';
import './migrations_table.scss';
-export type Props = {
+type Props = {
createHelpText: React.ReactElement;
className?: string;
actions: {
@@ -19,72 +19,68 @@ export type Props = {
};
}
-type State = {
- migrations: SchemaMigration[];
-}
+const MigrationsTable = ({
+ createHelpText,
+ className,
+ actions,
+}: Props) => {
+ const [migrations, setMigrations] = useState([]);
-class MigrationsTable extends React.PureComponent {
- constructor(props: Props) {
- super(props);
- this.state = {
- migrations: [],
- };
- }
+ useEffect(() => {
+ async function handleGetAppliedSchemaMigrations() {
+ const result: ActionResult = await actions.getAppliedSchemaMigrations();
+ if (result.data) {
+ setMigrations(result.data);
+ }
+ }
- componentDidMount() {
- this.props.actions.getAppliedSchemaMigrations().then((result) => {
- this.setState({
- migrations: result.data,
- });
- });
- }
-
- render() {
- const items = this.state.migrations.map((migration) => {
- return (
-
- | {migration.version} |
- {migration.name} |
-
- );
- });
+ handleGetAppliedSchemaMigrations();
+ }, []);
+ const items = useMemo(() => migrations.map((migration) => {
return (
-
-
- {this.props.createHelpText}
-
-
-
-
-
- |
-
- |
-
-
- |
-
-
-
- {items}
-
-
-
-
+
+ | {migration.version} |
+ {migration.name} |
+
);
- }
-}
+ }), [migrations]);
-export default MigrationsTable;
+ return (
+
+
+ {createHelpText}
+
+
+
+
+
+ |
+
+ |
+
+
+ |
+
+
+
+ {items}
+
+
+
+
+ );
+};
+
+export default React.memo(MigrationsTable);