Skip to content
This repository has been archived by the owner on Mar 13, 2024. It is now read-only.

Commit

Permalink
PLT-6451 Migrate installed_oauth_app.jsx to be pure and use Redux (#7190
Browse files Browse the repository at this point in the history
)

* Migrate installed_oauth_app.jsx to be pure and use Redux, add test

* Fix behavior for the error case
  • Loading branch information
n1aba authored and crspeller committed Aug 18, 2017
1 parent e5e9877 commit 1ff3120
Show file tree
Hide file tree
Showing 8 changed files with 294 additions and 49 deletions.
14 changes: 0 additions & 14 deletions actions/admin_actions.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ const getState = store.getState;

import * as AdminActions from 'mattermost-redux/actions/admin';
import * as UserActions from 'mattermost-redux/actions/users';
import * as IntegrationActions from 'mattermost-redux/actions/integrations';
import {Client4} from 'mattermost-redux/client';

export function saveConfig(config, success, error) {
Expand Down Expand Up @@ -238,19 +237,6 @@ export function oauthToEmail(currentService, email, password, success, error) {
);
}

export function regenerateOAuthAppSecret(oauthAppId, success, error) {
IntegrationActions.regenOAuthAppSecret(oauthAppId)(dispatch, getState).then(
(data) => {
if (data && success) {
success(data);
} else if (data == null && error) {
const serverError = getState().requests.admin.updateOAuthApp.error;
error({id: serverError.server_error_id, ...serverError});
}
}
);
}

export function uploadBrandImage(brandImage, success, error) {
AdminActions.uploadBrandImage(brandImage)(dispatch, getState).then(
(data) => {
Expand Down
79 changes: 46 additions & 33 deletions components/integrations/components/installed_oauth_app.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,70 +4,83 @@
import React from 'react';
import PropTypes from 'prop-types';

import FormError from 'components/form_error.jsx';

import * as Utils from 'utils/utils.jsx';

import {FormattedMessage, FormattedHTMLMessage} from 'react-intl';
import {regenerateOAuthAppSecret} from 'actions/admin_actions.jsx';

import FormError from 'components/form_error.jsx';
import DeleteIntegration from './delete_integration.jsx';

const FAKE_SECRET = '***************';

export default class InstalledOAuthApp extends React.Component {
static get propTypes() {
return {
oauthApp: PropTypes.object.isRequired,
onDelete: PropTypes.func.isRequired,
filter: PropTypes.string
};
export default class InstalledOAuthApp extends React.PureComponent {
static propTypes = {

/**
* The oauthApp data
*/
oauthApp: PropTypes.object.isRequired,

/**
* The request state for regenOAuthAppSecret action. Contains status and error
*/
regenOAuthAppSecretRequest: PropTypes.object.isRequired,

/**
* The function to call when Regenerate Secret link is clicked
*/
onRegenerateSecret: PropTypes.func.isRequired,

/**
* The function to call when Delete link is clicked
*/
onDelete: PropTypes.func.isRequired,

/**
* Set to filter OAuthApp
*/
filter: PropTypes.string
}

constructor(props) {
super(props);

this.handleShowClientSecret = this.handleShowClientSecret.bind(this);
this.handleHideClientScret = this.handleHideClientScret.bind(this);
this.handleRegenerate = this.handleRegenerate.bind(this);
this.handleDelete = this.handleDelete.bind(this);

this.matchesFilter = this.matchesFilter.bind(this);

this.state = {
clientSecret: FAKE_SECRET
};
}

handleShowClientSecret(e) {
e.preventDefault();
handleShowClientSecret = (e) => {
if (e && e.preventDefault) {
e.preventDefault();
}
this.setState({clientSecret: this.props.oauthApp.client_secret});
}

handleHideClientScret(e) {
handleHideClientSecret = (e) => {
e.preventDefault();
this.setState({clientSecret: FAKE_SECRET});
}

handleRegenerate(e) {
handleRegenerate = (e) => {
e.preventDefault();

regenerateOAuthAppSecret(
this.props.oauthApp.id,
this.props.onRegenerateSecret(this.props.oauthApp.id).then(
() => {
this.handleShowClientSecret(e);
},
(err) => {
this.setState({error: err.message});
const {error} = this.props.regenOAuthAppSecretRequest;
if (error) {
this.setState({error: error.message});
} else {
this.setState({error: null});
this.handleShowClientSecret();
}
}
);
}

handleDelete() {
handleDelete = () => {
this.props.onDelete(this.props.oauthApp);
}

matchesFilter(oauthApp, filter) {
matchesFilter = (oauthApp, filter) => {
if (!filter) {
return true;
}
Expand Down Expand Up @@ -152,7 +165,7 @@ export default class InstalledOAuthApp extends React.Component {
showHide = (
<a
href='#'
onClick={this.handleHideClientScret}
onClick={this.handleHideClientSecret}
>
<FormattedMessage
id='installed_integrations.hideSecret'
Expand Down Expand Up @@ -254,4 +267,4 @@ export default class InstalledOAuthApp extends React.Component {
</div>
);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,16 @@ function mapStateToProps(state, ownProps) {
return {
...ownProps,
oauthApps: getOAuthApps(state),
isSystemAdmin: isCurrentUserSystemAdmin(state)
isSystemAdmin: isCurrentUserSystemAdmin(state),
regenOAuthAppSecretRequest: state.requests.integrations.updateOAuthApp
};
}

function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators({
getOAuthApps: Actions.getOAuthApps,
regenOAuthAppSecret: Actions.regenOAuthAppSecret,
deleteOAuthApp: Actions.deleteOAuthApp
}, dispatch)
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,23 @@ export default class InstalledOAuthApps extends React.PureComponent {
*/
isSystemAdmin: PropTypes.bool,

/**
* The request state for regenOAuthAppSecret action. Contains status and error
*/
regenOAuthAppSecretRequest: PropTypes.object.isRequired,

actions: PropTypes.shape({

/**
* The function to call to fetch OAuth apps
*/
getOAuthApps: PropTypes.func.isRequired,

/**
* The function to call when Regenerate Secret link is clicked
*/
regenOAuthAppSecret: PropTypes.func.isRequired,

/**
* The function to call when Delete link is clicked
*/
Expand Down Expand Up @@ -80,6 +90,8 @@ export default class InstalledOAuthApps extends React.PureComponent {
<InstalledOAuthApp
key={app.id}
oauthApp={app}
regenOAuthAppSecretRequest={this.props.regenOAuthAppSecretRequest}
onRegenerateSecret={this.props.actions.regenOAuthAppSecret}
onDelete={this.deleteOAuthApp}
/>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`components/integrations/InstalledOAuthApp should filter out OAuthApp 1`] = `null`;

exports[`components/integrations/InstalledOAuthApp should match snapshot 1`] = `
<div
className="backstage-list__item"
>
<div
className="integration__icon integration-list__icon"
>
<img
src="https://test.com/icon"
/>
</div>
<div
className="item-details"
>
<div
className="item-details__row"
>
<span
className="item-details__name"
>
testApp
</span>
</div>
<div
className="item-details__row"
>
<span
className="item-details__description"
>
testing
</span>
</div>
<div
className="item-details__row"
>
<span
className="item-details__url"
>
<FormattedHTMLMessage
defaultMessage="Is Trusted: <strong>{isTrusted}</strong>"
id="installed_oauth_apps.is_trusted"
values={
Object {
"isTrusted": "Yes",
}
}
/>
</span>
</div>
<div
className="item-details__row"
>
<span
className="item-details__token"
>
<FormattedHTMLMessage
defaultMessage="Client ID: <strong>{clientId}</strong>"
id="installed_integrations.client_id"
values={
Object {
"clientId": "facxd9wpzpbpfp8pad78xj75pr",
}
}
/>
</span>
</div>
<div
className="item-details__row"
>
<span
className="item-details__token"
>
<FormattedHTMLMessage
defaultMessage="Client Secret: <strong>{clientSecret}</strong>"
id="installed_integrations.client_secret"
values={
Object {
"clientSecret": "***************",
}
}
/>
</span>
</div>
<div
className="item-details__row"
>
<span
className="item-details__url"
>
<FormattedMessage
defaultMessage="Callback URLs: {urls}"
id="installed_integrations.callback_urls"
values={
Object {
"urls": "https://test.com/callback, https://test.com/callback2",
}
}
/>
</span>
</div>
<div
className="item-details__row"
>
<span
className="item-details__creation"
>
<FormattedMessage
defaultMessage="Created by {creator} on {createAt, date, full}"
id="installed_integrations.creation"
values={
Object {
"createAt": 1501365458934,
"creator": "",
}
}
/>
</span>
</div>
</div>
<div
className="item-actions"
>
<a
href="#"
onClick={[Function]}
>
<FormattedMessage
defaultMessage="Show Secret"
id="installed_integrations.showSecret"
values={Object {}}
/>
</a>
-
<a
href="#"
onClick={[Function]}
>
<FormattedMessage
defaultMessage="Regenerate Secret"
id="installed_integrations.regenSecret"
values={Object {}}
/>
</a>
-
<DeleteIntegration
messageId="installed_oauth_apps.delete.confirm"
onDelete={[Function]}
/>
</div>
</div>
`;
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ exports[`components/integrations/InstalledOAuthApps should match snapshot 1`] =
}
}
onDelete={[Function]}
onRegenerateSecret={[Function]}
/>
<InstalledOAuthApp
oauthApp={
Expand All @@ -93,6 +94,7 @@ exports[`components/integrations/InstalledOAuthApps should match snapshot 1`] =
}
}
onDelete={[Function]}
onRegenerateSecret={[Function]}
/>
</BackstageList>
`;
Loading

0 comments on commit 1ff3120

Please sign in to comment.