diff --git a/app/scenes/APITokenNew.js b/app/scenes/APITokenNew.js
new file mode 100644
index 000000000..e84282e58
--- /dev/null
+++ b/app/scenes/APITokenNew.js
@@ -0,0 +1,65 @@
+// @flow
+import * as React from "react";
+import { useTranslation, Trans } from "react-i18next";
+import Button from "components/Button";
+import Flex from "components/Flex";
+import HelpText from "components/HelpText";
+import Input from "components/Input";
+import useStores from "hooks/useStores";
+
+type Props = {|
+ onSubmit: () => void,
+|};
+
+function APITokenNew({ onSubmit }: Props) {
+ const [name, setName] = React.useState("");
+ const [isSaving, setIsSaving] = React.useState(false);
+ const { apiKeys, ui } = useStores();
+ const { t } = useTranslation();
+
+ const handleSubmit = React.useCallback(async () => {
+ setIsSaving(true);
+
+ try {
+ await apiKeys.create({ name });
+ ui.showToast(t("API token created", { type: "success" }));
+ onSubmit();
+ } catch (err) {
+ ui.showToast(err.message, { type: "error" });
+ } finally {
+ setIsSaving(false);
+ }
+ }, [t, ui, name, onSubmit, apiKeys]);
+
+ const handleNameChange = React.useCallback((event) => {
+ setName(event.target.value);
+ }, []);
+
+ return (
+
+ );
+}
+
+export default APITokenNew;
diff --git a/app/scenes/Settings/Groups.js b/app/scenes/Settings/Groups.js
index ff5cdef86..1a3fc2b71 100644
--- a/app/scenes/Settings/Groups.js
+++ b/app/scenes/Settings/Groups.js
@@ -4,6 +4,7 @@ import { PlusIcon, GroupIcon } from "outline-icons";
import * as React from "react";
import { useTranslation, Trans } from "react-i18next";
import GroupNew from "scenes/GroupNew";
+import { Action } from "components/Actions";
import Button from "components/Button";
import Empty from "components/Empty";
import GroupListItem from "components/GroupListItem";
@@ -33,25 +34,31 @@ function Groups() {
}, []);
return (
- }>
+ }
+ actions={
+ <>
+ {can.createGroup && (
+
+ }
+ >
+ {`${t("New group")}…`}
+
+
+ )}
+ >
+ }
+ >
{t("Groups")}
Groups can be used to organize and manage the people on your team.
-
- {can.createGroup && (
- }
- neutral
- >
- {`${t("New group")}…`}
-
- )}
-
{t("All groups")}
{
- @observable name: string = "";
+ const handleNewModalOpen = React.useCallback(() => {
+ setNewModalOpen(true);
+ }, []);
- componentDidMount() {
- this.props.apiKeys.fetchPage({ limit: 100 });
- }
+ const handleNewModalClose = React.useCallback(() => {
+ setNewModalOpen(false);
+ }, []);
- handleUpdate = (ev: SyntheticInputEvent<*>) => {
- this.name = ev.target.value;
- };
-
- handleSubmit = async (ev: SyntheticEvent<>) => {
- try {
- ev.preventDefault();
- await this.props.apiKeys.create({ name: this.name });
- this.name = "";
- } catch (error) {
- this.props.ui.showToast(error.message, { type: "error" });
- }
- };
-
- render() {
- const { apiKeys } = this.props;
- const hasApiKeys = apiKeys.orderedData.length > 0;
-
- return (
- }>
- API Tokens
-
- You can create an unlimited amount of personal tokens to authenticate
- with the API. For more details about the API take a look at the{" "}
-
- developer documentation
-
- .
-
-
- {hasApiKeys && (
-
- {apiKeys.orderedData.map((token) => (
- }
+ actions={
+ <>
+ {can.createApiKey && (
+
+
- ))}
-
- )}
+
+ )}
+ >
+ }
+ >
+ {t("API Tokens")}
+
+
+ ),
+ }}
+ />
+
-
-
- );
- }
+ {t("Tokens")}}
+ renderItem={(token) => (
+
+ )}
+ />
+
+
+
+
+
+ );
}
-export default inject("apiKeys", "ui")(Tokens);
+export default observer(Tokens);
diff --git a/app/scenes/Settings/components/TokenListItem.js b/app/scenes/Settings/components/TokenListItem.js
index 5f0a9660b..3fd91cb24 100644
--- a/app/scenes/Settings/components/TokenListItem.js
+++ b/app/scenes/Settings/components/TokenListItem.js
@@ -4,17 +4,20 @@ import ApiKey from "models/ApiKey";
import Button from "components/Button";
import ListItem from "components/List/Item";
-type Props = {
+type Props = {|
token: ApiKey,
onDelete: (tokenId: string) => Promise,
-};
+|};
const TokenListItem = ({ token, onDelete }: Props) => {
return (
{token.secret}}
+ title={
+ <>
+ {token.name} – {token.secret}
+ >
+ }
actions={