From 3c4b1e6974e899553a005d800ef717740f079480 Mon Sep 17 00:00:00 2001 From: Brad Harris Date: Thu, 8 Dec 2022 16:52:31 +0000 Subject: [PATCH 1/3] Adding a tooltip w/ full expiration date --- components/dashboard/src/settings/TokenEntry.tsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/components/dashboard/src/settings/TokenEntry.tsx b/components/dashboard/src/settings/TokenEntry.tsx index 4127811526317b..a98150f831f1f2 100644 --- a/components/dashboard/src/settings/TokenEntry.tsx +++ b/components/dashboard/src/settings/TokenEntry.tsx @@ -8,6 +8,7 @@ import { PersonalAccessToken } from "@gitpod/public-api/lib/gitpod/experimental/ import dayjs from "dayjs"; import { ContextMenuEntry } from "../components/ContextMenu"; import { ItemFieldContextMenu } from "../components/ItemsList"; +import Tooltip from "../components/Tooltip"; import { ReactComponent as ExclamationIcon } from "../images/exclamation.svg"; import { AllPermissions } from "./PersonalAccessTokens"; @@ -19,6 +20,7 @@ interface TokenEntryProps { function TokenEntry(props: TokenEntryProps) { const expirationDay = dayjs(props.token.expirationTime!.toDate()); const expired = expirationDay.isBefore(dayjs()); + const expirationDateString = expirationDay.format("MMM D, YYYY, hh:mm A"); const getScopes = () => { if (!props.token.scopes) { @@ -44,7 +46,11 @@ function TokenEntry(props: TokenEntryProps) {
{expirationDay.format("MMM D, YYYY")} - {expired && } + {expired && ( + + + + )}
From a3eeafa0e93ac649ace4edea965782b59506d515 Mon Sep 17 00:00:00 2001 From: Brad Harris Date: Fri, 9 Dec 2022 01:50:06 +0000 Subject: [PATCH 2/3] removing fragment --- .../dashboard/src/settings/TokenEntry.tsx | 42 +++++++++---------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/components/dashboard/src/settings/TokenEntry.tsx b/components/dashboard/src/settings/TokenEntry.tsx index a98150f831f1f2..7d2aa129ae7a59 100644 --- a/components/dashboard/src/settings/TokenEntry.tsx +++ b/components/dashboard/src/settings/TokenEntry.tsx @@ -35,29 +35,27 @@ function TokenEntry(props: TokenEntryProps) { }; return ( - <> -
-
- {props.token.name || ""} -
-
- {getScopes()} -
-
- - {expirationDay.format("MMM D, YYYY")} - {expired && ( - - - - )} - -
-
- -
+
+
+ {props.token.name || ""}
- +
+ {getScopes()} +
+
+ + {expirationDay.format("MMM D, YYYY")} + {expired && ( + + + + )} + +
+
+ +
+
); } From 7ec92c0eee653e314ce6c0f613774a10f2838f5e Mon Sep 17 00:00:00 2001 From: Brad Harris Date: Fri, 9 Dec 2022 01:51:18 +0000 Subject: [PATCH 3/3] Updating Tooltip positioning --- components/dashboard/package.json | 3 ++ .../dashboard/src/components/Tooltip.tsx | 42 +++++++++++++------ yarn.lock | 18 +++++++- 3 files changed, 49 insertions(+), 14 deletions(-) diff --git a/components/dashboard/package.json b/components/dashboard/package.json index 654f61951752d2..aa89d3b5f11fd2 100644 --- a/components/dashboard/package.json +++ b/components/dashboard/package.json @@ -21,6 +21,8 @@ "react-datepicker": "^4.8.0", "react-dom": "^17.0.1", "react-intl-tel-input": "^8.2.0", + "react-popper": "^2.3.0", + "react-portal": "^4.2.2", "react-router-dom": "^5.2.0", "xterm": "^4.11.0", "xterm-addon-fit": "^0.5.0" @@ -38,6 +40,7 @@ "@types/node": "^16.11.0", "@types/react": "^17.0.0", "@types/react-dom": "^17.0.3", + "@types/react-portal": "^4.0.4", "@types/react-router": "^5.1.13", "@types/react-router-dom": "^5.1.7", "@types/uuid": "^8.3.1", diff --git a/components/dashboard/src/components/Tooltip.tsx b/components/dashboard/src/components/Tooltip.tsx index 3aa0bd0c1e6277..9003f295976185 100644 --- a/components/dashboard/src/components/Tooltip.tsx +++ b/components/dashboard/src/components/Tooltip.tsx @@ -4,30 +4,48 @@ * See License-AGPL.txt in the project root for license information. */ -import { useState } from "react"; +import { ReactNode, useEffect, useState } from "react"; +import { Portal } from "react-portal"; +import { usePopper } from "react-popper"; export interface TooltipProps { - children: React.ReactChild[] | React.ReactChild; + children: ReactNode; content: string; allowWrap?: boolean; } function Tooltip(props: TooltipProps) { const [expanded, setExpanded] = useState(false); + const [triggerEl, setTriggerEl] = useState(null); + const [tooltipEl, setTooltipEl] = useState(null); + + // this calculates the positioning for our tooltip + const { styles, attributes, update } = usePopper(triggerEl, tooltipEl, { + placement: "top", + }); + + // If the tooltip contents change, force a recalc on positioning + useEffect(() => { + update && update(); + }, [update, props.content]); return (
setExpanded(false)} onMouseEnter={() => setExpanded(true)} className="relative"> -
{props.children}
+
{props.children}
{expanded ? ( -
- {props.content} -
+ +
+ {props.content} +
+
) : null}
); diff --git a/yarn.lock b/yarn.lock index 78bdb54ffc8429..c0be8e35150fde 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3188,6 +3188,13 @@ dependencies: "@types/react" "*" +"@types/react-portal@^4.0.4": + version "4.0.4" + resolved "https://registry.yarnpkg.com/@types/react-portal/-/react-portal-4.0.4.tgz#1c0e5a248f6e18a66f981139c13b6e796f4a92b6" + integrity sha512-ecVWngYHeSymq5XdrQOXRpIb9ay5SM4Stm/ur6+wc0Z+r05gafZ5SuMRbXKYsj4exNJa+4CTKK6J7qcTKm9K5g== + dependencies: + "@types/react" "*" + "@types/react-router-dom@^5.1.7": version "5.3.2" resolved "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.3.2.tgz" @@ -14572,7 +14579,7 @@ prompts@^2.0.1: kleur "^3.0.3" sisteransi "^1.0.5" -prop-types@^15.5.4, prop-types@^15.6.1: +prop-types@^15.5.4, prop-types@^15.5.8, prop-types@^15.6.1: version "15.8.1" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== @@ -15039,7 +15046,7 @@ react-onclickoutside@^6.12.0: resolved "https://registry.yarnpkg.com/react-onclickoutside/-/react-onclickoutside-6.12.2.tgz#8e6cf80c7d17a79f2c908399918158a7b02dda01" integrity sha512-NMXGa223OnsrGVp5dJHkuKxQ4czdLmXSp5jSV9OqiCky9LOpPATn3vLldc+q5fK3gKbEHvr7J1u0yhBh/xYkpA== -react-popper@^2.2.5: +react-popper@^2.2.5, react-popper@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/react-popper/-/react-popper-2.3.0.tgz#17891c620e1320dce318bad9fede46a5f71c70ba" integrity sha512-e1hj8lL3uM+sgSR4Lxzn5h1GxBlpa4CQz0XLF8kx4MDrDRWY0Ena4c97PUeSX9i5W3UAfDP0z0FXCTQkoXUl3Q== @@ -15047,6 +15054,13 @@ react-popper@^2.2.5: react-fast-compare "^3.0.1" warning "^4.0.2" +react-portal@^4.2.2: + version "4.2.2" + resolved "https://registry.yarnpkg.com/react-portal/-/react-portal-4.2.2.tgz#bff1e024147d6041ba8c530ffc99d4c8248f49fa" + integrity sha512-vS18idTmevQxyQpnde0Td6ZcUlv+pD8GTyR42n3CHUQq9OHi1C4jDE4ZWEbEsrbrLRhSECYiao58cvocwMtP7Q== + dependencies: + prop-types "^15.5.8" + react-refresh@^0.8.3: version "0.8.3" resolved "https://registry.npmjs.org/react-refresh/-/react-refresh-0.8.3.tgz"