Skip to content

Commit

Permalink
Refactor ClusterTasks and dropdown containers to be functional compon…
Browse files Browse the repository at this point in the history
…ents

Update the ClusterTasks and *Dropdown containers to use the React Hooks API
(i.e. convert from class-based to functional components) so we can adopt
`react-query` and other libraries that only provide a hook-based API.
  • Loading branch information
AlanGreene authored and tekton-robot committed Apr 23, 2021
1 parent 5b68115 commit 2ce9981
Show file tree
Hide file tree
Showing 14 changed files with 399 additions and 462 deletions.
353 changes: 167 additions & 186 deletions src/containers/ClusterTasks/ClusterTasks.js

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion src/containers/ClusterTasks/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
Copyright 2019 The Tekton Authors
Copyright 2019-2021 The Tekton Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
Expand All @@ -10,5 +10,6 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/* istanbul ignore file */

export { default } from './ClusterTasks';
65 changes: 28 additions & 37 deletions src/containers/ClusterTasksDropdown/ClusterTasksDropdown.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
Copyright 2020 The Tekton Authors
Copyright 2020-2021 The Tekton Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
Expand All @@ -11,7 +11,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

import React from 'react';
import React, { useEffect } from 'react';
import { injectIntl } from 'react-intl';
import { connect } from 'react-redux';
import { TooltipDropdown } from '@tektoncd/dashboard-components';
Expand All @@ -21,44 +21,35 @@ import {
isFetchingClusterTasks,
isWebSocketConnected
} from '../../reducers';
import { fetchClusterTasks } from '../../actions/tasks';
import { fetchClusterTasks as fetchClusterTasksActionCreator } from '../../actions/tasks';

class ClusterTasksDropdown extends React.Component {
componentDidMount() {
this.props.fetchClusterTasks();
}

componentDidUpdate(prevProps) {
const { webSocketConnected } = this.props;
const { webSocketConnected: prevWebSocketConnected } = prevProps;
if (webSocketConnected && prevWebSocketConnected === false) {
this.props.fetchClusterTasks();
function ClusterTasksDropdown({
fetchClusterTasks,
intl,
label,
webSocketConnected,
...rest
}) {
useEffect(() => {
if (webSocketConnected !== false) {
fetchClusterTasks();
}
}
}, [webSocketConnected]);

render() {
const {
fetchClusterTasks: _fetchClusterTasks,
intl,
label,
webSocketConnected,
...rest
} = this.props;
const emptyText = intl.formatMessage({
id: 'dashboard.clusterTasksDropdown.empty',
defaultMessage: 'No ClusterTasks found'
});
const emptyText = intl.formatMessage({
id: 'dashboard.clusterTasksDropdown.empty',
defaultMessage: 'No ClusterTasks found'
});

const labelString =
label ||
intl.formatMessage({
id: 'dashboard.clusterTasksDropdown.label',
defaultMessage: 'Select ClusterTask'
});
return (
<TooltipDropdown {...rest} emptyText={emptyText} label={labelString} />
);
}
const labelString =
label ||
intl.formatMessage({
id: 'dashboard.clusterTasksDropdown.label',
defaultMessage: 'Select ClusterTask'
});
return (
<TooltipDropdown {...rest} emptyText={emptyText} label={labelString} />
);
}

ClusterTasksDropdown.defaultProps = {
Expand All @@ -76,7 +67,7 @@ function mapStateToProps(state) {
}

const mapDispatchToProps = {
fetchClusterTasks
fetchClusterTasks: fetchClusterTasksActionCreator
};

export default connect(
Expand Down
21 changes: 20 additions & 1 deletion src/containers/ClusterTasksDropdown/ClusterTasksDropdown.test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
Copyright 2020 The Tekton Authors
Copyright 2020-2021 The Tekton Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
Expand All @@ -20,6 +20,7 @@ import { renderWithIntl } from '@tektoncd/dashboard-components/src/utils/test';

import ClusterTasksDropdown from './ClusterTasksDropdown';
import * as API from '../../api/clusterTasks';
import * as reducers from '../../reducers';

const props = {
id: 'clustertasks-dropdown',
Expand Down Expand Up @@ -188,4 +189,22 @@ describe('ClusterTasksDropdown', () => {
fireEvent.click(getByText(/clustertask-1/i));
expect(onChange).toHaveBeenCalledTimes(1);
});

it('does not make the API call when the websocket disconnects', () => {
jest
.spyOn(reducers, 'isWebSocketConnected')
.mockImplementation(() => false);
jest.spyOn(API, 'getClusterTasks');

const store = mockStore({
...clusterTasksStoreDefault,
notifications: {}
});
renderWithIntl(
<Provider store={store}>
<ClusterTasksDropdown {...props} />
</Provider>
);
expect(API.getClusterTasks).not.toHaveBeenCalled();
});
});
3 changes: 2 additions & 1 deletion src/containers/ClusterTasksDropdown/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
Copyright 2020 The Tekton Authors
Copyright 2020-2021 The Tekton Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
Expand All @@ -10,5 +10,6 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/* istanbul ignore file */

export { default } from './ClusterTasksDropdown';
3 changes: 2 additions & 1 deletion src/containers/NamespacesDropdown/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
Copyright 2019 The Tekton Authors
Copyright 2019-2021 The Tekton Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
Expand All @@ -10,5 +10,6 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/* istanbul ignore file */

export { default } from './NamespacesDropdown';
130 changes: 57 additions & 73 deletions src/containers/PipelineResourcesDropdown/PipelineResourcesDropdown.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
Copyright 2019 The Tekton Authors
Copyright 2019-2021 The Tekton Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
Expand All @@ -11,7 +11,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

import React from 'react';
import React, { useEffect } from 'react';
import { injectIntl } from 'react-intl';
import { connect } from 'react-redux';
import { ALL_NAMESPACES } from '@tektoncd/dashboard-utils';
Expand All @@ -23,82 +23,66 @@ import {
isFetchingPipelineResources,
isWebSocketConnected
} from '../../reducers';
import { fetchPipelineResources } from '../../actions/pipelineResources';
import { fetchPipelineResources as fetchPipelineResourcesActionCreator } from '../../actions/pipelineResources';

class PipelineResourcesDropdown extends React.Component {
componentDidMount() {
const { namespace } = this.props;
this.props.fetchPipelineResources({ namespace });
}
function PipelineResourcesDropdown({
fetchPipelineResources,
intl,
label,
namespace,
type,
webSocketConnected,
...rest
}) {
useEffect(() => {
fetchPipelineResources({ namespace });
}, [namespace, webSocketConnected]);

componentDidUpdate(prevProps) {
const { namespace, webSocketConnected } = this.props;
const { webSocketConnected: prevWebSocketConnected } = prevProps;
if (
namespace !== prevProps.namespace ||
(webSocketConnected && prevWebSocketConnected === false)
) {
this.props.fetchPipelineResources({ namespace });
}
let emptyText = intl.formatMessage({
id: 'dashboard.pipelineResourcesDropdown.empty.allNamespaces',
defaultMessage: 'No PipelineResources found'
});
if (type && namespace !== ALL_NAMESPACES) {
emptyText = intl.formatMessage(
{
id: 'dashboard.pipelineResourcesDropdown.empty.selectedNamespace.type',
defaultMessage:
"No PipelineResources found of type ''{type}'' in the ''{namespace}'' namespace"
},
{
namespace,
type
}
);
} else if (type) {
emptyText = intl.formatMessage(
{
id: 'dashboard.pipelineResourcesDropdown.empty.allNamespaces.type',
defaultMessage: "No PipelineResources found of type ''{type}''"
},
{ type }
);
} else if (namespace !== ALL_NAMESPACES) {
emptyText = intl.formatMessage(
{
id: 'dashboard.pipelineResourcesDropdown.empty.selectedNamespace',
defaultMessage:
"No PipelineResources found in the ''{namespace}'' namespace"
},
{ namespace }
);
}

render() {
const {
fetchPipelineResources: _fetchPipelineResources,
intl,
label,
namespace,
type,
webSocketConnected,
...rest
} = this.props;
let emptyText = intl.formatMessage({
id: 'dashboard.pipelineResourcesDropdown.empty.allNamespaces',
defaultMessage: 'No PipelineResources found'
const labelString =
label ||
intl.formatMessage({
id: 'dashboard.pipelineResourcesDropdown.label',
defaultMessage: 'Select PipelineResource'
});
if (type && namespace !== ALL_NAMESPACES) {
emptyText = intl.formatMessage(
{
id:
'dashboard.pipelineResourcesDropdown.empty.selectedNamespace.type',
defaultMessage:
"No PipelineResources found of type ''{type}'' in the ''{namespace}'' namespace"
},
{
namespace,
type
}
);
} else if (type) {
emptyText = intl.formatMessage(
{
id: 'dashboard.pipelineResourcesDropdown.empty.allNamespaces.type',
defaultMessage: "No PipelineResources found of type ''{type}''"
},
{ type }
);
} else if (namespace !== ALL_NAMESPACES) {
emptyText = intl.formatMessage(
{
id: 'dashboard.pipelineResourcesDropdown.empty.selectedNamespace',
defaultMessage:
"No PipelineResources found in the ''{namespace}'' namespace"
},
{ namespace }
);
}

const labelString =
label ||
intl.formatMessage({
id: 'dashboard.pipelineResourcesDropdown.label',
defaultMessage: 'Select PipelineResource'
});

return (
<TooltipDropdown {...rest} emptyText={emptyText} label={labelString} />
);
}
return (
<TooltipDropdown {...rest} emptyText={emptyText} label={labelString} />
);
}

PipelineResourcesDropdown.defaultProps = {
Expand All @@ -121,7 +105,7 @@ function mapStateToProps(state, ownProps) {
}

const mapDispatchToProps = {
fetchPipelineResources
fetchPipelineResources: fetchPipelineResourcesActionCreator
};

export default connect(
Expand Down
3 changes: 2 additions & 1 deletion src/containers/PipelineResourcesDropdown/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
Copyright 2019 The Tekton Authors
Copyright 2019-2021 The Tekton Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
Expand All @@ -10,5 +10,6 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/* istanbul ignore file */

export { default } from './PipelineResourcesDropdown';
Loading

0 comments on commit 2ce9981

Please sign in to comment.