|
1 | 1 | import PropTypes from 'prop-types';
|
2 |
| -import React from 'react'; |
| 2 | +import React, { useState } from 'react'; |
| 3 | +import { useTranslation } from 'react-i18next'; |
| 4 | +import { useDispatch, useSelector } from 'react-redux'; |
3 | 5 | import Button from '../../../common/Button';
|
4 | 6 | import { PlusIcon } from '../../../common/icons';
|
5 | 7 | import CopyableInput from '../../IDE/components/CopyableInput';
|
| 8 | +import { createApiKey, removeApiKey } from '../actions'; |
6 | 9 |
|
7 | 10 | import APIKeyList from './APIKeyList';
|
8 | 11 |
|
9 | 12 | export const APIKeyPropType = PropTypes.shape({
|
10 |
| - id: PropTypes.objectOf(PropTypes.shape()).isRequired, |
11 |
| - token: PropTypes.objectOf(PropTypes.shape()), |
| 13 | + id: PropTypes.string.isRequired, |
| 14 | + token: PropTypes.string, |
12 | 15 | label: PropTypes.string.isRequired,
|
13 | 16 | createdAt: PropTypes.string.isRequired,
|
14 | 17 | lastUsedAt: PropTypes.string
|
15 | 18 | });
|
16 | 19 |
|
17 |
| -class APIKeyForm extends React.Component { |
18 |
| - constructor(props) { |
19 |
| - super(props); |
20 |
| - this.state = { keyLabel: '' }; |
| 20 | +const APIKeyForm = () => { |
| 21 | + const { t } = useTranslation(); |
| 22 | + const apiKeys = useSelector((state) => state.user.apiKeys); |
| 23 | + const dispatch = useDispatch(); |
21 | 24 |
|
22 |
| - this.addKey = this.addKey.bind(this); |
23 |
| - this.removeKey = this.removeKey.bind(this); |
24 |
| - this.renderApiKeys = this.renderApiKeys.bind(this); |
25 |
| - } |
| 25 | + const [keyLabel, setKeyLabel] = useState(''); |
26 | 26 |
|
27 |
| - addKey(event) { |
| 27 | + const addKey = (event) => { |
28 | 28 | event.preventDefault();
|
29 |
| - const { keyLabel } = this.state; |
| 29 | + dispatch(createApiKey(keyLabel)); |
| 30 | + setKeyLabel(''); |
| 31 | + }; |
30 | 32 |
|
31 |
| - this.setState({ |
32 |
| - keyLabel: '' |
33 |
| - }); |
34 |
| - |
35 |
| - this.props.createApiKey(keyLabel); |
36 |
| - |
37 |
| - return false; |
38 |
| - } |
39 |
| - |
40 |
| - removeKey(key) { |
41 |
| - const message = this.props.t('APIKeyForm.ConfirmDelete', { |
| 33 | + const removeKey = (key) => { |
| 34 | + const message = t('APIKeyForm.ConfirmDelete', { |
42 | 35 | key_label: key.label
|
43 | 36 | });
|
44 | 37 |
|
45 | 38 | if (window.confirm(message)) {
|
46 |
| - this.props.removeApiKey(key.id); |
| 39 | + dispatch(removeApiKey(key.id)); |
47 | 40 | }
|
48 |
| - } |
| 41 | + }; |
49 | 42 |
|
50 |
| - renderApiKeys() { |
51 |
| - const hasApiKeys = this.props.apiKeys && this.props.apiKeys.length > 0; |
| 43 | + const renderApiKeys = () => { |
| 44 | + const hasApiKeys = apiKeys && apiKeys.length > 0; |
52 | 45 |
|
53 | 46 | if (hasApiKeys) {
|
54 |
| - return ( |
55 |
| - <APIKeyList apiKeys={this.props.apiKeys} onRemove={this.removeKey} /> |
56 |
| - ); |
| 47 | + return <APIKeyList apiKeys={apiKeys} onRemove={removeKey} />; |
57 | 48 | }
|
58 |
| - return <p>{this.props.t('APIKeyForm.NoTokens')}</p>; |
59 |
| - } |
60 |
| - |
61 |
| - render() { |
62 |
| - const keyWithToken = this.props.apiKeys.find((k) => !!k.token); |
63 |
| - |
64 |
| - return ( |
65 |
| - <div className="api-key-form"> |
66 |
| - <p className="api-key-form__summary"> |
67 |
| - {this.props.t('APIKeyForm.Summary')} |
68 |
| - </p> |
69 |
| - |
70 |
| - <div className="api-key-form__section"> |
71 |
| - <h3 className="api-key-form__title"> |
72 |
| - {this.props.t('APIKeyForm.CreateToken')} |
73 |
| - </h3> |
74 |
| - <form className="form form--inline" onSubmit={this.addKey}> |
75 |
| - <label |
76 |
| - htmlFor="keyLabel" |
77 |
| - className="form__label form__label--hidden " |
78 |
| - > |
79 |
| - {this.props.t('APIKeyForm.TokenLabel')} |
80 |
| - </label> |
81 |
| - <input |
82 |
| - className="form__input" |
83 |
| - id="keyLabel" |
84 |
| - onChange={(event) => { |
85 |
| - this.setState({ keyLabel: event.target.value }); |
86 |
| - }} |
87 |
| - placeholder={this.props.t('APIKeyForm.TokenPlaceholder')} |
88 |
| - type="text" |
89 |
| - value={this.state.keyLabel} |
| 49 | + return <p>{t('APIKeyForm.NoTokens')}</p>; |
| 50 | + }; |
| 51 | + |
| 52 | + const keyWithToken = apiKeys.find((k) => !!k.token); |
| 53 | + |
| 54 | + return ( |
| 55 | + <div className="api-key-form"> |
| 56 | + <p className="api-key-form__summary">{t('APIKeyForm.Summary')}</p> |
| 57 | + |
| 58 | + <div className="api-key-form__section"> |
| 59 | + <h3 className="api-key-form__title">{t('APIKeyForm.CreateToken')}</h3> |
| 60 | + <form className="form form--inline" onSubmit={addKey}> |
| 61 | + <label |
| 62 | + htmlFor="keyLabel" |
| 63 | + className="form__label form__label--hidden " |
| 64 | + > |
| 65 | + {t('APIKeyForm.TokenLabel')} |
| 66 | + </label> |
| 67 | + <input |
| 68 | + className="form__input" |
| 69 | + id="keyLabel" |
| 70 | + onChange={(event) => { |
| 71 | + setKeyLabel(event.target.value); |
| 72 | + }} |
| 73 | + placeholder={t('APIKeyForm.TokenPlaceholder')} |
| 74 | + type="text" |
| 75 | + value={keyLabel} |
| 76 | + /> |
| 77 | + <Button |
| 78 | + disabled={keyLabel === ''} |
| 79 | + iconBefore={<PlusIcon />} |
| 80 | + label="Create new key" |
| 81 | + type="submit" |
| 82 | + > |
| 83 | + {t('APIKeyForm.CreateTokenSubmit')} |
| 84 | + </Button> |
| 85 | + </form> |
| 86 | + |
| 87 | + {keyWithToken && ( |
| 88 | + <div className="api-key-form__new-token"> |
| 89 | + <h4 className="api-key-form__new-token__title"> |
| 90 | + {t('APIKeyForm.NewTokenTitle')} |
| 91 | + </h4> |
| 92 | + <p className="api-key-form__new-token__info"> |
| 93 | + {t('APIKeyForm.NewTokenInfo')} |
| 94 | + </p> |
| 95 | + <CopyableInput |
| 96 | + label={keyWithToken.label} |
| 97 | + value={keyWithToken.token} |
90 | 98 | />
|
91 |
| - <Button |
92 |
| - disabled={this.state.keyLabel === ''} |
93 |
| - iconBefore={<PlusIcon />} |
94 |
| - label="Create new key" |
95 |
| - type="submit" |
96 |
| - > |
97 |
| - {this.props.t('APIKeyForm.CreateTokenSubmit')} |
98 |
| - </Button> |
99 |
| - </form> |
100 |
| - |
101 |
| - {keyWithToken && ( |
102 |
| - <div className="api-key-form__new-token"> |
103 |
| - <h4 className="api-key-form__new-token__title"> |
104 |
| - {this.props.t('APIKeyForm.NewTokenTitle')} |
105 |
| - </h4> |
106 |
| - <p className="api-key-form__new-token__info"> |
107 |
| - {this.props.t('APIKeyForm.NewTokenInfo')} |
108 |
| - </p> |
109 |
| - <CopyableInput |
110 |
| - label={keyWithToken.label} |
111 |
| - value={keyWithToken.token} |
112 |
| - /> |
113 |
| - </div> |
114 |
| - )} |
115 |
| - </div> |
116 |
| - |
117 |
| - <div className="api-key-form__section"> |
118 |
| - <h3 className="api-key-form__title"> |
119 |
| - {this.props.t('APIKeyForm.ExistingTokensTitle')} |
120 |
| - </h3> |
121 |
| - {this.renderApiKeys()} |
122 |
| - </div> |
| 99 | + </div> |
| 100 | + )} |
123 | 101 | </div>
|
124 |
| - ); |
125 |
| - } |
126 |
| -} |
127 | 102 |
|
128 |
| -APIKeyForm.propTypes = { |
129 |
| - apiKeys: PropTypes.arrayOf(PropTypes.shape(APIKeyPropType)).isRequired, |
130 |
| - createApiKey: PropTypes.func.isRequired, |
131 |
| - removeApiKey: PropTypes.func.isRequired, |
132 |
| - t: PropTypes.func.isRequired |
| 103 | + <div className="api-key-form__section"> |
| 104 | + <h3 className="api-key-form__title"> |
| 105 | + {t('APIKeyForm.ExistingTokensTitle')} |
| 106 | + </h3> |
| 107 | + {renderApiKeys()} |
| 108 | + </div> |
| 109 | + </div> |
| 110 | + ); |
133 | 111 | };
|
134 | 112 |
|
135 | 113 | export default APIKeyForm;
|
0 commit comments