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
)}
+