2019-12-07 16:58:52 +05:30
|
|
|
|
import React from 'react';
|
2018-03-26 00:46:45 +05:30
|
|
|
|
import { FormattedMessage as Message } from 'react-intl';
|
|
|
|
|
import { Link } from 'react-router-dom';
|
|
|
|
|
import classNames from 'classnames';
|
|
|
|
|
import { SKIN_LIGHT, COLOR_BLACK, COLOR_RED } from 'components/ui';
|
|
|
|
|
import { Input, Button } from 'components/ui/form';
|
2019-12-07 16:58:52 +05:30
|
|
|
|
import { OauthAppResponse } from 'services/api/oauth';
|
2018-03-26 00:46:45 +05:30
|
|
|
|
import Collapse from 'components/ui/collapse';
|
|
|
|
|
|
2018-11-04 11:01:31 +05:30
|
|
|
|
import styles from '../applicationsIndex.scss';
|
|
|
|
|
import messages from '../ApplicationsIndex.intl.json';
|
2018-03-26 00:46:45 +05:30
|
|
|
|
|
|
|
|
|
const ACTION_REVOKE_TOKENS = 'revoke-tokens';
|
|
|
|
|
const ACTION_RESET_SECRET = 'reset-secret';
|
|
|
|
|
const ACTION_DELETE = 'delete';
|
2018-11-04 11:01:31 +05:30
|
|
|
|
const actionButtons = [
|
2019-11-27 14:33:32 +05:30
|
|
|
|
{
|
|
|
|
|
type: ACTION_REVOKE_TOKENS,
|
|
|
|
|
label: messages.revokeAllTokens,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
type: ACTION_RESET_SECRET,
|
|
|
|
|
label: messages.resetClientSecret,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
type: ACTION_DELETE,
|
|
|
|
|
label: messages.delete,
|
|
|
|
|
},
|
2018-11-04 11:01:31 +05:30
|
|
|
|
];
|
2018-03-26 00:46:45 +05:30
|
|
|
|
|
2019-12-07 16:58:52 +05:30
|
|
|
|
interface State {
|
|
|
|
|
selectedAction: string | null;
|
|
|
|
|
isActionPerforming: boolean;
|
|
|
|
|
detailsHeight: number;
|
|
|
|
|
translateY: number;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export default class ApplicationItem extends React.Component<
|
2019-11-27 14:33:32 +05:30
|
|
|
|
{
|
2019-12-07 16:58:52 +05:30
|
|
|
|
application: OauthAppResponse;
|
|
|
|
|
expand: boolean;
|
|
|
|
|
onTileClick: (clientId: string) => void;
|
|
|
|
|
onResetSubmit: (
|
|
|
|
|
clientId: string,
|
|
|
|
|
resetClientSecret: boolean,
|
|
|
|
|
) => Promise<void>;
|
|
|
|
|
onDeleteSubmit: (clientId: string) => Promise<void>;
|
2019-11-27 14:33:32 +05:30
|
|
|
|
},
|
2019-12-07 16:58:52 +05:30
|
|
|
|
State
|
2018-11-04 11:01:31 +05:30
|
|
|
|
> {
|
2019-12-07 16:58:52 +05:30
|
|
|
|
state: State = {
|
2019-11-27 14:33:32 +05:30
|
|
|
|
selectedAction: null,
|
|
|
|
|
isActionPerforming: false,
|
|
|
|
|
translateY: 0,
|
|
|
|
|
detailsHeight: 0,
|
|
|
|
|
};
|
2018-03-26 00:46:45 +05:30
|
|
|
|
|
2019-12-07 16:58:52 +05:30
|
|
|
|
actionContainer: HTMLDivElement | null;
|
2018-11-04 11:37:04 +05:30
|
|
|
|
|
2019-11-27 14:33:32 +05:30
|
|
|
|
render() {
|
|
|
|
|
const { application: app, expand } = this.props;
|
|
|
|
|
const { selectedAction, translateY } = this.state;
|
2018-11-04 11:01:31 +05:30
|
|
|
|
|
2019-11-27 14:33:32 +05:30
|
|
|
|
return (
|
|
|
|
|
<div
|
|
|
|
|
className={classNames(styles.appItemContainer, {
|
|
|
|
|
[styles.appExpanded]: expand,
|
|
|
|
|
})}
|
|
|
|
|
data-e2e="appItem"
|
|
|
|
|
data-e2e-app-name={app.name}
|
|
|
|
|
>
|
|
|
|
|
<div className={styles.appItemTile} onClick={this.onTileToggle}>
|
|
|
|
|
<div className={styles.appTileTitle}>
|
|
|
|
|
<div className={styles.appName}>{app.name}</div>
|
|
|
|
|
<div className={styles.appStats}>
|
|
|
|
|
Client ID: {app.clientId}
|
|
|
|
|
{typeof app.countUsers !== 'undefined' && (
|
|
|
|
|
<span>
|
|
|
|
|
{' | '}
|
|
|
|
|
<Message
|
|
|
|
|
{...messages.countUsers}
|
|
|
|
|
values={{
|
|
|
|
|
count: app.countUsers,
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
</span>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div className={styles.appItemToggle}>
|
|
|
|
|
<div className={styles.appItemToggleIcon} />
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
2018-11-04 11:01:31 +05:30
|
|
|
|
|
2019-11-27 14:33:32 +05:30
|
|
|
|
<Collapse isOpened={expand} onRest={this.onCollapseRest}>
|
|
|
|
|
<div
|
|
|
|
|
className={styles.appDetailsContainer}
|
|
|
|
|
style={{ transform: `translateY(-${translateY}px)` }}
|
|
|
|
|
>
|
|
|
|
|
<div className={styles.appDetailsInfoField}>
|
|
|
|
|
<Link
|
|
|
|
|
to={`/dev/applications/${app.clientId}`}
|
|
|
|
|
className={styles.editAppLink}
|
|
|
|
|
>
|
|
|
|
|
<Message
|
|
|
|
|
{...messages.editDescription}
|
|
|
|
|
values={{
|
|
|
|
|
icon: <div className={styles.pencilIcon} />,
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
</Link>
|
|
|
|
|
<Input
|
|
|
|
|
label="Client ID:"
|
|
|
|
|
skin={SKIN_LIGHT}
|
|
|
|
|
disabled
|
|
|
|
|
value={app.clientId}
|
|
|
|
|
copy
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
2018-11-04 11:01:31 +05:30
|
|
|
|
|
2019-11-27 14:33:32 +05:30
|
|
|
|
<div className={styles.appDetailsInfoField}>
|
|
|
|
|
<Input
|
|
|
|
|
label="Client Secret:"
|
|
|
|
|
skin={SKIN_LIGHT}
|
|
|
|
|
disabled
|
|
|
|
|
value={app.clientSecret}
|
|
|
|
|
copy
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
2018-11-04 11:01:31 +05:30
|
|
|
|
|
2019-11-27 14:33:32 +05:30
|
|
|
|
<div className={styles.appDetailsDescription}>
|
|
|
|
|
<Message
|
|
|
|
|
{...messages.ifYouSuspectingThatSecretHasBeenCompromised}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
2018-03-26 00:46:45 +05:30
|
|
|
|
|
2019-11-27 14:33:32 +05:30
|
|
|
|
<div className={styles.appActionsButtons}>
|
|
|
|
|
{actionButtons.map(({ type, label }) => (
|
|
|
|
|
<Button
|
|
|
|
|
key={type}
|
|
|
|
|
label={label}
|
|
|
|
|
color={COLOR_BLACK}
|
|
|
|
|
className={styles.appActionButton}
|
2019-12-07 16:58:52 +05:30
|
|
|
|
disabled={!!selectedAction && selectedAction !== type}
|
2019-11-27 14:33:32 +05:30
|
|
|
|
onClick={this.onActionButtonClick(type)}
|
|
|
|
|
small
|
|
|
|
|
/>
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
2018-11-04 11:01:31 +05:30
|
|
|
|
|
2019-11-27 14:33:32 +05:30
|
|
|
|
<div
|
|
|
|
|
className={styles.appActionContainer}
|
|
|
|
|
ref={el => {
|
|
|
|
|
this.actionContainer = el;
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
{this.getActionContent()}
|
2018-11-04 11:01:31 +05:30
|
|
|
|
</div>
|
2019-11-27 14:33:32 +05:30
|
|
|
|
</div>
|
|
|
|
|
</Collapse>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
2018-11-04 11:01:31 +05:30
|
|
|
|
|
2019-11-27 14:33:32 +05:30
|
|
|
|
getActionContent() {
|
|
|
|
|
const { selectedAction, isActionPerforming } = this.state;
|
2018-05-14 01:02:53 +05:30
|
|
|
|
|
2019-11-27 14:33:32 +05:30
|
|
|
|
switch (selectedAction) {
|
|
|
|
|
case ACTION_REVOKE_TOKENS:
|
|
|
|
|
case ACTION_RESET_SECRET:
|
|
|
|
|
return (
|
|
|
|
|
<div>
|
|
|
|
|
<div className={styles.appActionDescription}>
|
|
|
|
|
<Message {...messages.allRefreshTokensWillBecomeInvalid} />{' '}
|
|
|
|
|
<Message {...messages.takeCareAccessTokensInvalidation} />
|
|
|
|
|
</div>
|
|
|
|
|
<div className={styles.appActionsButtons}>
|
|
|
|
|
<Button
|
|
|
|
|
label={messages.cancel}
|
|
|
|
|
color={COLOR_BLACK}
|
|
|
|
|
className={styles.appActionButton}
|
|
|
|
|
onClick={this.onActionButtonClick(null)}
|
|
|
|
|
small
|
|
|
|
|
/>
|
|
|
|
|
<div className={styles.continueActionButtonWrapper}>
|
|
|
|
|
{isActionPerforming ? (
|
|
|
|
|
<div className={styles.performingAction}>
|
|
|
|
|
<Message {...messages.performing} />
|
|
|
|
|
</div>
|
|
|
|
|
) : (
|
|
|
|
|
<div
|
|
|
|
|
className={styles.continueActionLink}
|
|
|
|
|
onClick={this.onResetSubmit(
|
|
|
|
|
selectedAction === ACTION_RESET_SECRET,
|
|
|
|
|
)}
|
|
|
|
|
>
|
|
|
|
|
<Message {...messages.continue} />
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
2018-11-04 11:01:31 +05:30
|
|
|
|
|
2019-11-27 14:33:32 +05:30
|
|
|
|
case ACTION_DELETE:
|
|
|
|
|
return (
|
|
|
|
|
<div>
|
|
|
|
|
<div className={styles.appActionDescription}>
|
|
|
|
|
<Message {...messages.appAndAllTokenWillBeDeleted} />{' '}
|
|
|
|
|
<Message {...messages.takeCareAccessTokensInvalidation} />
|
|
|
|
|
</div>
|
|
|
|
|
<div className={styles.appActionsButtons}>
|
|
|
|
|
<Button
|
|
|
|
|
label={messages.cancel}
|
|
|
|
|
color={COLOR_BLACK}
|
|
|
|
|
className={styles.appActionButton}
|
|
|
|
|
onClick={this.onActionButtonClick(null)}
|
|
|
|
|
small
|
|
|
|
|
/>
|
|
|
|
|
<div className={styles.continueActionButtonWrapper}>
|
|
|
|
|
{isActionPerforming ? (
|
|
|
|
|
<div className={styles.performingAction}>
|
|
|
|
|
<Message {...messages.performing} />
|
|
|
|
|
</div>
|
|
|
|
|
) : (
|
|
|
|
|
<Button
|
|
|
|
|
label={messages.delete}
|
|
|
|
|
color={COLOR_RED}
|
|
|
|
|
className={styles.appActionButton}
|
|
|
|
|
onClick={this.onSubmitDelete}
|
|
|
|
|
small
|
|
|
|
|
/>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
2018-11-04 11:01:31 +05:30
|
|
|
|
|
2019-11-27 14:33:32 +05:30
|
|
|
|
default:
|
|
|
|
|
return null;
|
2018-03-26 00:46:45 +05:30
|
|
|
|
}
|
2019-11-27 14:33:32 +05:30
|
|
|
|
}
|
2018-03-26 00:46:45 +05:30
|
|
|
|
|
2019-12-07 16:58:52 +05:30
|
|
|
|
setActiveAction = (type: string | null) => {
|
2019-11-27 14:33:32 +05:30
|
|
|
|
const { actionContainer } = this;
|
2018-11-04 11:37:04 +05:30
|
|
|
|
|
2019-11-27 14:33:32 +05:30
|
|
|
|
if (!actionContainer) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2018-11-04 11:37:04 +05:30
|
|
|
|
|
2019-11-27 14:33:32 +05:30
|
|
|
|
this.setState(
|
|
|
|
|
{
|
|
|
|
|
selectedAction: type,
|
|
|
|
|
},
|
|
|
|
|
() => {
|
|
|
|
|
const translateY = actionContainer.offsetHeight;
|
2018-11-04 11:37:04 +05:30
|
|
|
|
|
2019-11-27 14:33:32 +05:30
|
|
|
|
this.setState({ translateY });
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
};
|
2018-11-04 11:37:04 +05:30
|
|
|
|
|
2019-11-27 14:33:32 +05:30
|
|
|
|
onTileToggle = () => {
|
|
|
|
|
const { onTileClick, application } = this.props;
|
2018-11-04 11:37:04 +05:30
|
|
|
|
|
2019-11-27 14:33:32 +05:30
|
|
|
|
onTileClick(application.clientId);
|
|
|
|
|
};
|
2018-03-26 00:46:45 +05:30
|
|
|
|
|
2019-11-27 14:33:32 +05:30
|
|
|
|
onCollapseRest = () => {
|
|
|
|
|
if (!this.props.expand && this.state.selectedAction) {
|
|
|
|
|
this.setActiveAction(null);
|
|
|
|
|
}
|
|
|
|
|
};
|
2018-03-26 00:46:45 +05:30
|
|
|
|
|
2019-12-07 16:58:52 +05:30
|
|
|
|
onActionButtonClick = (type: string | null) => () => {
|
2019-11-27 14:33:32 +05:30
|
|
|
|
this.setActiveAction(type === this.state.selectedAction ? null : type);
|
|
|
|
|
};
|
2018-03-26 00:46:45 +05:30
|
|
|
|
|
2019-11-27 14:33:32 +05:30
|
|
|
|
onResetSubmit = (resetClientSecret: boolean) => async () => {
|
|
|
|
|
const { onResetSubmit, application } = this.props;
|
2018-11-04 11:37:04 +05:30
|
|
|
|
|
2019-11-27 14:33:32 +05:30
|
|
|
|
this.setState({
|
|
|
|
|
isActionPerforming: true,
|
|
|
|
|
});
|
2018-11-04 11:37:04 +05:30
|
|
|
|
|
2019-11-27 14:33:32 +05:30
|
|
|
|
await onResetSubmit(application.clientId, resetClientSecret);
|
2018-11-04 11:37:04 +05:30
|
|
|
|
|
2019-11-27 14:33:32 +05:30
|
|
|
|
this.setState({
|
|
|
|
|
isActionPerforming: false,
|
|
|
|
|
});
|
|
|
|
|
this.setActiveAction(null);
|
|
|
|
|
};
|
2018-03-26 00:46:45 +05:30
|
|
|
|
|
2019-11-27 14:33:32 +05:30
|
|
|
|
onSubmitDelete = () => {
|
|
|
|
|
const { onDeleteSubmit, application } = this.props;
|
2018-11-04 11:37:04 +05:30
|
|
|
|
|
2019-11-27 14:33:32 +05:30
|
|
|
|
this.setState({
|
|
|
|
|
isActionPerforming: true,
|
|
|
|
|
});
|
2018-11-04 11:37:04 +05:30
|
|
|
|
|
2019-11-27 14:33:32 +05:30
|
|
|
|
onDeleteSubmit(application.clientId);
|
|
|
|
|
};
|
2018-03-26 00:46:45 +05:30
|
|
|
|
}
|