diff --git a/frontend/scenes/Settings/Settings.js b/frontend/scenes/Settings/Settings.js
index dda64d68e..8b75a4c9c 100644
--- a/frontend/scenes/Settings/Settings.js
+++ b/frontend/scenes/Settings/Settings.js
@@ -6,6 +6,7 @@ import { Input, ButtonOutline, InlineForm } from 'rebass';
import Layout, { Title } from 'components/Layout';
import CenteredContent from 'components/CenteredContent';
import SlackAuthLink from 'components/SlackAuthLink';
+import ApiKeyRow from './components/ApiKeyRow';
import styles from './Settings.scss';
@@ -65,13 +66,12 @@ class Settings extends React.Component {
{ this.store.apiKeys && (
{ this.store.apiKeys.map(key => (
-
- | { key.name } |
- { key.secret } |
- {/*
- Delete
- | */}
-
+
)) }
) }
diff --git a/frontend/scenes/Settings/Settings.scss b/frontend/scenes/Settings/Settings.scss
index 64f268ed4..20a48ff8a 100644
--- a/frontend/scenes/Settings/Settings.scss
+++ b/frontend/scenes/Settings/Settings.scss
@@ -17,9 +17,3 @@
color: #969696;
}
}
-
-.deleteAction {
- font-size: 14px;
- cursor: pointer;
- color: $textColor;
-}
diff --git a/frontend/scenes/Settings/SettingsStore.js b/frontend/scenes/Settings/SettingsStore.js
index 67b9940c3..4f96050be 100644
--- a/frontend/scenes/Settings/SettingsStore.js
+++ b/frontend/scenes/Settings/SettingsStore.js
@@ -40,6 +40,22 @@ class SearchStore {
this.isFetching = false;
}
+ @action deleteApiKey = async (id) => {
+ this.isFetching = true;
+
+ try {
+ await client.post('/apiKeys.delete', {
+ id,
+ });
+ runInAction('deleteApiKey', () => {
+ this.fetchApiKeys();
+ });
+ } catch (e) {
+ console.error("Something went wrong");
+ }
+ this.isFetching = false;
+ }
+
@action setKeyName = (value) => {
this.keyName = value.target.value;
}
diff --git a/frontend/scenes/Settings/components/ApiKeyRow/ApiKeyRow.js b/frontend/scenes/Settings/components/ApiKeyRow/ApiKeyRow.js
new file mode 100644
index 000000000..7d21ab8df
--- /dev/null
+++ b/frontend/scenes/Settings/components/ApiKeyRow/ApiKeyRow.js
@@ -0,0 +1,50 @@
+import React, { PropTypes } from 'react';
+
+import styles from './ApiKeyRow.scss';
+import classNames from 'classnames/bind';
+const cx = classNames.bind(styles);
+
+class ApiKeyRow extends React.Component {
+ static propTypes = {
+ id: PropTypes.string.isRequired,
+ name: PropTypes.string.isRequired,
+ secret: PropTypes.string.isRequired,
+ onDelete: PropTypes.func.isRequired,
+ }
+
+ state = {
+ disabled: false,
+ }
+
+ onClick = () => {
+ this.props.onDelete(this.props.id);
+ this.setState({ disabled: true });
+ }
+
+ render() {
+ const {
+ name,
+ secret,
+ } = this.props;
+
+ const {
+ disabled,
+ } = this.state;
+
+ return (
+
+ | { name } |
+ { secret } |
+
+ Delete
+ |
+
+ );
+ }
+}
+
+export default ApiKeyRow;
diff --git a/frontend/scenes/Settings/components/ApiKeyRow/ApiKeyRow.scss b/frontend/scenes/Settings/components/ApiKeyRow/ApiKeyRow.scss
new file mode 100644
index 000000000..18496088d
--- /dev/null
+++ b/frontend/scenes/Settings/components/ApiKeyRow/ApiKeyRow.scss
@@ -0,0 +1,10 @@
+@import '~styles/constants.scss';
+
+.deleteAction {
+ font-size: 14px;
+ color: $textColor;
+}
+
+.disabled {
+ opacity: 0.5;
+}
diff --git a/frontend/scenes/Settings/components/ApiKeyRow/index.js b/frontend/scenes/Settings/components/ApiKeyRow/index.js
new file mode 100644
index 000000000..5a4a1f59a
--- /dev/null
+++ b/frontend/scenes/Settings/components/ApiKeyRow/index.js
@@ -0,0 +1,2 @@
+import ApiKeyRow from './ApiKeyRow';
+export default ApiKeyRow;
diff --git a/frontend/styles/base.scss b/frontend/styles/base.scss
index 50ab3a658..9221a07cc 100644
--- a/frontend/styles/base.scss
+++ b/frontend/styles/base.scss
@@ -93,6 +93,9 @@ hr {
border-bottom-style: solid;
border-bottom-color: #ccc;
}
+*[role=button] {
+ cursor: pointer;
+}
:global {
.hljs {
diff --git a/server/api/apiKeys.js b/server/api/apiKeys.js
index efafe6164..1dda17fc2 100644
--- a/server/api/apiKeys.js
+++ b/server/api/apiKeys.js
@@ -50,4 +50,27 @@ router.post('apiKeys.list', auth(), pagination(), async (ctx) => {
};
});
+router.post('apiKeys.delete', auth(), async (ctx) => {
+ const {
+ id,
+ } = ctx.body;
+ ctx.assertPresent(id, 'id is required');
+
+ const user = ctx.state.user;
+ const key = await ApiKey.findById(id);
+
+ if (!key || key.userId !== user.id) throw httpErrors.BadRequest();
+
+ // Delete the actual document
+ try {
+ await key.destroy();
+ } catch (e) {
+ throw httpErrors.BadRequest('Error while deleting key');
+ }
+
+ ctx.body = {
+ success: true,
+ };
+});
+
export default router;
diff --git a/server/api/documents.js b/server/api/documents.js
index f528bfe0e..5b4e15fb7 100644
--- a/server/api/documents.js
+++ b/server/api/documents.js
@@ -232,7 +232,7 @@ router.post('documents.delete', auth(), async (ctx) => {
}
ctx.body = {
- ok: true,
+ success: true,
};
});