diff --git a/components/layout/connection/ConnectionMain.js b/components/layout/connection/ConnectionMain.js
index c5c26a3..4cafa7f 100644
--- a/components/layout/connection/ConnectionMain.js
+++ b/components/layout/connection/ConnectionMain.js
@@ -19,6 +19,8 @@ export default function ConnectionMain() {
handleSlack,
handleGoogleSheets,
handleHubSpot,
+ handleNotion,
+ handleAirtable,
} = useSocial();
const connectionTypes = [
@@ -62,6 +64,16 @@ export default function ConnectionMain() {
key: "hubspot",
type: "redirect",
},
+ {
+ name: "Notion",
+ key: "notion",
+ type: "redirect",
+ },
+ {
+ name: "Airtable",
+ key: "airtable",
+ type: "redirect",
+ },
];
const connectionType = key
@@ -76,7 +88,7 @@ export default function ConnectionMain() {
type: "SOCIAL_AUTH_ERROR",
message: "Connection not found",
},
- window.location.origin
+ window.location.origin,
);
}, 3000);
}
@@ -105,7 +117,7 @@ export default function ConnectionMain() {
type: "SOCIAL_AUTH_ERROR",
message: error.message,
},
- window.location.origin
+ window.location.origin,
);
}
} else if (connectionType.key === "twitter") {
@@ -124,7 +136,7 @@ export default function ConnectionMain() {
type: "SOCIAL_AUTH_ERROR",
message: error.message,
},
- window.location.origin
+ window.location.origin,
);
}
} else if (connectionType.key === "linkedin") {
@@ -143,7 +155,7 @@ export default function ConnectionMain() {
type: "SOCIAL_AUTH_ERROR",
message: error.message,
},
- window.location.origin
+ window.location.origin,
);
}
} else if (connectionType.key === "gmail_trigger") {
@@ -162,7 +174,7 @@ export default function ConnectionMain() {
type: "SOCIAL_AUTH_ERROR",
message: error.message,
},
- window.location.origin
+ window.location.origin,
);
}
} else if (connectionType.key === "gmail_read") {
@@ -181,7 +193,7 @@ export default function ConnectionMain() {
type: "SOCIAL_AUTH_ERROR",
message: error.message,
},
- window.location.origin
+ window.location.origin,
);
}
} else if (connectionType.key === "slack") {
@@ -200,7 +212,7 @@ export default function ConnectionMain() {
type: "SOCIAL_AUTH_ERROR",
message: error.message,
},
- window.location.origin
+ window.location.origin,
);
}
} else if (connectionType.key === "google_sheets") {
@@ -219,7 +231,7 @@ export default function ConnectionMain() {
type: "SOCIAL_AUTH_ERROR",
message: error.message,
},
- window.location.origin
+ window.location.origin,
);
}
} else if (connectionType.key === "hubspot") {
@@ -238,7 +250,45 @@ export default function ConnectionMain() {
type: "SOCIAL_AUTH_ERROR",
message: error.message,
},
- window.location.origin
+ window.location.origin,
+ );
+ }
+ } else if (connectionType.key === "notion") {
+ try {
+ const response = await handleNotion(workflowId);
+
+ if (!response.data.success) {
+ throw new Error(response.data.message);
+ }
+
+ window.location.href = response.data.authURL;
+ } catch (error) {
+ console.log(error);
+ window.opener.postMessage(
+ {
+ type: "SOCIAL_AUTH_ERROR",
+ message: error.message,
+ },
+ window.location.origin,
+ );
+ }
+ } else if (connectionType.key === "airtable") {
+ try {
+ const response = await handleAirtable(workflowId);
+
+ if (!response.data.success) {
+ throw new Error(response.data.message);
+ }
+
+ window.location.href = response.data.authURL;
+ } catch (error) {
+ console.log(error);
+ window.opener.postMessage(
+ {
+ type: "SOCIAL_AUTH_ERROR",
+ message: error.message,
+ },
+ window.location.origin,
);
}
}
diff --git a/components/layout/dashboard/files/FileList.js b/components/layout/dashboard/files/FileList.js
index 2a892dd..bf121db 100644
--- a/components/layout/dashboard/files/FileList.js
+++ b/components/layout/dashboard/files/FileList.js
@@ -29,16 +29,18 @@ const getFilesData = async (page) => {
const limit = 10;
const response = await fetch(
- `${process.env.API_URL}/storage/list?page=${currentPage}&limit=${limit}`,
+ `${process.env.API_URL}/storage/list?page=${currentPage}&limit=${limit}&t=${Date.now()}`,
{
method: "GET",
headers: {
"Content-Type": "application/json",
cookie: cookieHeader,
+ Pragma: "no-cache",
+ "Cache-Control": "no-cache, no-store, must-revalidate",
},
credentials: "include",
cache: "no-store",
- }
+ },
);
if (!response.ok) {
@@ -76,7 +78,7 @@ const FileList = async ({ page, query }) => {
if (query) {
files = files.filter((file) =>
- file.fileName.toLowerCase().includes(query.toLowerCase())
+ file.fileName.toLowerCase().includes(query.toLowerCase()),
);
}
@@ -203,19 +205,20 @@ const FileList = async ({ page, query }) => {
- {file.scrapeStatus && (
+ {file.sourceUrl && (
)}
- {file.ragStatus && (
-
- )}
+ {(file.sourceUrl ? file.scrapeStatus === "done" : true) &&
+ file.ragStatus && (
+
+ )}
diff --git a/components/layout/dashboard/files/FileMenuBox.js b/components/layout/dashboard/files/FileMenuBox.js
index 8b29070..5aebd0f 100644
--- a/components/layout/dashboard/files/FileMenuBox.js
+++ b/components/layout/dashboard/files/FileMenuBox.js
@@ -19,7 +19,14 @@ import RagConversionDialog from "./RagConversionDialog";
const baseMenuBtn =
"data-highlighted:bg-foreground/5 not-disabled:not-active:not-data-pressed:before:shadow-none px-2 min-h-5 font-normal rounded-sm text-xs [&_svg:not([class*='size-'])]:size-3 dark:not-disabled:not-active:not-data-pressed:before:shadow-none data-highlighted:text-destructive cursor-pointer dark:bg-transparent shadow-none! bg-transparent hover:bg-transparent w-full justify-start border-none";
-const FileMenuBox = ({ fileKey, fileName, ragStatus, ragTableName }) => {
+const FileMenuBox = ({
+ fileKey,
+ fileName,
+ ragStatus,
+ ragTableName,
+ sourceUrl,
+ scrapeStatus,
+}) => {
const [showRagDialog, setShowRagDialog] = useState(false);
const [showEditDialog, setShowEditDialog] = useState(false);
const [showDeleteDialog, setShowDeleteDialog] = useState(false);
@@ -29,6 +36,15 @@ const FileMenuBox = ({ fileKey, fileName, ragStatus, ragTableName }) => {
e.stopPropagation();
};
+ const handleRagDialogOpen = () => {
+ if (sourceUrl && scrapeStatus !== "done") {
+ toast.error("Scrape not completed");
+ return;
+ }
+
+ setShowRagDialog(!showRagDialog);
+ };
+
const handleDownload = useCallback(
async (e) => {
stop(e);
@@ -41,7 +57,7 @@ const FileMenuBox = ({ fileKey, fileName, ragStatus, ragTableName }) => {
credentials: "include",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ fileKey }),
- }
+ },
);
const data = await res.json();
@@ -74,7 +90,7 @@ const FileMenuBox = ({ fileKey, fileName, ragStatus, ragTableName }) => {
toast.error("Failed to download file");
}
},
- [fileKey, fileName]
+ [fileKey, fileName],
);
const handleEdit = useCallback((e) => {
@@ -87,10 +103,14 @@ const FileMenuBox = ({ fileKey, fileName, ragStatus, ragTableName }) => {
setShowDeleteDialog(true);
}, []);
- const handleRagConversion = useCallback((e) => {
- stop(e);
+ const handleRagConversion = () => {
+ if (sourceUrl && scrapeStatus !== "done") {
+ toast.error("Scrape not completed");
+ return;
+ }
+
setShowRagDialog(true);
- }, []);
+ };
return (
<>
@@ -182,7 +202,7 @@ const FileMenuBox = ({ fileKey, fileName, ragStatus, ragTableName }) => {
ragStatus={ragStatus}
ragTableName={ragTableName}
open={showRagDialog}
- onOpenChange={setShowRagDialog}
+ onOpenChange={handleRagDialogOpen}
/>
>
);
diff --git a/components/layout/dashboard/files/RagConversionDialog.js b/components/layout/dashboard/files/RagConversionDialog.js
index c59530b..56fb032 100644
--- a/components/layout/dashboard/files/RagConversionDialog.js
+++ b/components/layout/dashboard/files/RagConversionDialog.js
@@ -10,7 +10,7 @@ import {
} from "lucide-react";
import { toast } from "sonner";
import { useRouter } from "next/navigation";
-import { useState, useEffect, useRef, useMemo } from "react";
+import { useState, useEffect, useMemo } from "react";
import {
Dialog,
@@ -38,11 +38,9 @@ const RagConversionDialog = ({
const [ragTableName, setRagTableName] = useState(initialRagTableName);
const [ragStatus, setRagStatus] = useState(
- initialRagStatus || "not-requested"
+ initialRagStatus || "not-requested",
);
- const intervalRef = useRef(null);
-
const statusInfo = useMemo(
() =>
({
@@ -86,14 +84,14 @@ const RagConversionDialog = ({
label: "Failed",
description: "Conversion failed. You can try again.",
},
- }[ragStatus] || {
+ })[ragStatus] || {
icon: Database,
color: "text-gray-500",
bg: "bg-gray-100 dark:bg-gray-800",
label: "Not Converted",
description: "This file has not been converted to RAG database yet.",
- }),
- [ragStatus]
+ },
+ [ragStatus],
);
const StatusIcon = statusInfo.icon;
@@ -102,39 +100,12 @@ const RagConversionDialog = ({
if (open) {
setRagStatus(initialRagStatus || "not-requested");
setRagTableName(initialRagTableName);
-
refreshStatus();
} else {
- cleanupPolling();
setLoading(true);
}
- // eslint-disable-next-line react-hooks/exhaustive-deps
}, [open, initialRagStatus, initialRagTableName]);
- useEffect(() => {
- if (!open) return;
-
- if (ragStatus === "queued" || ragStatus === "processing") {
- startPolling();
- } else {
- cleanupPolling();
- }
-
- return cleanupPolling;
- }, [ragStatus, open]);
-
- const cleanupPolling = () => {
- if (intervalRef.current) {
- clearInterval(intervalRef.current);
- intervalRef.current = null;
- }
- };
-
- const startPolling = () => {
- if (intervalRef.current) return;
- intervalRef.current = setInterval(refreshStatus, 5000);
- };
-
const fetchJson = async (input, init = {}) => {
const res = await fetch(input, init);
@@ -157,23 +128,31 @@ const RagConversionDialog = ({
try {
const url = `${
process.env.NEXT_PUBLIC_API_URL
- }/storage/rag-status/${encodeURIComponent(fileKey)}`;
+ }/storage/rag-status/${encodeURIComponent(fileKey)}?t=${Date.now()}`;
const { ok, data } = await fetchJson(url, {
method: "GET",
cache: "no-store",
credentials: "include",
- headers: { "Content-Type": "application/json" },
+ headers: {
+ Pragma: "no-cache",
+ "Cache-Control": "no-cache, no-store, must-revalidate",
+ "Content-Type": "application/json",
+ },
});
- if (ok && data?.success) {
- const { status, tableName } = data;
+ if (ok && data && (data.success || data.status)) {
+ const { status, tableName, message } = data;
setRagStatus(status);
if (tableName) setRagTableName(tableName);
+ if (status === "failed" && message) {
+ // Optional: Display the error message from the backend in a toast
+ toast.error(message);
+ }
+
if (status === "done" || status === "failed") {
- cleanupPolling();
router.refresh();
}
}
@@ -201,21 +180,19 @@ const RagConversionDialog = ({
if (ok && data?.success) {
const { status } = data;
-
setRagStatus(status);
- toast.success("Conversion started! This may take a few minutes.");
-
- if (status === "queued" || status === "processing") {
- startPolling();
- }
+ toast.success(
+ ragStatus === "failed"
+ ? "Retry submitted! Check status shortly."
+ : "Conversion started! Click 'Refresh Status' to check progress.",
+ );
router.refresh();
} else {
toast.error(data?.message || "Conversion request failed");
}
} catch (error) {
- // eslint-disable-next-line no-console
console.error("Conversion error:", error);
toast.error("An error occurred while starting conversion");
} finally {
@@ -318,6 +295,7 @@ const RagConversionDialog = ({
Close
+ {/* Initial Convert Button */}
{ragStatus === "not-requested" && (