@memori.ai/memori-react 8.4.1 → 8.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +21 -0
- package/dist/components/LoginDrawer/LoginDrawer.d.ts +1 -2
- package/dist/components/LoginDrawer/LoginDrawer.js +2 -105
- package/dist/components/LoginDrawer/LoginDrawer.js.map +1 -1
- package/dist/components/MemoriArtifactSystem/components/ArtifactActions/ArtifactActions.css +0 -4
- package/dist/components/MemoriArtifactSystem/components/ArtifactActions/ArtifactActions.d.ts +1 -0
- package/dist/components/MemoriArtifactSystem/components/ArtifactActions/ArtifactActions.js +3 -3
- package/dist/components/MemoriArtifactSystem/components/ArtifactActions/ArtifactActions.js.map +1 -1
- package/dist/components/MemoriArtifactSystem/components/ArtifactActions/components/CopyButtonWithDropdown.js +110 -8
- package/dist/components/MemoriArtifactSystem/components/ArtifactActions/components/CopyButtonWithDropdown.js.map +1 -1
- package/dist/components/MemoriArtifactSystem/components/ArtifactActions/components/CopyMenuItem.js +3 -0
- package/dist/components/MemoriArtifactSystem/components/ArtifactActions/components/CopyMenuItem.js.map +1 -1
- package/dist/components/MemoriArtifactSystem/components/ArtifactActions/hooks/useCopyArtifact.js +42 -38
- package/dist/components/MemoriArtifactSystem/components/ArtifactActions/hooks/useCopyArtifact.js.map +1 -1
- package/dist/components/MemoriArtifactSystem/components/ArtifactActions/styles.css +1 -2
- package/dist/components/MemoriArtifactSystem/components/ArtifactActions/types.d.ts +2 -1
- package/dist/components/MemoriArtifactSystem/components/ArtifactDrawer/ArtifactDrawer.css +428 -15
- package/dist/components/MemoriArtifactSystem/components/ArtifactDrawer/ArtifactDrawer.d.ts +1 -0
- package/dist/components/MemoriArtifactSystem/components/ArtifactDrawer/ArtifactDrawer.js +47 -8
- package/dist/components/MemoriArtifactSystem/components/ArtifactDrawer/ArtifactDrawer.js.map +1 -1
- package/dist/components/MemoriArtifactSystem/components/ArtifactDrawer/components/TabSwitch.css +150 -0
- package/dist/components/MemoriArtifactSystem/components/ArtifactDrawer/components/TabSwitch.d.ts +9 -0
- package/dist/components/MemoriArtifactSystem/components/ArtifactDrawer/components/TabSwitch.js +35 -0
- package/dist/components/MemoriArtifactSystem/components/ArtifactDrawer/components/TabSwitch.js.map +1 -0
- package/dist/components/MemoriArtifactSystem/components/ArtifactHandler/ArtifactHandler.css +2 -0
- package/dist/components/MemoriArtifactSystem/components/ArtifactPreview/ArtifactPreview.css +1 -1
- package/dist/components/MemoriArtifactSystem/components/ArtifactPreview/ArtifactPreview.d.ts +2 -1
- package/dist/components/MemoriArtifactSystem/components/ArtifactPreview/ArtifactPreview.js +15 -26
- package/dist/components/MemoriArtifactSystem/components/ArtifactPreview/ArtifactPreview.js.map +1 -1
- package/dist/components/MemoriArtifactSystem/context/ArtifactContext.js +1 -5
- package/dist/components/MemoriArtifactSystem/context/ArtifactContext.js.map +1 -1
- package/dist/components/MemoriWidget/MemoriWidget.js +1 -1
- package/dist/components/MemoriWidget/MemoriWidget.js.map +1 -1
- package/dist/components/icons/Close.d.ts +2 -1
- package/dist/components/icons/Close.js +1 -1
- package/dist/components/icons/Close.js.map +1 -1
- package/dist/components/icons/MenuVertical.d.ts +7 -0
- package/dist/components/icons/MenuVertical.js +6 -0
- package/dist/components/icons/MenuVertical.js.map +1 -0
- package/dist/components/layouts/Chat.js +1 -1
- package/dist/components/layouts/Chat.js.map +1 -1
- package/dist/components/layouts/FullPage.js +1 -1
- package/dist/components/layouts/FullPage.js.map +1 -1
- package/dist/components/layouts/ZoomedFullBody.js +1 -1
- package/dist/components/layouts/ZoomedFullBody.js.map +1 -1
- package/dist/components/layouts/chat.css +73 -85
- package/dist/components/ui/Drawer.d.ts +1 -0
- package/dist/components/ui/Drawer.js +2 -2
- package/dist/components/ui/Drawer.js.map +1 -1
- package/dist/locales/de.json +37 -1
- package/dist/locales/en.json +37 -1
- package/dist/locales/es.json +37 -1
- package/dist/locales/fr.json +37 -1
- package/dist/locales/it.json +37 -1
- package/esm/components/LoginDrawer/LoginDrawer.d.ts +1 -2
- package/esm/components/LoginDrawer/LoginDrawer.js +3 -106
- package/esm/components/LoginDrawer/LoginDrawer.js.map +1 -1
- package/esm/components/MemoriArtifactSystem/components/ArtifactActions/ArtifactActions.css +0 -4
- package/esm/components/MemoriArtifactSystem/components/ArtifactActions/ArtifactActions.d.ts +1 -0
- package/esm/components/MemoriArtifactSystem/components/ArtifactActions/ArtifactActions.js +3 -3
- package/esm/components/MemoriArtifactSystem/components/ArtifactActions/ArtifactActions.js.map +1 -1
- package/esm/components/MemoriArtifactSystem/components/ArtifactActions/components/CopyButtonWithDropdown.js +110 -8
- package/esm/components/MemoriArtifactSystem/components/ArtifactActions/components/CopyButtonWithDropdown.js.map +1 -1
- package/esm/components/MemoriArtifactSystem/components/ArtifactActions/components/CopyMenuItem.js +3 -0
- package/esm/components/MemoriArtifactSystem/components/ArtifactActions/components/CopyMenuItem.js.map +1 -1
- package/esm/components/MemoriArtifactSystem/components/ArtifactActions/hooks/useCopyArtifact.js +42 -38
- package/esm/components/MemoriArtifactSystem/components/ArtifactActions/hooks/useCopyArtifact.js.map +1 -1
- package/esm/components/MemoriArtifactSystem/components/ArtifactActions/styles.css +1 -2
- package/esm/components/MemoriArtifactSystem/components/ArtifactActions/types.d.ts +2 -1
- package/esm/components/MemoriArtifactSystem/components/ArtifactDrawer/ArtifactDrawer.css +428 -15
- package/esm/components/MemoriArtifactSystem/components/ArtifactDrawer/ArtifactDrawer.d.ts +1 -0
- package/esm/components/MemoriArtifactSystem/components/ArtifactDrawer/ArtifactDrawer.js +48 -9
- package/esm/components/MemoriArtifactSystem/components/ArtifactDrawer/ArtifactDrawer.js.map +1 -1
- package/esm/components/MemoriArtifactSystem/components/ArtifactDrawer/components/TabSwitch.css +150 -0
- package/esm/components/MemoriArtifactSystem/components/ArtifactDrawer/components/TabSwitch.d.ts +9 -0
- package/esm/components/MemoriArtifactSystem/components/ArtifactDrawer/components/TabSwitch.js +32 -0
- package/esm/components/MemoriArtifactSystem/components/ArtifactDrawer/components/TabSwitch.js.map +1 -0
- package/esm/components/MemoriArtifactSystem/components/ArtifactHandler/ArtifactHandler.css +2 -0
- package/esm/components/MemoriArtifactSystem/components/ArtifactPreview/ArtifactPreview.css +1 -1
- package/esm/components/MemoriArtifactSystem/components/ArtifactPreview/ArtifactPreview.d.ts +2 -1
- package/esm/components/MemoriArtifactSystem/components/ArtifactPreview/ArtifactPreview.js +16 -27
- package/esm/components/MemoriArtifactSystem/components/ArtifactPreview/ArtifactPreview.js.map +1 -1
- package/esm/components/MemoriArtifactSystem/context/ArtifactContext.js +1 -5
- package/esm/components/MemoriArtifactSystem/context/ArtifactContext.js.map +1 -1
- package/esm/components/MemoriWidget/MemoriWidget.js +1 -1
- package/esm/components/MemoriWidget/MemoriWidget.js.map +1 -1
- package/esm/components/icons/Close.d.ts +2 -1
- package/esm/components/icons/Close.js +1 -1
- package/esm/components/icons/Close.js.map +1 -1
- package/esm/components/icons/MenuVertical.d.ts +7 -0
- package/esm/components/icons/MenuVertical.js +4 -0
- package/esm/components/icons/MenuVertical.js.map +1 -0
- package/esm/components/layouts/Chat.js +1 -1
- package/esm/components/layouts/Chat.js.map +1 -1
- package/esm/components/layouts/FullPage.js +1 -1
- package/esm/components/layouts/FullPage.js.map +1 -1
- package/esm/components/layouts/ZoomedFullBody.js +1 -1
- package/esm/components/layouts/ZoomedFullBody.js.map +1 -1
- package/esm/components/layouts/chat.css +73 -85
- package/esm/components/ui/Drawer.d.ts +1 -0
- package/esm/components/ui/Drawer.js +2 -2
- package/esm/components/ui/Drawer.js.map +1 -1
- package/esm/locales/de.json +37 -1
- package/esm/locales/en.json +37 -1
- package/esm/locales/es.json +37 -1
- package/esm/locales/fr.json +37 -1
- package/esm/locales/it.json +37 -1
- package/package.json +1 -1
- package/src/components/FilePreview/__snapshots__/FilePreview.test.tsx.snap +9 -0
- package/src/components/LoginDrawer/LoginDrawer.tsx +46 -221
- package/src/components/MemoriArtifactSystem/components/ArtifactActions/ArtifactActions.css +0 -4
- package/src/components/MemoriArtifactSystem/components/ArtifactActions/ArtifactActions.tsx +7 -5
- package/src/components/MemoriArtifactSystem/components/ArtifactActions/components/CopyButtonWithDropdown.tsx +148 -12
- package/src/components/MemoriArtifactSystem/components/ArtifactActions/components/CopyMenuItem.tsx +3 -0
- package/src/components/MemoriArtifactSystem/components/ArtifactActions/hooks/useCopyArtifact.ts +54 -47
- package/src/components/MemoriArtifactSystem/components/ArtifactActions/styles.css +1 -2
- package/src/components/MemoriArtifactSystem/components/ArtifactActions/types.ts +2 -1
- package/src/components/MemoriArtifactSystem/components/ArtifactDrawer/ArtifactDrawer.css +428 -15
- package/src/components/MemoriArtifactSystem/components/ArtifactDrawer/ArtifactDrawer.tsx +240 -42
- package/src/components/MemoriArtifactSystem/components/ArtifactDrawer/components/TabSwitch.css +150 -0
- package/src/components/MemoriArtifactSystem/components/ArtifactDrawer/components/TabSwitch.tsx +79 -0
- package/src/components/MemoriArtifactSystem/components/ArtifactHandler/ArtifactHandler.css +2 -0
- package/src/components/MemoriArtifactSystem/components/ArtifactPreview/ArtifactPreview.css +1 -1
- package/src/components/MemoriArtifactSystem/components/ArtifactPreview/ArtifactPreview.tsx +2 -41
- package/src/components/MemoriArtifactSystem/context/ArtifactContext.tsx +1 -5
- package/src/components/MemoriWidget/MemoriWidget.tsx +0 -1
- package/src/components/icons/Close.tsx +8 -1
- package/src/components/icons/MenuVertical.tsx +29 -0
- package/src/components/layouts/Chat.tsx +3 -1
- package/src/components/layouts/FullPage.tsx +7 -2
- package/src/components/layouts/ZoomedFullBody.tsx +8 -3
- package/src/components/layouts/__snapshots__/Chat.test.tsx.snap +1 -1
- package/src/components/layouts/__snapshots__/FullPage.test.tsx.snap +112 -104
- package/src/components/layouts/__snapshots__/HiddenChat.test.tsx.snap +3 -0
- package/src/components/layouts/__snapshots__/ZoomedFullBody.test.tsx.snap +56 -52
- package/src/components/layouts/chat.css +73 -85
- package/src/components/ui/Drawer.tsx +3 -1
- package/src/components/ui/__snapshots__/Alert.test.tsx.snap +3 -0
- package/src/locales/de.json +37 -1
- package/src/locales/en.json +37 -1
- package/src/locales/es.json +37 -1
- package/src/locales/fr.json +37 -1
- package/src/locales/it.json +38 -1
|
@@ -20,7 +20,6 @@ export interface Props {
|
|
|
20
20
|
onLogout: () => void;
|
|
21
21
|
tenant: Tenant;
|
|
22
22
|
apiClient: ReturnType<typeof memoriApiClient>;
|
|
23
|
-
baseURL?: string;
|
|
24
23
|
__TEST__signup?: boolean;
|
|
25
24
|
__TEST__needMissingData?: boolean;
|
|
26
25
|
__TEST__waitingForOtp?: boolean;
|
|
@@ -36,7 +35,6 @@ const LoginDrawer = ({
|
|
|
36
35
|
loginToken,
|
|
37
36
|
tenant,
|
|
38
37
|
apiClient,
|
|
39
|
-
baseURL,
|
|
40
38
|
__TEST__signup = false,
|
|
41
39
|
__TEST__needMissingData = false,
|
|
42
40
|
__TEST__waitingForOtp = false,
|
|
@@ -52,13 +50,6 @@ const LoginDrawer = ({
|
|
|
52
50
|
const [loading, setLoading] = useState(false);
|
|
53
51
|
const [error, setError] = useState<string | null>(null);
|
|
54
52
|
|
|
55
|
-
// OTP-related state
|
|
56
|
-
const [otpCode, setOtpCode] = useState<string>('');
|
|
57
|
-
const [otpUserName, setOtpUserName] = useState<string>('');
|
|
58
|
-
const [otpError, setOtpError] = useState<string | null>(null);
|
|
59
|
-
const [showOtpForm, setShowOtpForm] = useState(false);
|
|
60
|
-
const [otpTimer, setOtpTimer] = useState<number | null>(null);
|
|
61
|
-
|
|
62
53
|
const [showSignup, setShowSignup] = useState(__TEST__signup);
|
|
63
54
|
const [userMustChangePwd, setUserMustChangePwd] = useState<User | undefined>(
|
|
64
55
|
__TEST__changePwd
|
|
@@ -85,96 +76,6 @@ const LoginDrawer = ({
|
|
|
85
76
|
: ({} as any)
|
|
86
77
|
);
|
|
87
78
|
|
|
88
|
-
// OTP timer effect
|
|
89
|
-
useEffect(() => {
|
|
90
|
-
let interval: NodeJS.Timeout;
|
|
91
|
-
if (otpTimer && otpTimer > 0) {
|
|
92
|
-
interval = setInterval(() => {
|
|
93
|
-
setOtpTimer(prev => (prev && prev > 0 ? prev - 1 : 0));
|
|
94
|
-
}, 1000);
|
|
95
|
-
}
|
|
96
|
-
return () => {
|
|
97
|
-
if (interval) clearInterval(interval);
|
|
98
|
-
};
|
|
99
|
-
}, [otpTimer]);
|
|
100
|
-
|
|
101
|
-
// OTP validation function
|
|
102
|
-
const validateOtp = async (otp: string) => {
|
|
103
|
-
if (!otp || otp.length !== 4) {
|
|
104
|
-
setOtpError(t('login.otpInvalidFormat'));
|
|
105
|
-
return;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
if (!otpUserName || otpUserName.trim().length === 0) {
|
|
109
|
-
setOtpError(t('login.userNameRequired'));
|
|
110
|
-
return;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
setLoading(true);
|
|
114
|
-
setOtpError(null);
|
|
115
|
-
|
|
116
|
-
try {
|
|
117
|
-
const response = await fetch(`${baseURL}/api/validate-otp`, {
|
|
118
|
-
method: 'POST',
|
|
119
|
-
headers: {
|
|
120
|
-
'Content-Type': 'application/json',
|
|
121
|
-
},
|
|
122
|
-
body: JSON.stringify({
|
|
123
|
-
otp: otp,
|
|
124
|
-
userName: otpUserName.trim(),
|
|
125
|
-
}),
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
const data = await response.json();
|
|
129
|
-
|
|
130
|
-
if (response.status == 200 && data.user && data.loginToken) {
|
|
131
|
-
toast.success(t('login.otpSuccess'));
|
|
132
|
-
setShowOtpForm(false);
|
|
133
|
-
setOtpCode('');
|
|
134
|
-
setOtpUserName('');
|
|
135
|
-
|
|
136
|
-
if (!data.user?.tnCAndPPAccepted || !data.user?.birthDate) {
|
|
137
|
-
setNeedsMissingData({
|
|
138
|
-
token: data.loginToken,
|
|
139
|
-
birthDate: !data.user.birthDate,
|
|
140
|
-
tnCAndPPAccepted: !data.user.tnCAndPPAccepted,
|
|
141
|
-
});
|
|
142
|
-
} else {
|
|
143
|
-
onLogin(data.user as User, data.loginToken);
|
|
144
|
-
}
|
|
145
|
-
} else {
|
|
146
|
-
setOtpError(data.resultMessage || t('login.otpInvalid'));
|
|
147
|
-
}
|
|
148
|
-
} catch (err) {
|
|
149
|
-
console.error('[OTP VALIDATION]', err);
|
|
150
|
-
setOtpError(t('login.otpError'));
|
|
151
|
-
} finally {
|
|
152
|
-
setLoading(false);
|
|
153
|
-
}
|
|
154
|
-
};
|
|
155
|
-
|
|
156
|
-
// Handle OTP input change
|
|
157
|
-
const handleOtpChange = (value: string) => {
|
|
158
|
-
const numericValue = value.replace(/\D/g, '').slice(0, 4);
|
|
159
|
-
setOtpCode(numericValue);
|
|
160
|
-
setOtpError(null);
|
|
161
|
-
|
|
162
|
-
if (numericValue.length === 4 && otpUserName.trim().length > 0) {
|
|
163
|
-
validateOtp(numericValue);
|
|
164
|
-
}
|
|
165
|
-
};
|
|
166
|
-
|
|
167
|
-
// Handle username input change
|
|
168
|
-
const handleUserNameChange = (value: string) => {
|
|
169
|
-
setOtpUserName(value);
|
|
170
|
-
setOtpError(null);
|
|
171
|
-
};
|
|
172
|
-
|
|
173
|
-
// Start OTP timer
|
|
174
|
-
const startOtpTimer = () => {
|
|
175
|
-
setOtpTimer(60);
|
|
176
|
-
};
|
|
177
|
-
|
|
178
79
|
const login = (e: React.FormEvent<HTMLFormElement>) => {
|
|
179
80
|
e.preventDefault();
|
|
180
81
|
const form = e.currentTarget as HTMLFormElement;
|
|
@@ -578,135 +479,59 @@ const LoginDrawer = ({
|
|
|
578
479
|
<SignupForm
|
|
579
480
|
tenant={tenant}
|
|
580
481
|
apiClient={apiClient}
|
|
581
|
-
onLogin={
|
|
582
|
-
// Force all signup users to go through missing data flow
|
|
583
|
-
// This ensures consistent user experience and data collection
|
|
584
|
-
setNeedsMissingData({
|
|
585
|
-
token: token,
|
|
586
|
-
birthDate: true, // Always require birth date for new users
|
|
587
|
-
tnCAndPPAccepted: true, // Always require terms acceptance for new users
|
|
588
|
-
});
|
|
589
|
-
}}
|
|
482
|
+
onLogin={onLogin}
|
|
590
483
|
goToLogin={() => setShowSignup(false)}
|
|
591
484
|
__TEST__waitingForOtp={__TEST__waitingForOtp}
|
|
592
485
|
/>
|
|
593
|
-
) :
|
|
486
|
+
) : (
|
|
594
487
|
<>
|
|
595
|
-
<
|
|
596
|
-
<
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
488
|
+
<form className="memori--login-drawer--form" onSubmit={login}>
|
|
489
|
+
<label htmlFor="#userNameOrEmail">
|
|
490
|
+
{t('login.userNameOrEmail')}
|
|
491
|
+
<input
|
|
492
|
+
id="userNameOrEmail"
|
|
493
|
+
name="userNameOrEmail"
|
|
494
|
+
required
|
|
495
|
+
autoComplete="email"
|
|
496
|
+
placeholder="Username/email"
|
|
497
|
+
/>
|
|
498
|
+
</label>
|
|
600
499
|
|
|
601
|
-
<
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
autoComplete="username"
|
|
613
|
-
disabled={loading}
|
|
614
|
-
/>
|
|
615
|
-
</label>
|
|
616
|
-
|
|
617
|
-
<label htmlFor="otp-code">
|
|
618
|
-
<span>{t('login.otpCode')}</span>
|
|
619
|
-
<input
|
|
620
|
-
id="otp-code"
|
|
621
|
-
type="text"
|
|
622
|
-
className={cx('memori--login-drawer--otp-input', {
|
|
623
|
-
success: otpCode.length === 4 && !otpError,
|
|
624
|
-
})}
|
|
625
|
-
value={otpCode}
|
|
626
|
-
onChange={e => handleOtpChange(e.target.value)}
|
|
627
|
-
placeholder="0000"
|
|
628
|
-
maxLength={4}
|
|
629
|
-
autoComplete="one-time-code"
|
|
630
|
-
required
|
|
631
|
-
disabled={loading}
|
|
632
|
-
/>
|
|
633
|
-
</label>
|
|
634
|
-
</div>
|
|
635
|
-
|
|
636
|
-
{otpTimer && otpTimer > 0 && (
|
|
637
|
-
<p className="memori--login-drawer--otp-timer">
|
|
638
|
-
{t('login.otpTimer', { seconds: otpTimer })}
|
|
639
|
-
</p>
|
|
640
|
-
)}
|
|
500
|
+
<label htmlFor="#password">
|
|
501
|
+
Password
|
|
502
|
+
<input
|
|
503
|
+
id="password"
|
|
504
|
+
name="password"
|
|
505
|
+
type="password"
|
|
506
|
+
required
|
|
507
|
+
autoComplete="password"
|
|
508
|
+
placeholder="Password"
|
|
509
|
+
/>
|
|
510
|
+
</label>
|
|
641
511
|
|
|
642
|
-
<
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
onClick={() => {
|
|
646
|
-
setShowOtpForm(false);
|
|
647
|
-
setOtpCode('');
|
|
648
|
-
setOtpUserName('');
|
|
649
|
-
setOtpError(null);
|
|
650
|
-
}}
|
|
651
|
-
>
|
|
652
|
-
{t('login.backToLogin')}
|
|
653
|
-
</Button>
|
|
654
|
-
|
|
655
|
-
<Button
|
|
656
|
-
primary
|
|
657
|
-
onClick={() => {
|
|
658
|
-
window.open(
|
|
659
|
-
'http://localhost:3000/it/account?t=account',
|
|
660
|
-
'_blank'
|
|
661
|
-
);
|
|
662
|
-
startOtpTimer();
|
|
663
|
-
}}
|
|
664
|
-
>
|
|
665
|
-
{t('login.generateOtp')}
|
|
666
|
-
</Button>
|
|
667
|
-
</div>
|
|
668
|
-
|
|
669
|
-
{otpError && (
|
|
670
|
-
<p role="alert" className="memori--login-drawer--otp-error">
|
|
671
|
-
{otpError}
|
|
672
|
-
</p>
|
|
673
|
-
)}
|
|
674
|
-
</div>
|
|
675
|
-
</>
|
|
676
|
-
) : (
|
|
677
|
-
<>
|
|
678
|
-
<div className="memori--login-drawer--welcome">
|
|
679
|
-
<h3>{t('login.welcomeTitle')}</h3>
|
|
680
|
-
<p className="memori--login-drawer--welcome-description">
|
|
681
|
-
{t('login.welcomeDescription')}
|
|
682
|
-
</p>
|
|
512
|
+
<Button htmlType="submit" primary loading={loading}>
|
|
513
|
+
{t('login.login')}
|
|
514
|
+
</Button>
|
|
683
515
|
|
|
684
|
-
|
|
685
|
-
<
|
|
686
|
-
|
|
687
|
-
<
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
<
|
|
695
|
-
|
|
516
|
+
{!tenant?.disableRegistration ? (
|
|
517
|
+
<p className="memori--login-drawer--signup">
|
|
518
|
+
{t('login.newUserSignUp')}{' '}
|
|
519
|
+
<Button outlined onClick={() => setShowSignup(true)}>
|
|
520
|
+
{t('login.signUp')}
|
|
521
|
+
</Button>
|
|
522
|
+
</p>
|
|
523
|
+
) : tenant.adminEmail ? (
|
|
524
|
+
<div className="memori--login-drawer--signup">
|
|
525
|
+
<p>{t('login.registrationDisabled')}</p>
|
|
526
|
+
<p>
|
|
527
|
+
{t('login.contactAdmin')}:{' '}
|
|
528
|
+
<a href={`mailto:${tenant.adminEmail}`}>
|
|
529
|
+
{tenant.adminEmail}
|
|
530
|
+
</a>
|
|
531
|
+
</p>
|
|
696
532
|
</div>
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
<Button
|
|
700
|
-
primary
|
|
701
|
-
onClick={() => {
|
|
702
|
-
setShowOtpForm(true);
|
|
703
|
-
startOtpTimer();
|
|
704
|
-
}}
|
|
705
|
-
className="memori--login-drawer--start-otp-button"
|
|
706
|
-
>
|
|
707
|
-
{t('login.startOtpLogin')}
|
|
708
|
-
</Button>
|
|
709
|
-
</div>
|
|
533
|
+
) : null}
|
|
534
|
+
</form>
|
|
710
535
|
|
|
711
536
|
{error && (
|
|
712
537
|
<p role="alert" className="memori--login-drawer--error">
|
|
@@ -719,4 +544,4 @@ const LoginDrawer = ({
|
|
|
719
544
|
);
|
|
720
545
|
};
|
|
721
546
|
|
|
722
|
-
export default LoginDrawer;
|
|
547
|
+
export default LoginDrawer;
|
|
@@ -16,7 +16,7 @@ import FullscreenExit from '../../../icons/FullscreenExit';
|
|
|
16
16
|
import PrintIcon from '../../../icons/Print';
|
|
17
17
|
import { CopyButtonWithDropdown } from './';
|
|
18
18
|
import { Menu, Transition } from '@headlessui/react';
|
|
19
|
-
import
|
|
19
|
+
import MenuVertical from '../../../icons/MenuVertical';
|
|
20
20
|
|
|
21
21
|
const ArtifactActions: React.FC<{
|
|
22
22
|
artifact: ArtifactData;
|
|
@@ -25,6 +25,7 @@ const ArtifactActions: React.FC<{
|
|
|
25
25
|
onPrint: () => void;
|
|
26
26
|
onOpenExternal: () => void;
|
|
27
27
|
loading: boolean;
|
|
28
|
+
isMobile?: boolean;
|
|
28
29
|
}> = ({
|
|
29
30
|
artifact,
|
|
30
31
|
onCopy,
|
|
@@ -32,6 +33,7 @@ const ArtifactActions: React.FC<{
|
|
|
32
33
|
onPrint,
|
|
33
34
|
onOpenExternal,
|
|
34
35
|
loading = false,
|
|
36
|
+
isMobile = false,
|
|
35
37
|
}) => {
|
|
36
38
|
const { t } = useTranslation();
|
|
37
39
|
|
|
@@ -183,19 +185,19 @@ const ArtifactActions: React.FC<{
|
|
|
183
185
|
loading={loading}
|
|
184
186
|
className="memori-artifact-action-btn"
|
|
185
187
|
/>
|
|
186
|
-
|
|
188
|
+
{isMobile && <Menu as="div" className="memori-copy-menu-wrapper">
|
|
187
189
|
<Menu.Button as="div" className="memori-copy-button-trigger">
|
|
188
190
|
<Button
|
|
189
191
|
disabled={loading}
|
|
190
192
|
className={cx(
|
|
191
193
|
'memori-button',
|
|
192
|
-
'memori-button--
|
|
194
|
+
'memori-button--more-options',
|
|
193
195
|
'memori-button--icon-only'
|
|
194
196
|
)}
|
|
195
197
|
ghost
|
|
196
198
|
title="More copy options"
|
|
197
199
|
>
|
|
198
|
-
<
|
|
200
|
+
<MenuVertical className="memori-artifact-action-icon" />
|
|
199
201
|
</Button>
|
|
200
202
|
</Menu.Button>
|
|
201
203
|
|
|
@@ -239,7 +241,7 @@ const ArtifactActions: React.FC<{
|
|
|
239
241
|
</div>
|
|
240
242
|
</Menu.Items>
|
|
241
243
|
</Transition>
|
|
242
|
-
</Menu>
|
|
244
|
+
</Menu>}
|
|
243
245
|
</div>
|
|
244
246
|
</div>
|
|
245
247
|
);
|
|
@@ -14,12 +14,16 @@ import Copy from '../../../../icons/Copy';
|
|
|
14
14
|
import ChevronDown from '../../../../icons/ChevronDown';
|
|
15
15
|
import ThumbUp from '../../../../icons/ThumbUp';
|
|
16
16
|
import Alert from '../../../../icons/Alert';
|
|
17
|
+
import { useTranslation } from 'react-i18next';
|
|
18
|
+
import Link from '../../../../icons/Link';
|
|
19
|
+
import PrintIcon from '../../../../icons/Print';
|
|
17
20
|
|
|
18
21
|
const CopyButtonWithDropdown: React.FC<CopyButtonWithDropdownProps> = ({
|
|
19
22
|
artifact,
|
|
20
23
|
onCopy,
|
|
21
24
|
onDownload,
|
|
22
25
|
onPrint,
|
|
26
|
+
onOpenExternal,
|
|
23
27
|
loading = false,
|
|
24
28
|
className,
|
|
25
29
|
disabled = false,
|
|
@@ -30,6 +34,7 @@ const CopyButtonWithDropdown: React.FC<CopyButtonWithDropdownProps> = ({
|
|
|
30
34
|
onDownload,
|
|
31
35
|
onPrint
|
|
32
36
|
);
|
|
37
|
+
const { t } = useTranslation();
|
|
33
38
|
|
|
34
39
|
/**
|
|
35
40
|
* Handle format selection from dropdown
|
|
@@ -38,6 +43,34 @@ const CopyButtonWithDropdown: React.FC<CopyButtonWithDropdownProps> = ({
|
|
|
38
43
|
await handleCopy(format);
|
|
39
44
|
};
|
|
40
45
|
|
|
46
|
+
/**
|
|
47
|
+
* Get MIME type string for downloads
|
|
48
|
+
*/
|
|
49
|
+
const getMimeTypeString = useCallback((mimeType: string): string => {
|
|
50
|
+
const mimeTypes: Record<string, string> = {
|
|
51
|
+
html: 'text/html',
|
|
52
|
+
json: 'application/json',
|
|
53
|
+
markdown: 'text/markdown',
|
|
54
|
+
css: 'text/css',
|
|
55
|
+
javascript: 'text/javascript',
|
|
56
|
+
typescript: 'text/typescript',
|
|
57
|
+
svg: 'image/svg+xml',
|
|
58
|
+
xml: 'text/xml',
|
|
59
|
+
text: 'text/plain',
|
|
60
|
+
python: 'text/x-python',
|
|
61
|
+
java: 'text/x-java',
|
|
62
|
+
cpp: 'text/x-c++',
|
|
63
|
+
csharp: 'text/x-csharp',
|
|
64
|
+
php: 'text/x-php',
|
|
65
|
+
ruby: 'text/x-ruby',
|
|
66
|
+
go: 'text/x-go',
|
|
67
|
+
rust: 'text/x-rust',
|
|
68
|
+
yaml: 'text/yaml',
|
|
69
|
+
sql: 'text/x-sql',
|
|
70
|
+
};
|
|
71
|
+
return mimeTypes[mimeType] || 'text/plain';
|
|
72
|
+
}, []);
|
|
73
|
+
|
|
41
74
|
/**
|
|
42
75
|
* Get button content based on state
|
|
43
76
|
*/
|
|
@@ -46,7 +79,9 @@ const CopyButtonWithDropdown: React.FC<CopyButtonWithDropdownProps> = ({
|
|
|
46
79
|
return (
|
|
47
80
|
<>
|
|
48
81
|
<ThumbUp className="memori-copy-button-icon memori-copy-button-icon--success" />
|
|
49
|
-
<span className="memori-copy-button-text">
|
|
82
|
+
<span className="memori-copy-button-text">
|
|
83
|
+
{t('artifact.copied') || 'Copied!'}
|
|
84
|
+
</span>
|
|
50
85
|
</>
|
|
51
86
|
);
|
|
52
87
|
}
|
|
@@ -55,7 +90,9 @@ const CopyButtonWithDropdown: React.FC<CopyButtonWithDropdownProps> = ({
|
|
|
55
90
|
return (
|
|
56
91
|
<>
|
|
57
92
|
<Alert className="memori-copy-button-icon memori-copy-button-icon--error" />
|
|
58
|
-
<span className="memori-copy-button-text">
|
|
93
|
+
<span className="memori-copy-button-text">
|
|
94
|
+
{t('artifact.error') || 'Error'}
|
|
95
|
+
</span>
|
|
59
96
|
</>
|
|
60
97
|
);
|
|
61
98
|
}
|
|
@@ -68,8 +105,8 @@ const CopyButtonWithDropdown: React.FC<CopyButtonWithDropdownProps> = ({
|
|
|
68
105
|
</div>
|
|
69
106
|
<span className="memori-copy-button-text">
|
|
70
107
|
{copyState.activeFormat === 'pdf'
|
|
71
|
-
? 'Generating PDF...'
|
|
72
|
-
: 'Copying...'}
|
|
108
|
+
? t('artifact.generatingPdf') || 'Generating PDF...'
|
|
109
|
+
: t('artifact.copying') || 'Copying...'}
|
|
73
110
|
</span>
|
|
74
111
|
</>
|
|
75
112
|
);
|
|
@@ -78,11 +115,94 @@ const CopyButtonWithDropdown: React.FC<CopyButtonWithDropdownProps> = ({
|
|
|
78
115
|
return (
|
|
79
116
|
<>
|
|
80
117
|
<Copy className="memori-copy-button-icon" />
|
|
81
|
-
<span className="memori-copy-button-text">
|
|
118
|
+
<span className="memori-copy-button-text">
|
|
119
|
+
{t('artifact.copy') || 'Copy'}
|
|
120
|
+
</span>
|
|
82
121
|
</>
|
|
83
122
|
);
|
|
84
123
|
};
|
|
85
124
|
|
|
125
|
+
/**
|
|
126
|
+
* Handle print action
|
|
127
|
+
*/
|
|
128
|
+
const handlePrint = useCallback(() => {
|
|
129
|
+
try {
|
|
130
|
+
const printWindow = window.open('', '_blank');
|
|
131
|
+
if (!printWindow) {
|
|
132
|
+
alert('Popup blocked! Please enable popups to print the artifact.');
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
let printContent: string;
|
|
137
|
+
if (artifact.mimeType === 'html') {
|
|
138
|
+
printContent = artifact.content;
|
|
139
|
+
} else {
|
|
140
|
+
printContent = `
|
|
141
|
+
<!DOCTYPE html>
|
|
142
|
+
<html>
|
|
143
|
+
<head>
|
|
144
|
+
<title>Artifact - ${artifact.mimeType.toUpperCase()}</title>
|
|
145
|
+
<style>
|
|
146
|
+
body {
|
|
147
|
+
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
|
|
148
|
+
white-space: pre-wrap;
|
|
149
|
+
margin: 20px;
|
|
150
|
+
line-height: 1.4;
|
|
151
|
+
}
|
|
152
|
+
@media print {
|
|
153
|
+
body { margin: 0; }
|
|
154
|
+
}
|
|
155
|
+
</style>
|
|
156
|
+
</head>
|
|
157
|
+
<body>${artifact.content
|
|
158
|
+
.replace(/</g, '<')
|
|
159
|
+
.replace(/>/g, '>')}</body>
|
|
160
|
+
</html>
|
|
161
|
+
`;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
printWindow.document.write(printContent);
|
|
165
|
+
printWindow.document.close();
|
|
166
|
+
|
|
167
|
+
setTimeout(() => {
|
|
168
|
+
printWindow.print();
|
|
169
|
+
printWindow.close();
|
|
170
|
+
}, 500);
|
|
171
|
+
|
|
172
|
+
onPrint?.();
|
|
173
|
+
} catch (error) {
|
|
174
|
+
console.error('Print failed:', error);
|
|
175
|
+
}
|
|
176
|
+
}, [artifact, onPrint]);
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Handle external open action
|
|
180
|
+
*/
|
|
181
|
+
const handleOpenExternal = useCallback(() => {
|
|
182
|
+
try {
|
|
183
|
+
const mimeType = getMimeTypeString(artifact.mimeType);
|
|
184
|
+
const blob = new Blob([artifact.content], { type: mimeType });
|
|
185
|
+
const url = URL.createObjectURL(blob);
|
|
186
|
+
|
|
187
|
+
const externalWindow = window.open(url, '_blank');
|
|
188
|
+
if (!externalWindow) {
|
|
189
|
+
alert(
|
|
190
|
+
'Popup blocked! Please enable popups to open the artifact in a new window.'
|
|
191
|
+
);
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Cleanup URL after a delay
|
|
196
|
+
setTimeout(() => {
|
|
197
|
+
URL.revokeObjectURL(url);
|
|
198
|
+
}, 60000);
|
|
199
|
+
|
|
200
|
+
onOpenExternal?.();
|
|
201
|
+
} catch (error) {
|
|
202
|
+
console.error('External open failed:', error);
|
|
203
|
+
}
|
|
204
|
+
}, [artifact, getMimeTypeString, onOpenExternal]);
|
|
205
|
+
|
|
86
206
|
/**
|
|
87
207
|
* Get button title/tooltip
|
|
88
208
|
*/
|
|
@@ -157,12 +277,6 @@ const CopyButtonWithDropdown: React.FC<CopyButtonWithDropdownProps> = ({
|
|
|
157
277
|
>
|
|
158
278
|
<Menu.Items className="memori-copy-dropdown">
|
|
159
279
|
<div className="memori-copy-dropdown-content">
|
|
160
|
-
<div className="memori-copy-dropdown-header">
|
|
161
|
-
<span className="memori-copy-dropdown-title">
|
|
162
|
-
Copy as
|
|
163
|
-
</span>
|
|
164
|
-
</div>
|
|
165
|
-
|
|
166
280
|
<div className="memori-copy-dropdown-list">
|
|
167
281
|
{formats.map(format => (
|
|
168
282
|
<Menu.Item key={format.id}>
|
|
@@ -176,6 +290,29 @@ const CopyButtonWithDropdown: React.FC<CopyButtonWithDropdownProps> = ({
|
|
|
176
290
|
)}
|
|
177
291
|
</Menu.Item>
|
|
178
292
|
))}
|
|
293
|
+
<CopyMenuItem
|
|
294
|
+
format={{
|
|
295
|
+
id: 'external',
|
|
296
|
+
label: t('artifact.external') || 'External',
|
|
297
|
+
action: 'link',
|
|
298
|
+
mimeType: artifact.mimeType,
|
|
299
|
+
}}
|
|
300
|
+
onClick={handleOpenExternal}
|
|
301
|
+
loading={copyState.loading}
|
|
302
|
+
active={false}
|
|
303
|
+
/>
|
|
304
|
+
<CopyMenuItem
|
|
305
|
+
format={{
|
|
306
|
+
id: 'print',
|
|
307
|
+
label: t('artifact.print') || 'Print',
|
|
308
|
+
action: 'print',
|
|
309
|
+
mimeType: artifact.mimeType,
|
|
310
|
+
}}
|
|
311
|
+
onClick={handlePrint}
|
|
312
|
+
loading={copyState.loading}
|
|
313
|
+
active={false}
|
|
314
|
+
/>
|
|
315
|
+
|
|
179
316
|
</div>
|
|
180
317
|
</div>
|
|
181
318
|
</Menu.Items>
|
|
@@ -185,7 +322,6 @@ const CopyButtonWithDropdown: React.FC<CopyButtonWithDropdownProps> = ({
|
|
|
185
322
|
</Menu>
|
|
186
323
|
)}
|
|
187
324
|
</div>
|
|
188
|
-
|
|
189
325
|
</div>
|
|
190
326
|
);
|
|
191
327
|
};
|
package/src/components/MemoriArtifactSystem/components/ArtifactActions/components/CopyMenuItem.tsx
CHANGED
|
@@ -9,6 +9,7 @@ import { CopyMenuItemProps } from '../types';
|
|
|
9
9
|
import Copy from '../../../../icons/Copy';
|
|
10
10
|
import Download from '../../../../icons/Download';
|
|
11
11
|
import PrintIcon from '../../../../icons/Print';
|
|
12
|
+
import Link from '../../../../icons/Link';
|
|
12
13
|
|
|
13
14
|
const CopyMenuItem: React.FC<CopyMenuItemProps & { active?: boolean }> = ({
|
|
14
15
|
format,
|
|
@@ -37,6 +38,8 @@ const CopyMenuItem: React.FC<CopyMenuItemProps & { active?: boolean }> = ({
|
|
|
37
38
|
return <Download className="memori-copy-menu-item-icon" />;
|
|
38
39
|
case 'print':
|
|
39
40
|
return <PrintIcon className="memori-copy-menu-item-icon" />;
|
|
41
|
+
case 'link':
|
|
42
|
+
return <Link className="memori-copy-menu-item-icon" />;
|
|
40
43
|
default:
|
|
41
44
|
return <Copy className="memori-copy-menu-item-icon" />;
|
|
42
45
|
}
|