diff --git a/ui/package-lock.json b/ui/package-lock.json
index aadea0922..98ef3e08c 100644
--- a/ui/package-lock.json
+++ b/ui/package-lock.json
@@ -4,15 +4,6 @@
"lockfileVersion": 1,
"requires": true,
"dependencies": {
- "@attently/riek": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/@attently/riek/-/riek-2.0.1.tgz",
- "integrity": "sha1-AFJ4WlurHKepkjbxNWJNOeZhkCQ=",
- "requires": {
- "debug": "^2.6.8",
- "prop-types": "^15.5.10"
- }
- },
"@babel/code-frame": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz",
diff --git a/ui/package.json b/ui/package.json
index 0ab6335c9..5485a687d 100644
--- a/ui/package.json
+++ b/ui/package.json
@@ -4,7 +4,6 @@
"license": "Apache-2.0",
"private": true,
"dependencies": {
- "@attently/riek": "2.0.1",
"@fortawesome/fontawesome-common-types": "0.2.28",
"@fortawesome/fontawesome-svg-core": "1.2.28",
"@fortawesome/free-regular-svg-icons": "5.13.0",
diff --git a/ui/src/Components/InlineEdit/index.js b/ui/src/Components/InlineEdit/index.js
new file mode 100644
index 000000000..9a01745b2
--- /dev/null
+++ b/ui/src/Components/InlineEdit/index.js
@@ -0,0 +1,87 @@
+import React, { useState, useRef, useEffect } from "react";
+import PropTypes from "prop-types";
+
+import { useOnClickOutside } from "Hooks/useOnClickOutside";
+
+const InlineEdit = ({
+ className,
+ classNameEditing,
+ value,
+ onChange,
+ onEnterEditing,
+ onExitEditing,
+}) => {
+ const ref = useRef(null);
+ const [editedValue, setEditedValue] = useState(null);
+ const [isEditing, setIsEditing] = useState(false);
+
+ const startEditing = () => {
+ if (onEnterEditing) {
+ onEnterEditing();
+ }
+ setIsEditing(true);
+ };
+
+ const doneEditing = () => {
+ setIsEditing(false);
+ setEditedValue(null);
+ if (onExitEditing) {
+ onExitEditing();
+ }
+ };
+
+ const onInput = (event) => {
+ setEditedValue(event.target.value.trim());
+ };
+
+ const onKeyDown = (event) => {
+ if (event.keyCode === 13) {
+ if (editedValue) {
+ onChange(editedValue);
+ }
+ doneEditing();
+ } else if (event.keyCode === 27) {
+ doneEditing();
+ }
+ };
+
+ useOnClickOutside(ref, doneEditing);
+
+ useEffect(() => {
+ if (isEditing && ref.current) {
+ ref.current.focus();
+ }
+ }, [isEditing, ref]);
+
+ if (isEditing) {
+ const val = editedValue === null ? value : editedValue;
+
+ return (
+
+ );
+ }
+
+ return (
+
+ {value}
+
+ );
+};
+InlineEdit.propTypes = {
+ className: PropTypes.string,
+ classNameEditing: PropTypes.string,
+ value: PropTypes.string.isRequired,
+ onChange: PropTypes.func.isRequired,
+ onEnterEditing: PropTypes.func,
+ onExitEditing: PropTypes.func,
+};
+
+export { InlineEdit };
diff --git a/ui/src/Components/InlineEdit/index.test.js b/ui/src/Components/InlineEdit/index.test.js
new file mode 100644
index 000000000..768bcb645
--- /dev/null
+++ b/ui/src/Components/InlineEdit/index.test.js
@@ -0,0 +1,141 @@
+import React from "react";
+import { act } from "react-dom/test-utils";
+
+import { mount } from "enzyme";
+
+import { InlineEdit } from ".";
+
+describe("