diff --git a/packages/dashboard-v2/src/components/Modal/index.js b/packages/dashboard-v2/src/components/Modal/index.js
index 28d34710..00ce01f6 100644
--- a/packages/dashboard-v2/src/components/Modal/index.js
+++ b/packages/dashboard-v2/src/components/Modal/index.js
@@ -1 +1,2 @@
export * from "./ModalPortal";
+export * from "./Modal";
diff --git a/packages/dashboard-v2/src/components/forms/AddAPIKeyForm.js b/packages/dashboard-v2/src/components/forms/AddAPIKeyForm.js
new file mode 100644
index 00000000..703d88a0
--- /dev/null
+++ b/packages/dashboard-v2/src/components/forms/AddAPIKeyForm.js
@@ -0,0 +1,114 @@
+import * as Yup from "yup";
+import { forwardRef, useImperativeHandle, useState } from "react";
+import PropTypes from "prop-types";
+import { Formik, Form } from "formik";
+
+import accountsService from "../../services/accountsService";
+
+import { Alert } from "../Alert";
+import { Button } from "../Button";
+import { CopyButton } from "../CopyButton";
+import { TextField } from "../Form/TextField";
+import { CircledProgressIcon, PlusIcon } from "../Icons";
+
+const newAPIKeySchema = Yup.object().shape({
+ name: Yup.string(),
+});
+
+const State = {
+ Pure: "PURE",
+ Success: "SUCCESS",
+ Failure: "FAILURE",
+};
+
+export const APIKeyType = {
+ Public: "public",
+ General: "general",
+};
+
+export const AddAPIKeyForm = forwardRef(({ onSuccess, type }, ref) => {
+ const [state, setState] = useState(State.Pure);
+ const [generatedKey, setGeneratedKey] = useState(null);
+
+ useImperativeHandle(ref, () => ({
+ reset: () => setState(State.Pure),
+ }));
+
+ return (
+
+ {state === State.Success && (
+
+ Success!
+ Please copy your new API key below. We'll never show it again!
+
+
+ {generatedKey}
+
+
+
+
+ )}
+ {state === State.Failure && (
+
We were not able to generate a new key. Please try again later.
+ )}
+
{
+ try {
+ const { key } = await accountsService
+ .post("user/apikeys", {
+ json: {
+ name,
+ public: type === APIKeyType.Public ? "true" : "false",
+ skylinks: type === APIKeyType.Public ? [] : null,
+ },
+ })
+ .json();
+
+ resetForm();
+ setGeneratedKey(key);
+ setState(State.Success);
+ onSuccess();
+ } catch {
+ setState(State.Failure);
+ }
+ }}
+ >
+ {({ errors, touched, isSubmitting }) => (
+
+ )}
+
+
+ );
+});
+
+AddAPIKeyForm.displayName = "AddAPIKeyForm";
+
+AddAPIKeyForm.propTypes = {
+ onSuccess: PropTypes.func.isRequired,
+ type: PropTypes.oneOf([APIKeyType.Public, APIKeyType.General]).isRequired,
+};
diff --git a/packages/dashboard-v2/src/components/forms/AddSkylinkToAPIKeyForm.js b/packages/dashboard-v2/src/components/forms/AddSkylinkToAPIKeyForm.js
new file mode 100644
index 00000000..fda27d36
--- /dev/null
+++ b/packages/dashboard-v2/src/components/forms/AddSkylinkToAPIKeyForm.js
@@ -0,0 +1,73 @@
+import * as Yup from "yup";
+import PropTypes from "prop-types";
+import { Formik, Form } from "formik";
+
+import accountsService from "../../services/accountsService";
+
+import { Button } from "../Button";
+import { TextField } from "../Form/TextField";
+import { CircledProgressIcon, PlusIcon } from "../Icons";
+
+const newSkylinkSchema = Yup.object().shape({
+ skylink: Yup.string().required("Provide a valid Skylink"), // TODO: Comprehensive Skylink validation
+});
+
+export const AddSkylinkToAPIKeyForm = ({ keyId, onSuccess, onFailure }) => (
+
{
+ try {
+ await accountsService
+ .patch(`user/apikeys/${keyId}`, {
+ json: {
+ add: [skylink],
+ },
+ })
+ .json();
+
+ resetForm();
+ onSuccess();
+ } catch (err) {
+ if (err.response) {
+ const { message } = await err.response.json();
+ onFailure(message);
+ } else {
+ onFailure("Unknown error occured, please try again.");
+ }
+ }
+ }}
+ >
+ {({ errors, touched, isSubmitting }) => (
+
+ )}
+
+);
+
+AddSkylinkToAPIKeyForm.propTypes = {
+ onFailure: PropTypes.func.isRequired,
+ onSuccess: PropTypes.func.isRequired,
+ keyId: PropTypes.string.isRequired,
+};
diff --git a/packages/dashboard-v2/src/pages/settings/api-keys.js b/packages/dashboard-v2/src/pages/settings/api-keys.js
index 8ed8b1c8..3cbefb17 100644
--- a/packages/dashboard-v2/src/pages/settings/api-keys.js
+++ b/packages/dashboard-v2/src/pages/settings/api-keys.js
@@ -1,63 +1,97 @@
import useSWR from "swr";
-import dayjs from "dayjs";
+import { useCallback, useRef } from "react";
import UserSettingsLayout from "../../layouts/UserSettingsLayout";
-import { TextInputBasic } from "../../components/TextInputBasic";
-import { Button } from "../../components/Button";
-import { TrashIcon } from "../../components/Icons";
+import { AddAPIKeyForm, APIKeyType } from "../../components/forms/AddAPIKeyForm";
+import { APIKeyList } from "../../components/APIKeyList/APIKeyList";
+import { Alert } from "../../components/Alert";
const APIKeysPage = () => {
- const { data: apiKeys } = useSWR("user/apikeys");
+ const { data: apiKeys = [], mutate: reloadKeys, error } = useSWR("user/apikeys");
+ const generalKeys = apiKeys.filter(({ public: isPublic }) => isPublic === "false");
+ const publicKeys = apiKeys.filter(({ public: isPublic }) => isPublic === "true");
+
+ const publicFormRef = useRef();
+ const generalFormRef = useRef();
+
+ const refreshState = useCallback(
+ (resetForms) => {
+ if (resetForms) {
+ publicFormRef.current?.reset();
+ generalFormRef.current?.reset();
+ }
+ reloadKeys();
+ },
+ [reloadKeys]
+ );
return (
<>
-
+
API Keys
-
- At vero eos et caritatem, quae sine metu contineret, saluti prospexit civium, qua. Laudem et dolorem
- aspernari ut ad naturam aut fu.
+
There are two types of API keys that you can generate for your account.
+
Make sure to use the appropriate type.
+
+
+
+
+
+ Public keys
+
+ Give read access to a selected list of Skylinks. You can share them publicly.
+
+
+
+ {error ? (
+
+ An error occurred while loading your API keys. Please try again later.
+
+ ) : (
+
+ {publicKeys?.length > 0 ? (
+
refreshState(true)} />
+ ) : (
+ No public API keys found.
+ )}
+
+ )}
-
-
-
-
-
-
+
+
+ General keys
+
+ Give full access to Accounts service and are equivalent to using a JWT token.
+
+ This type of API keys need to be kept secret and never shared with anyone.
+
+
+
+ {error ? (
+
+ An error occurred while loading your API keys. Please try again later.
+
+ ) : (
+
+ {generalKeys?.length > 0 ? (
+
refreshState(true)} />
+ ) : (
+ No general API keys found.
+ )}
+
+ )}
- {apiKeys?.length > 0 && (
-
- API Keys
-
- {apiKeys.map(({ id, name, createdAt }) => (
- -
- {name || id}
-
- {dayjs(createdAt).format("MMM DD, YYYY")}
-
-
-
-
- ))}
-
-
- )}
-
-
+
+
>
diff --git a/packages/dashboard-v2/tailwind.config.js b/packages/dashboard-v2/tailwind.config.js
index 076d6912..636cd40e 100644
--- a/packages/dashboard-v2/tailwind.config.js
+++ b/packages/dashboard-v2/tailwind.config.js
@@ -54,6 +54,7 @@ module.exports = {
wiggle: "wiggle 3s ease-in-out infinite",
},
width: {
+ modal: "500px",
page: "100%",
"page-md": "640px",
"page-lg": "896px",
@@ -64,6 +65,9 @@ module.exports = {
minWidth: {
button: "112px",
},
+ maxWidth: {
+ modal: "calc(100vw - 1rem)",
+ },
},
},
plugins: [