diff --git a/backend/database/data_profile_manager.py b/backend/database/data_profile_manager.py index 750cb2d..88c56d6 100644 --- a/backend/database/data_profile_manager.py +++ b/backend/database/data_profile_manager.py @@ -13,6 +13,16 @@ def get_all_data_profiles(self): """Retrieve all DataProfiles.""" return self.session.query(DataProfile).all() + def get_all_data_profile_names_by_org_id(self, org_id): + """Retrieve all DataProfiles.""" + result = ( + self.session.query(DataProfile.name) + .filter(DataProfile.organization_id == org_id) + .all() + ) + data_profile_names = [name for (name,) in result] + return data_profile_names + def create_dataprofile(self, data_profile_data: DataProfileCreateRequest): """Create a new DataProfile.""" new_data_profile = DataProfile( diff --git a/backend/database/database_manager.py b/backend/database/database_manager.py index ff0907e..3682898 100644 --- a/backend/database/database_manager.py +++ b/backend/database/database_manager.py @@ -2,6 +2,7 @@ APP_ENV, DATABASE_POOL_MAX_OVERFLOW, DATABASE_POOL_SIZE, + DATABASE_POOL_URL, DATABASE_URL, ) from sqlalchemy import create_engine @@ -13,7 +14,7 @@ class DatabaseManager: def __init__(self): if APP_ENV == "prod": self.engine = create_engine( - DATABASE_URL, + DATABASE_POOL_URL, poolclass=QueuePool, pool_size=DATABASE_POOL_SIZE, max_overflow=DATABASE_POOL_MAX_OVERFLOW, diff --git a/backend/routes/data_profile_routes.py b/backend/routes/data_profile_routes.py index f190852..a83a290 100644 --- a/backend/routes/data_profile_routes.py +++ b/backend/routes/data_profile_routes.py @@ -27,6 +27,16 @@ async def get_data_profiles(current_user: User = Depends(get_current_user)): return data_profiles +@data_profile_router.get("/data-profiles/org/") +async def get_data_profiles_by_org_id(current_user: User = Depends(get_current_user)): + with DatabaseManager() as session: + data_profile_manager = DataProfileManager(session) + data_profile_names = data_profile_manager.get_all_data_profile_names_by_org_id( + current_user.organization_id + ) + return data_profile_names + + @data_profile_router.post("/data-profile/") async def save_data_profiles( request: DataProfileCreateRequest, current_user: User = Depends(get_current_user) diff --git a/frontend/src/components/auth/RequireAuth.jsx b/frontend/src/components/auth/RequireAuth.jsx index 1590012..98810f3 100644 --- a/frontend/src/components/auth/RequireAuth.jsx +++ b/frontend/src/components/auth/RequireAuth.jsx @@ -17,7 +17,6 @@ function RequireAuth({ children }) { if (isAuthenticated && !isEmailVerified) { // Redirect to the verify-email page if email is not verified - console.log("triggered"); return ; } diff --git a/frontend/src/components/navigation/Navigation.jsx b/frontend/src/components/navigation/Navigation.jsx index 082a132..045a876 100644 --- a/frontend/src/components/navigation/Navigation.jsx +++ b/frontend/src/components/navigation/Navigation.jsx @@ -36,7 +36,7 @@ const Navigation = () => { let menuItems = [ { text: "Dashboards", icon: , path: "/dashboards" }, { text: "Data Upload", icon: , path: "/upload" }, - { text: "Data Analytics", icon: , path: "/analytics" }, + { text: "AI Analyst", icon: , path: "/analytics" }, { text: "Data Profiling", icon: , diff --git a/frontend/src/pages/analytics/AnalyticsPage.jsx b/frontend/src/pages/analytics/AnalyticsPage.jsx index 7f627a2..6af3427 100644 --- a/frontend/src/pages/analytics/AnalyticsPage.jsx +++ b/frontend/src/pages/analytics/AnalyticsPage.jsx @@ -31,7 +31,7 @@ function AnalyticsPage() { return ( - 📊 Data Analytics + 📊 AI Analyst diff --git a/frontend/src/pages/data-profiling/DataProfilingPage.jsx b/frontend/src/pages/data-profiling/DataProfilingPage.jsx index f8eba7e..9f29eca 100644 --- a/frontend/src/pages/data-profiling/DataProfilingPage.jsx +++ b/frontend/src/pages/data-profiling/DataProfilingPage.jsx @@ -19,8 +19,6 @@ import { API_URL } from "../../utils/constants"; function DataProfilingPage() { const [dataProfiles, setDataProfiles] = useState([]); - const [selectedFile, setSelectedFile] = useState(null); - const [selectedFileName, setSelectedFileName] = useState(""); const [instructions, setInstructions] = useState(""); const [isUploading, setIsUploading] = useState(false); const [previewData, setPreviewData] = useState(null); diff --git a/frontend/src/pages/upload/DataProfileSelector.jsx b/frontend/src/pages/upload/DataProfileSelector.jsx new file mode 100644 index 0000000..009256d --- /dev/null +++ b/frontend/src/pages/upload/DataProfileSelector.jsx @@ -0,0 +1,27 @@ +import React from "react"; +import { FormControl, InputLabel, MenuItem, Select } from "@mui/material"; + +const DataProfileSelector = ({ dataProfiles, dataProfile, setDataProfile }) => { + const isValidDataProfile = dataProfiles.includes(dataProfile); + const safeDataProfile = isValidDataProfile ? dataProfile : ""; + + return ( + + Choose a data profile + + + ); +}; + +export default DataProfileSelector; diff --git a/frontend/src/pages/upload/DescriptionField.jsx b/frontend/src/pages/upload/DescriptionField.jsx deleted file mode 100644 index a2d7bf7..0000000 --- a/frontend/src/pages/upload/DescriptionField.jsx +++ /dev/null @@ -1,14 +0,0 @@ -import React from "react"; -import { TextField } from "@mui/material"; - -const DescriptionField = ({ description, setDescription }) => ( - setDescription(e.target.value)} - /> -); - -export default DescriptionField; diff --git a/frontend/src/pages/upload/EncodingSelector.jsx b/frontend/src/pages/upload/EncodingSelector.jsx deleted file mode 100644 index af5568e..0000000 --- a/frontend/src/pages/upload/EncodingSelector.jsx +++ /dev/null @@ -1,22 +0,0 @@ -import React from "react"; -import { FormControl, InputLabel, MenuItem, Select } from "@mui/material"; - -const EncodingSelector = ({ encodings, encoding, setEncoding }) => ( - - Choose an encoding - - -); - -export default EncodingSelector; diff --git a/frontend/src/pages/upload/FileTypeSelector.jsx b/frontend/src/pages/upload/FileTypeSelector.jsx deleted file mode 100644 index 5d3e5cd..0000000 --- a/frontend/src/pages/upload/FileTypeSelector.jsx +++ /dev/null @@ -1,30 +0,0 @@ -import React from "react"; -import { - FormControl, - FormLabel, - RadioGroup, - FormControlLabel, - Radio, -} from "@mui/material"; - -const FileTypeSelector = ({ fileTypes, fileType, setFileType }) => ( - - Choose file type - setFileType(e.target.value)} - > - {fileTypes.map((type, index) => ( - } - label={type.toUpperCase()} - /> - ))} - - -); - -export default FileTypeSelector; diff --git a/frontend/src/pages/upload/NewTableSelector.jsx b/frontend/src/pages/upload/NewTableSelector.jsx deleted file mode 100644 index 64da7f3..0000000 --- a/frontend/src/pages/upload/NewTableSelector.jsx +++ /dev/null @@ -1,24 +0,0 @@ -import React from "react"; -import { - FormControl, - FormControlLabel, - FormLabel, - Radio, - RadioGroup, -} from "@mui/material"; - -const NewTableSelector = ({ isNewTable, setIsNewTable }) => ( - - Is a new table needed? - setIsNewTable(e.target.value)} - > - } label="Yes" /> - } label="No" /> - - -); - -export default NewTableSelector; diff --git a/frontend/src/pages/upload/UploadPage.jsx b/frontend/src/pages/upload/UploadPage.jsx index 51bc539..6e78104 100644 --- a/frontend/src/pages/upload/UploadPage.jsx +++ b/frontend/src/pages/upload/UploadPage.jsx @@ -1,22 +1,14 @@ import React, { useState, useEffect } from "react"; import { Box, Button, Stack, Typography } from "@mui/material"; import axios from "axios"; -import FileTypeSelector from "./FileTypeSelector"; -import EncodingSelector from "./EncodingSelector"; -import DescriptionField from "./DescriptionField"; -import NewTableSelector from "./NewTableSelector"; -import FileUploader from "./FileUploader"; import AlertSnackbar from "./AlertSnackbar"; +import DataProfileSelector from "./DataProfileSelector"; import { API_URL } from "../../utils/constants"; function UploadPage() { - const [fileTypes, setFileTypes] = useState([]); - const [encodings, setEncodings] = useState([]); - const [fileType, setFileType] = useState(""); - const [encoding, setEncoding] = useState(""); - const [description, setDescription] = useState(""); - const [isNewTable, setIsNewTable] = useState("no"); - const [file, setFile] = useState(null); + const [files, setFiles] = useState(null); + const [dataProfile, setDataProfile] = useState([]); + const [dataProfiles, setDataProfiles] = useState([]); const [analyzed, setAnalyzed] = useState(false); const [alertInfo, setAlertInfo] = useState({ open: false, @@ -25,23 +17,14 @@ function UploadPage() { }); useEffect(() => { - // Fetch file types axios - .get(`${API_URL}file_types/`) - .then((response) => setFileTypes(response.data)) - .catch((error) => console.error("Error fetching file types", error)); + .get(`${API_URL}data-profiles/org/`) + .then((response) => { + setDataProfiles(response.data); + }) + .catch((error) => console.error("Error fetching data profiles:", error)); }, []); - useEffect(() => { - if (fileType === "csv") { - // Fetch encodings - axios - .get(`${API_URL}encodings/`, { params: { file_type: fileType } }) - .then((response) => setEncodings(response.data)) - .catch((error) => console.error("Error fetching encodings", error)); - } - }, [fileType]); - const handleAnalyze = () => { // Placeholder for analyze functionality setAnalyzed(true); @@ -49,7 +32,7 @@ function UploadPage() { const handleSubmit = async () => { const formData = new FormData(); - formData.append("file", file); + formData.append("file", files); formData.append("extra_desc", description); formData.append("is_new_table", isNewTable === "yes"); formData.append("encoding", encoding); @@ -92,35 +75,25 @@ function UploadPage() { - + {/* */} - {fileType === "csv" && ( - + - )} - - - - - - + +