diff --git a/packages/replay-next/components/Icon.tsx b/packages/replay-next/components/Icon.tsx index 2f4b5507223..4d5c8b9fa2b 100644 --- a/packages/replay-next/components/Icon.tsx +++ b/packages/replay-next/components/Icon.tsx @@ -45,7 +45,6 @@ export type IconType = | "folder-open" | "hide" | "inspect" - | "invisible" | "invoke-getter" | "log-point-panel-arrow-above" | "log-point-panel-arrow-below" @@ -91,7 +90,9 @@ export type IconType = | "view-component-source" | "view-function-source" | "view-html-element" - | "visible" + | "visibility-private" + | "visibility-public" + | "visibility-team" | "warning" | "whole-word" | "regex"; @@ -305,10 +306,6 @@ export default function Icon({ ); break; - case "invisible": - path = - "M12 7c2.76 0 5 2.24 5 5 0 .65-.13 1.26-.36 1.83l2.92 2.92c1.51-1.26 2.7-2.89 3.43-4.75-1.73-4.39-6-7.5-11-7.5-1.4 0-2.74.25-3.98.7l2.16 2.16C10.74 7.13 11.35 7 12 7zM2 4.27l2.28 2.28.46.46C3.08 8.3 1.78 10.02 1 12c1.73 4.39 6 7.5 11 7.5 1.55 0 3.03-.3 4.38-.84l.42.42L19.73 22 21 20.73 3.27 3 2 4.27zM7.53 9.8l1.55 1.55c-.05.21-.08.43-.08.65 0 1.66 1.34 3 3 3 .22 0 .44-.03.65-.08l1.55 1.55c-.67.33-1.41.53-2.2.53-2.76 0-5-2.24-5-5 0-.79.2-1.53.53-2.2zm4.31-.78l3.15 3.15.02-.16c0-1.66-1.34-3-3-3l-.17.01z"; - break; case "invoke-getter": path = ( <> @@ -680,9 +677,29 @@ export default function Icon({ path = "M5 15H3v4c0 1.1.9 2 2 2h4v-2H5v-4zM5 5h4V3H5c-1.1 0-2 .9-2 2v4h2V5zm14-2h-4v2h4v4h2V5c0-1.1-.9-2-2-2zm0 16h-4v2h4c1.1 0 2-.9 2-2v-4h-2v4zM12 9c-1.66 0-3 1.34-3 3s1.34 3 3 3 3-1.34 3-3-1.34-3-3-3z"; break; - case "visible": + case "visibility-private": path = - "M12 4.5C7 4.5 2.73 7.61 1 12c1.73 4.39 6 7.5 11 7.5s9.27-3.11 11-7.5c-1.73-4.39-6-7.5-11-7.5zM12 17c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5-2.24 5-5 5zm0-8c-1.66 0-3 1.34-3 3s1.34 3 3 3 3-1.34 3-3-1.34-3-3-3z"; + "M18 8h-1V6c0-2.76-2.24-5-5-5S7 3.24 7 6v2H6c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V10c0-1.1-.9-2-2-2zm-6 9c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2zm3.1-9H8.9V6c0-1.71 1.39-3.1 3.1-3.1 1.71 0 3.1 1.39 3.1 3.1v2z"; + break; + case "visibility-public": + path = + "M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 17.93c-3.95-.49-7-3.85-7-7.93 0-.62.08-1.21.21-1.79L9 15v1c0 1.1.9 2 2 2v1.93zm6.9-2.54c-.26-.81-1-1.39-1.9-1.39h-1v-3c0-.55-.45-1-1-1H8v-2h2c.55 0 1-.45 1-1V7h2c1.1 0 2-.9 2-2v-.41c2.93 1.19 5 4.06 5 7.41 0 2.08-.8 3.97-2.1 5.39z"; + break; + case "visibility-team": + path = ( + + + + + + + ); break; case "warning": path = "M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z"; diff --git a/src/ui/components/Header/Header.module.css b/src/ui/components/Header/Header.module.css index a48ea10c4ae..6b2c45ea059 100644 --- a/src/ui/components/Header/Header.module.css +++ b/src/ui/components/Header/Header.module.css @@ -57,3 +57,26 @@ transform: rotate(180deg); margin: 2px 2px 0 6px; } + +.VisibilityIcon { + width: 1rem; + height: 1rem; +} + +.VisibilityIconAndText { + flex-shrink: 0; + display: flex; + flex-direction: row; + align-items: center; + gap: 1ch; + font-size: var(--font-size-regular); + background-color: var(--body-bgcolor); + border-radius: 1rem; + overflow: hidden; + padding: 0.25rem 0.5rem; + cursor: pointer; +} + +.VisibilityIconAndText:hover { + background-color: var(--title-hover-bgcolor); +} diff --git a/src/ui/components/Header/Header.tsx b/src/ui/components/Header/Header.tsx index 12d1c538a91..f530a16ca57 100644 --- a/src/ui/components/Header/Header.tsx +++ b/src/ui/components/Header/Header.tsx @@ -4,10 +4,12 @@ import classNames from "classnames"; import { useRouter } from "next/router"; import { ClipboardEvent, KeyboardEvent, useLayoutEffect, useRef, useState } from "react"; +import Icon, { IconType } from "replay-next/components/Icon"; +import { useNag } from "replay-next/src/hooks/useNag"; import { RecordingTarget } from "replay-next/src/suspense/BuildIdCache"; -import { Recording } from "shared/graphql/types"; +import { Nag, Recording } from "shared/graphql/types"; import { selectAll } from "shared/utils/selection"; -import { getAccessToken, getRecordingTarget } from "ui/actions/app"; +import { getAccessToken, getRecordingTarget, setModal } from "ui/actions/app"; import Avatar from "ui/components/Avatar"; import UserOptions from "ui/components/Header/UserOptions"; import ViewToggle, { shouldShowDevToolsNag } from "ui/components/Header/ViewToggle"; @@ -15,7 +17,7 @@ import IconWithTooltip from "ui/components/shared/IconWithTooltip"; import hooks from "ui/hooks"; import { useGetActiveSessions } from "ui/hooks/sessions"; import { getViewMode } from "ui/reducers/layout"; -import { useAppSelector } from "ui/setup/hooks"; +import { useAppDispatch, useAppSelector } from "ui/setup/hooks"; import { trackEvent } from "ui/utils/telemetry"; import { isTestSuiteReplay } from "../TestSuite/utils/isTestSuiteReplay"; @@ -169,9 +171,13 @@ export default function Header() { const recordingTarget = useAppSelector(getRecordingTarget); const isAuthenticated = !!useAppSelector(getAccessToken); const recordingId = hooks.useGetRecordingId(); - const { recording, loading } = hooks.useGetRecording(recordingId); + const { loading, recording } = hooks.useGetRecording(recordingId); const backIcon =
; + const dispatch = useAppDispatch(); + + const [, dismissShareNag] = useNag(Nag.SHARE); // Properly call useNag and destructure dismissShareNag + if (loading) { return
; } @@ -197,6 +203,25 @@ export default function Header() { } } + let iconType: IconType; + let visibilityLabel: string; + if (!recording.private) { + iconType = "visibility-public"; + visibilityLabel = "Public"; + } else if (recording.workspace) { + iconType = "visibility-team"; + visibilityLabel = "Team"; + } else { + iconType = "visibility-private"; + visibilityLabel = "Private"; + } + + const onClick = () => { + trackEvent("header.open_share"); + dismissShareNag(); + dispatch(setModal("sharing", { recordingId: recordingId! })); + }; + return (
@@ -210,6 +235,9 @@ export default function Header() { ) : (
Recordings
)} +