Skip to content

Commit 0379c45

Browse files
Merge pull request #387 from MEDomics-UdeS/MacOSHotFix
MacOS V1.0.0 Fix
2 parents c637479 + 4e38af5 commit 0379c45

11 files changed

Lines changed: 237 additions & 20 deletions

File tree

.DS_Store

0 Bytes
Binary file not shown.

build/pkg-scripts/postinstall

Lines changed: 42 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,55 @@
44
# Create a log file
55
LOG_FILE=/tmp/medomics_postinstall.log
66

7+
# Default MEDomics configuration directory
78
MEDOMICS_DIR=~/.medomics
89

9-
echo "Requirements installation" >>$LOG_FILE
10+
# Name of the requirements file
1011
REQUIREMENTS_FILE=merged_requirements.txt
11-
REQUIREMENTS_FULL_PATH=/Applications/MEDomicsLab.app/Contents/Resources/pythonEnv/$REQUIREMENTS_FILE
12+
13+
# Function to locate the MEDomicsLab installation path
14+
find_medomics_path() {
15+
if [ -d "/Applications/MEDomicsLab.app" ]; then
16+
echo "/Applications/MEDomicsLab.app"
17+
elif [ -d "$HOME/Applications/MEDomicsLab.app" ]; then
18+
echo "$HOME/Applications/MEDomicsLab.app"
19+
else
20+
echo ""
21+
fi
22+
}
23+
24+
# Locate MEDomicsLab installation path
25+
MEDOMICS_PATH=$(find_medomics_path)
26+
27+
if [ -z "$MEDOMICS_PATH" ]; then
28+
echo "MEDomicsLab installation not found." >>$LOG_FILE
29+
echo "Postinstall script failed: MEDomicsLab not installed." >>$LOG_FILE
30+
exit 1
31+
fi
32+
33+
# Construct the full requirements path
34+
REQUIREMENTS_FULL_PATH="$MEDOMICS_PATH/Contents/Resources/pythonEnv/$REQUIREMENTS_FILE"
1235

1336
echo "Checking if $REQUIREMENTS_FULL_PATH exists" >>$LOG_FILE
14-
if [ -f "$MEDOMICS_DIR/python/bin/pip3" ]; then
15-
echo "Installing requirements from $REQUIREMENTS_FULL_PATH" >>$LOG_FILE
16-
$MEDOMICS_DIR/python/bin/pip3 install -r $REQUIREMENTS_FULL_PATH >>$LOG_FILE
37+
if [ -f "$REQUIREMENTS_FULL_PATH" ]; then
38+
echo "Found requirements file at $REQUIREMENTS_FULL_PATH" >>$LOG_FILE
39+
40+
# Check if pip3 exists in the specified directory
41+
if [ -f "$MEDOMICS_DIR/python/bin/pip3" ]; then
42+
echo "Installing requirements from $REQUIREMENTS_FULL_PATH" >>$LOG_FILE
43+
$MEDOMICS_DIR/python/bin/pip3 install -r "$REQUIREMENTS_FULL_PATH" >>$LOG_FILE 2>&1
44+
if [ $? -eq 0 ]; then
45+
echo "Requirements installed successfully." >>$LOG_FILE
46+
else
47+
echo "Failed to install requirements." >>$LOG_FILE
48+
fi
49+
else
50+
echo "pip3 not found in $MEDOMICS_DIR/python/bin" >>$LOG_FILE
51+
fi
52+
else
53+
echo "Requirements file $REQUIREMENTS_FULL_PATH not found." >>$LOG_FILE
1754
fi
1855

19-
echo "Requirements installed" >>$LOG_FILE
2056
echo "Postinstall script completed" >>$LOG_FILE
2157

2258
exit 0

go_server/main

-633 KB
Binary file not shown.

main/background.js

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ if (isProd) {
226226
// Kill the process on the port
227227
// killProcessOnPort(serverPort)
228228
} else if (process.platform === "darwin") {
229-
execSync("pkill -f mongod")
229+
exec("pkill -f mongod")
230230
} else {
231231
try {
232232
execSync("killall mongod")
@@ -497,11 +497,11 @@ ipcMain.handle("checkMongoIsRunning", async (event) => {
497497
let port = MEDconfig.mongoPort
498498
let isRunning = false
499499
if (process.platform === "win32") {
500-
isRunning = execSync(`netstat -ano | findstr :${port}`).toString().trim() !== ""
500+
isRunning = exec(`netstat -ano | findstr :${port}`).toString().trim() !== ""
501501
} else if (process.platform === "darwin") {
502-
isRunning = execSync(`lsof -i :${port}`).toString().trim() !== ""
502+
isRunning = exec(`lsof -i :${port}`).toString().trim() !== ""
503503
} else {
504-
isRunning = execSync(`netstat -tuln | grep ${port}`).toString().trim() !== ""
504+
isRunning = exec(`netstat -tuln | grep ${port}`).toString().trim() !== ""
505505
}
506506

507507
return isRunning
@@ -562,8 +562,8 @@ function startMongoDB(workspacePath) {
562562
if (process.platform !== "darwin") {
563563
mongoProcess = spawn(mongod, ["--config", mongoConfigPath])
564564
} else {
565-
if (process.env.NODE_ENV === "production") {
566-
mongoProcess = spawn(path.join(process.env.HOME, ".medomics", "mongodb", "bin", "mongod"), ["--config", mongoConfigPath])
565+
if (fs.existsSync(getMongoDBPath())) {
566+
mongoProcess = spawn(getMongoDBPath(), ["--config", mongoConfigPath])
567567
} else {
568568
mongoProcess = spawn("/opt/homebrew/Cellar/mongodb-community/7.0.12/bin/mongod", ["--config", mongoConfigPath], { shell: true })
569569
}
@@ -642,14 +642,13 @@ export function getMongoDBPath() {
642642
console.error("mongod not found")
643643
return null
644644
} else if (process.platform === "darwin") {
645-
// Check if it is installed in the .medomics directory
646-
if (process.env.NODE_ENV === "production") {
647-
const binPath = path.join(app.getPath("sessionData"), ".medomics", "mongodb", "bin", "mongod")
645+
// Check if it is installed in the .medomics directory
646+
const binPath = path.join(process.env.HOME, ".medomics", "mongodb", "bin", "mongod")
648647
if (fs.existsSync(binPath)) {
649648
console.log("mongod found in .medomics directory")
650649
return binPath
651650
}
652-
} else {
651+
if (process.env.NODE_ENV !== "production") {
653652

654653
// Check if mongod is in the process.env.PATH
655654
const paths = process.env.PATH.split(path.delimiter)

main/utils/pythonEnv.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,10 @@ export function getBundledPythonEnvironment() {
146146
let pythonEnvironment = null
147147

148148
let bundledPythonPath = null
149+
150+
// Check if the python path can be found in the .medomics directory
151+
let medomicsDirExists = fs.existsSync(path.join(app.getPath("home"), ".medomics", "python"))
152+
149153
if (process.env.NODE_ENV === "production") {
150154
// Get the user path followed by .medomics
151155
let userPath = getHomePath()
@@ -165,7 +169,11 @@ export function getBundledPythonEnvironment() {
165169

166170
bundledPythonPath = path.join(userPath, ".medomics", "python")
167171
} else {
168-
bundledPythonPath = path.join(process.cwd(), "python")
172+
if (medomicsDirExists) {
173+
bundledPythonPath = path.join(getHomePath(), ".medomics", "python")
174+
} else {
175+
bundledPythonPath = path.join(process.cwd(), "python")
176+
}
169177
}
170178

171179
pythonEnvironment = path.join(bundledPythonPath, "bin", "python")

pythonCode/med_libs/MEDml/nodes/Analyze.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
import io
33
import json
44
import os
5+
from pathlib import Path
6+
import platform
7+
import tempfile
58
import uuid
69
from typing import Union
710

@@ -59,6 +62,9 @@ def _execute(self, experiment: dict = None, **kwargs) -> json:
5962
# Convert plot settings to lowercase
6063
if 'plot' in settings and type(settings['plot']) == str:
6164
settings['plot'] = settings['plot'].lower()
65+
# Set saving path for plot_model
66+
if 'save' in settings and settings['save']:
67+
settings['save'] = Path("/tmp") if platform.system().lower() == "darwin" else True
6268
plot_image = experiment['pycaret_exp'].plot_model(model, **settings)
6369

6470
# Save Image into MongoDB

pythonEnv/merged_requirements.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,10 @@ pyunpack==0.3
1919
ray==2.1.0
2020
requests==2.28.2
2121
scipy==1.10.1
22+
sweetviz==2.1.4
2223
torch==2.1.0
2324
tqdm==4.64.1
2425
transformers==4.30.2
2526
tsfresh==0.20.1
26-
wget==3.2
27+
wget==3.2
28+
ydata-profiling==4.6.1

renderer/components/dbComponents/InputToolsComponent.jsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import MEDprofilesPrepareData from "../input/MEDprofiles/MEDprofilesPrepareData"
66
import ModulePage from "../mainPages/moduleBasics/modulePage"
77
import { DataContext } from "../workspace/dataContext"
88
import BasicToolsDB from "./inputToolsDB/basicToolsDB"
9+
import DropDuplicatesToolsDB from "./inputToolsDB/dropDuplicatesToolsDB"
910
import FeatureReductionToolsDB from "./inputToolsDB/featureReductionToolsDB/featureReductionToolsDB"
1011
import GroupingTaggingToolsDB from "./inputToolsDB/groupingTaggingToolsDB"
1112
import HoldoutSetCreationToolsDB from "./inputToolsDB/holdoutSetCreationToolsDB"
@@ -123,6 +124,9 @@ const InputToolsComponent = ({ data, exportOptions, refreshData, columns, transf
123124
<Panel header="Basic Tools" toggleable collapsed={true}>
124125
<BasicToolsDB exportOptions={exportOptions} refreshData={refreshData} currentCollection={!altData ? null : altData.id} />
125126
</Panel>
127+
<Panel header="Drop Duplicates Tools" toggleable collapsed={true}>
128+
<DropDuplicatesToolsDB exportOptions={exportOptions} currentCollection={!altData ? null : altData.id} />
129+
</Panel>
126130
<Panel header="Transform Column Tools" toggleable collapsed={true}>
127131
<TransformColumnToolsDB columns={columns} transformData={transformData} currentCollection={!altData ? null : altData.id} refreshData={refreshData} />
128132
</Panel>
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
import React, { useState, useEffect, useContext } from "react"
2+
import { Message } from "primereact/message"
3+
import { DataTable } from "primereact/datatable"
4+
import { Column } from "primereact/column"
5+
import { Button } from "primereact/button"
6+
import { toast } from "react-toastify"
7+
import { connectToMongoDB } from "../../mongoDB/mongoDBUtils"
8+
import { DataContext } from "../../workspace/dataContext"
9+
10+
const DropDuplicatesToolsDB = ({ currentCollection }) => {
11+
const { globalData } = useContext(DataContext)
12+
const [data, setData] = useState([])
13+
const [columns, setColumns] = useState([])
14+
const [duplicateColumns, setDuplicateColumns] = useState([])
15+
const [selectedColumn, setSelectedColumn] = useState(null)
16+
const [loadingData, setLoadingData] = useState(false)
17+
18+
const fetchData = async () => {
19+
setLoadingData(true)
20+
if (!currentCollection) {
21+
toast.warn("No collection selected.")
22+
return
23+
}
24+
25+
try {
26+
const db = await connectToMongoDB()
27+
const collection = db.collection(globalData[currentCollection].id)
28+
29+
const documents = await collection.find({}).limit(10).toArray()
30+
setData(documents)
31+
32+
const sampleDocument = documents[0]
33+
if (sampleDocument) {
34+
const allKeys = Object.keys(sampleDocument).filter((key) => key !== "_id")
35+
const columnStructure = allKeys.map((key) => ({
36+
field: key,
37+
header: key.charAt(0).toUpperCase() + key.slice(1)
38+
}))
39+
setColumns(columnStructure)
40+
41+
findDuplicateColumns(allKeys, collection)
42+
}
43+
} catch (error) {
44+
console.error("Error fetching data:", error)
45+
toast.error("An error occurred while fetching data.")
46+
} finally {
47+
setLoadingData(false)
48+
}
49+
}
50+
51+
const findDuplicateColumns = async (allKeys, collection) => {
52+
let duplicatePairs = []
53+
54+
try {
55+
for (let i = 0; i < allKeys.length; i++) {
56+
for (let j = i + 1; j < allKeys.length; j++) {
57+
const column1 = allKeys[i]
58+
const column2 = allKeys[j]
59+
60+
const pipeline = [{ $project: { areEqual: { $eq: [`$${column1}`, `$${column2}`] } } }, { $match: { areEqual: false } }, { $count: "mismatchedDocuments" }]
61+
62+
const result = await collection.aggregate(pipeline).toArray()
63+
if (result.length === 0 || (result[0]?.mismatchedDocuments || 0) === 0) {
64+
duplicatePairs.push({ column1, column2 })
65+
}
66+
}
67+
}
68+
69+
setDuplicateColumns(duplicatePairs)
70+
} catch (error) {
71+
console.error("Error finding duplicate columns:", error)
72+
toast.error("An error occurred while finding duplicate columns.")
73+
}
74+
}
75+
76+
const handleDeleteColumn = async () => {
77+
if (!selectedColumn) {
78+
toast.warn("Please select a column to delete.")
79+
return
80+
}
81+
82+
try {
83+
const db = await connectToMongoDB()
84+
const collection = db.collection(globalData[currentCollection].id)
85+
86+
await collection.updateMany({}, { $unset: { [selectedColumn]: "" } })
87+
88+
toast.success(`Column "${selectedColumn}" has been deleted.`)
89+
setSelectedColumn(null)
90+
await fetchData()
91+
} catch (error) {
92+
console.error("Error deleting column:", error)
93+
toast.error("An error occurred while deleting the column.")
94+
}
95+
}
96+
97+
useEffect(() => {
98+
fetchData()
99+
}, [currentCollection])
100+
101+
return (
102+
<div
103+
style={{
104+
display: "flex",
105+
flexDirection: "column",
106+
justifyContent: "center",
107+
alignItems: "center",
108+
padding: "5px"
109+
}}
110+
>
111+
{loadingData && <Message severity="info" text="Loading..." style={{ marginBottom: "15px" }} />}
112+
<Message severity="info" text="This tool identifies duplicate columns in your dataset and allows you to choose one for deletion." style={{ marginBottom: "15px" }} />
113+
<Message severity="success" text={`Current Collection: ${globalData[currentCollection]?.name || "None"}`} style={{ marginBottom: "15px" }} />
114+
{data.length > 0 && (
115+
<DataTable value={data} paginator rows={5} rowsPerPageOptions={[5, 10, 15]} className="p-datatable-gridlines">
116+
{columns.map((col) => (
117+
<Column
118+
key={col.field}
119+
field={col.field}
120+
header={col.header}
121+
sortable
122+
style={{
123+
backgroundColor: col.field === selectedColumn ? "#ee6b6e" : "transparent"
124+
}} // Highlight the selected column
125+
/>
126+
))}
127+
</DataTable>
128+
)}
129+
{duplicateColumns.length > 0 && (
130+
<div style={{ marginTop: "20px" }}>
131+
<h4>Duplicate Columns</h4>
132+
<ul style={{ listStyleType: "none", padding: 0 }}>
133+
{duplicateColumns.map((pair, index) => (
134+
<li key={index} style={{ marginBottom: "10px" }}>
135+
{pair.column1} and {pair.column2}{" "}
136+
<Button
137+
label={`Delete ${pair.column2}`}
138+
className="p-button-danger"
139+
onClick={() => setSelectedColumn(pair.column2)}
140+
style={{
141+
marginLeft: "10px",
142+
marginTop: "5px",
143+
display: "inline-block"
144+
}}
145+
/>
146+
</li>
147+
))}
148+
</ul>
149+
</div>
150+
)}
151+
152+
{selectedColumn && (
153+
<div style={{ marginTop: "20px", textAlign: "center" }}>
154+
<h4>Selected Column: {selectedColumn}</h4>
155+
<Button label="Confirm Delete" icon="pi pi-trash" className="p-button-danger" onClick={handleDeleteColumn} />
156+
</div>
157+
)}
158+
</div>
159+
)
160+
}
161+
162+
export default DropDuplicatesToolsDB

renderer/components/layout/layoutManager.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ const LayoutManager = (props) => {
5050
console.log("port set to: ", port)
5151
if (port) {
5252
ipcRenderer.invoke("getBundledPythonEnvironment").then((res) => {
53-
console.log("Python imbedded: ", res)
53+
console.log("Python embedded: " + res)
5454
if (res !== null) {
5555
requestBackend(
5656
port,

0 commit comments

Comments
 (0)