wu981526092 commited on
Commit
48b8905
·
1 Parent(s): 032c9f9

Implement One-Time Privacy Notice Modal for HF Spaces - Replace persistent banner with elegant popup that shows once per user

Browse files
frontend/src/components/layout/MainWorkspace.tsx CHANGED
@@ -16,7 +16,7 @@ import { ConnectionsView } from "../features/connections/ConnectionsView";
16
  import { UploadView } from "../features/upload/UploadView";
17
  import { Button } from "@/components/ui/button";
18
  import { ArrowLeft } from "lucide-react";
19
- import { IS_HF_SPACES } from "@/lib/config";
20
 
21
  interface MainWorkspaceProps {
22
  isSidebarCollapsed: boolean;
@@ -330,6 +330,9 @@ export function MainWorkspace({
330
  <div className="fixed inset-0 bg-background z-50 flex flex-col">
331
  {/* Global Floating Action Widget for temporal view */}
332
  <FloatingActionWidget />
 
 
 
333
 
334
  {/* Breadcrumb Navigation */}
335
  <div className="border-b bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60">
@@ -392,17 +395,8 @@ export function MainWorkspace({
392
  </div>
393
  )}
394
 
395
- {/* HF Spaces Privacy Notice */}
396
- {IS_HF_SPACES && (
397
- <div className="bg-amber-50 border-b border-amber-200 px-6 py-3 text-sm text-amber-800 flex items-center gap-2">
398
- <span className="text-amber-600">🔒</span>
399
- <span>
400
- <strong>Privacy Notice:</strong> You're using AgentGraph on Hugging Face Spaces.
401
- Your data is stored in a temporary session and will be cleared when the container restarts.
402
- Data is not shared between users or sessions.
403
- </span>
404
- </div>
405
- )}
406
 
407
  {/* Main Content */}
408
  <div className="flex-1 flex flex-col min-h-0">{renderView()}</div>
 
16
  import { UploadView } from "../features/upload/UploadView";
17
  import { Button } from "@/components/ui/button";
18
  import { ArrowLeft } from "lucide-react";
19
+ import { PrivacyNoticeModal } from "@/components/shared/modals/PrivacyNoticeModal";
20
 
21
  interface MainWorkspaceProps {
22
  isSidebarCollapsed: boolean;
 
330
  <div className="fixed inset-0 bg-background z-50 flex flex-col">
331
  {/* Global Floating Action Widget for temporal view */}
332
  <FloatingActionWidget />
333
+
334
+ {/* Privacy Notice Modal */}
335
+ <PrivacyNoticeModal />
336
 
337
  {/* Breadcrumb Navigation */}
338
  <div className="border-b bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60">
 
395
  </div>
396
  )}
397
 
398
+ {/* Privacy Notice Modal */}
399
+ <PrivacyNoticeModal />
 
 
 
 
 
 
 
 
 
400
 
401
  {/* Main Content */}
402
  <div className="flex-1 flex flex-col min-h-0">{renderView()}</div>
frontend/src/components/shared/modals/PrivacyNoticeModal.tsx ADDED
@@ -0,0 +1,105 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React, { useState, useEffect } from "react";
2
+ import {
3
+ Dialog,
4
+ DialogContent,
5
+ DialogDescription,
6
+ DialogFooter,
7
+ DialogHeader,
8
+ DialogTitle,
9
+ } from "@/components/ui/dialog";
10
+ import { Button } from "@/components/ui/button";
11
+ import { Shield, Info, Database, RefreshCw } from "lucide-react";
12
+ import { IS_HF_SPACES } from "@/lib/config";
13
+
14
+ const PRIVACY_NOTICE_KEY = "agentgraph_privacy_notice_seen";
15
+
16
+ export function PrivacyNoticeModal() {
17
+ const [isOpen, setIsOpen] = useState(false);
18
+
19
+ useEffect(() => {
20
+ // Only show on HF Spaces and if not seen before
21
+ if (IS_HF_SPACES) {
22
+ const hasSeenNotice = localStorage.getItem(PRIVACY_NOTICE_KEY);
23
+ if (!hasSeenNotice) {
24
+ // Show modal after a short delay to ensure the app is loaded
25
+ const timer = setTimeout(() => {
26
+ setIsOpen(true);
27
+ }, 1000);
28
+ return () => clearTimeout(timer);
29
+ }
30
+ }
31
+ }, []);
32
+
33
+ const handleAccept = () => {
34
+ localStorage.setItem(PRIVACY_NOTICE_KEY, "true");
35
+ setIsOpen(false);
36
+ };
37
+
38
+ const handleDismiss = () => {
39
+ // Don't set localStorage, so it shows again next time
40
+ setIsOpen(false);
41
+ };
42
+
43
+ // Don't render anything if not on HF Spaces
44
+ if (!IS_HF_SPACES) {
45
+ return null;
46
+ }
47
+
48
+ return (
49
+ <Dialog open={isOpen} onOpenChange={setIsOpen}>
50
+ <DialogContent className="sm:max-w-[500px]">
51
+ <DialogHeader>
52
+ <DialogTitle className="flex items-center gap-2 text-lg">
53
+ <Shield className="h-5 w-5 text-blue-600" />
54
+ Privacy Notice - Hugging Face Spaces
55
+ </DialogTitle>
56
+ <DialogDescription className="text-left space-y-3 pt-2">
57
+ <div className="flex items-start gap-3">
58
+ <Database className="h-4 w-4 text-amber-600 mt-0.5 flex-shrink-0" />
59
+ <div className="text-sm">
60
+ <strong>Temporary Data Storage:</strong> Your data is stored in a private, temporary session that is automatically cleared when the container restarts.
61
+ </div>
62
+ </div>
63
+
64
+ <div className="flex items-start gap-3">
65
+ <Shield className="h-4 w-4 text-green-600 mt-0.5 flex-shrink-0" />
66
+ <div className="text-sm">
67
+ <strong>Complete Privacy:</strong> Your traces and analysis results are not shared between users or sessions. Each user has their own isolated environment.
68
+ </div>
69
+ </div>
70
+
71
+ <div className="flex items-start gap-3">
72
+ <RefreshCw className="h-4 w-4 text-blue-600 mt-0.5 flex-shrink-0" />
73
+ <div className="text-sm">
74
+ <strong>Data Lifecycle:</strong> All uploaded traces, knowledge graphs, and analysis results will be permanently deleted when the Hugging Face Spaces container restarts.
75
+ </div>
76
+ </div>
77
+
78
+ <div className="flex items-start gap-3">
79
+ <Info className="h-4 w-4 text-gray-600 mt-0.5 flex-shrink-0" />
80
+ <div className="text-sm">
81
+ <strong>Recommendation:</strong> For persistent data storage and analysis, consider running AgentGraph locally or on your own infrastructure.
82
+ </div>
83
+ </div>
84
+ </DialogDescription>
85
+ </DialogHeader>
86
+
87
+ <DialogFooter className="flex gap-2 sm:gap-2">
88
+ <Button
89
+ variant="outline"
90
+ onClick={handleDismiss}
91
+ className="flex-1"
92
+ >
93
+ Remind Me Later
94
+ </Button>
95
+ <Button
96
+ onClick={handleAccept}
97
+ className="flex-1 bg-blue-600 hover:bg-blue-700"
98
+ >
99
+ I Understand
100
+ </Button>
101
+ </DialogFooter>
102
+ </DialogContent>
103
+ </Dialog>
104
+ );
105
+ }
frontend/src/lib/config.ts CHANGED
@@ -28,10 +28,12 @@ export const API_BASE = getApiBase();
28
  // Check if running on Hugging Face Spaces
29
  export const isHuggingFaceSpaces = () => {
30
  if (typeof window === "undefined") return false;
31
-
32
- return window.location.hostname.includes("huggingface.co") ||
33
- window.location.hostname.includes("hf.space") ||
34
- window.location.hostname.endsWith(".hf.space");
 
 
35
  };
36
 
37
  export const IS_HF_SPACES = isHuggingFaceSpaces();
 
28
  // Check if running on Hugging Face Spaces
29
  export const isHuggingFaceSpaces = () => {
30
  if (typeof window === "undefined") return false;
31
+
32
+ return (
33
+ window.location.hostname.includes("huggingface.co") ||
34
+ window.location.hostname.includes("hf.space") ||
35
+ window.location.hostname.endsWith(".hf.space")
36
+ );
37
  };
38
 
39
  export const IS_HF_SPACES = isHuggingFaceSpaces();