Skip to content

Commit 769466a

Browse files
authored
Merge pull request #571 from Steinbeck-Lab/development
Development
2 parents ba7faea + 328f1c0 commit 769466a

File tree

13 files changed

+183
-158
lines changed

13 files changed

+183
-158
lines changed

.github/workflows/dev-build.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ jobs:
5050
context: ./frontend
5151
file: ./frontend/Dockerfile
5252
push: true
53+
build-args: |
54+
REACT_APP_API_URL=https://dev.api.naturalproducts.net/latest
5355
# REACT_APP_API_URL will use the default from frontend/Dockerfile (https://dev.api.naturalproducts.net/latest)
5456
# If a specific one is needed for this dev build, add build-args here.
5557
# build-args: |

.github/workflows/prod-build.yml

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# This worklflow will perform following actions when a release is published:
1+
# This workflow will perform the following actions when a release is published:
22
# - Fetch Latest release.
33
# - Build the latest docker image in production.
44
# - Push the docker image to Github Artifact Registry-Prod.
@@ -7,15 +7,15 @@
77
# - name: Nisha Sharma
88
99

10-
name : Prod Build, Test and Publish
10+
name: Prod Build, Test and Publish
1111

1212
on:
1313
release:
1414
types: [published]
1515

1616
env:
17-
DOCKER_HUB_USERNAME : ${{ secrets.DOCKER_USERNAME }}
18-
DOCKER_HUB_PASSWORD : ${{ secrets.DOCKER_PASSWORD }}
17+
DOCKER_HUB_USERNAME: ${{ secrets.DOCKER_USERNAME }}
18+
DOCKER_HUB_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
1919
REPOSITORY_NAME: cheminformatics-microservice
2020
REPOSITORY_NAMESPACE: nfdi4chem
2121

@@ -35,12 +35,11 @@ jobs:
3535
exclude_types: "draft"
3636
view_top: 10
3737

38-
- name: "Print release name"
39-
run: |
40-
echo "tag_name: ${{ steps.fetch-latest-release.outputs.tag_name }}"
38+
- name: Print release name
39+
run: echo "tag_name: ${{ steps.fetch-latest-release.outputs.tag_name }}"
4140

4241
- name: Log in to Docker Hub
43-
uses: docker/login-action@f4ef78c080cd8ba55a85445d5b36e214a81df20a
42+
uses: docker/login-action@v4
4443
with:
4544
username: ${{ env.DOCKER_HUB_USERNAME }}
4645
password: ${{ env.DOCKER_HUB_PASSWORD }}
@@ -76,7 +75,7 @@ jobs:
7675
file: ./frontend/Dockerfile
7776
push: true
7877
build-args: |
79-
REACT_APP_API_URL=/api/latest # For prod Traefik setup
78+
REACT_APP_API_URL=https://api.naturalproducts.net/latest
8079
tags: |
8180
${{ env.REPOSITORY_NAMESPACE }}/${{ env.REPOSITORY_NAME }}:app-${{ steps.fetch-latest-release.outputs.tag_name }}
82-
${{ env.REPOSITORY_NAMESPACE }}/${{ env.REPOSITORY_NAME }}:app
81+
${{ env.REPOSITORY_NAMESPACE }}/${{ env.REPOSITORY_NAME }}:app

frontend/src/components/chem/AllFiltersView.jsx

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ const AllFiltersView = () => {
2323
const [error, setError] = useState(null);
2424
const [results, setResults] = useState([]);
2525
const [copied, setCopied] = useState(false);
26-
const [filterOperator, setFilterOperator] = useState("AND"); // Default to AND logic
26+
const [filterOperator, setFilterOperator] = useState("OR"); // Default to OR logic
2727
const [showInfoModal, setShowInfoModal] = useState(false); // State for showing info modal
2828
const { addRecentMolecule } = useAppContext(); // Assuming context provides this function
2929

@@ -800,9 +800,8 @@ const AllFiltersView = () => {
800800
</div>
801801
)}
802802

803-
{/* Initial State / Info Box */}
804-
{/* Show only if not loading, no error, no input has been entered, and no results */}
805-
{!loading && !error && !smilesInput.trim() && results.length === 0 && (
803+
{/* About Chemical Filters Info Box - Always visible */}
804+
{!loading && !error && (
806805
<div
807806
className="bg-blue-50 dark:bg-blue-900 dark:bg-opacity-20 border border-blue-200 dark:border-blue-800 rounded-lg p-6 shadow"
808807
role="complementary"

frontend/src/components/common/Header.jsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -126,10 +126,10 @@ const Header = () => {
126126
const logoDark = "https://raw.githubusercontent.com/Steinbeck-Lab/cheminformatics-microservice/main/public/img/logo_small_inverted.png";
127127
const logoLight = "https://raw.githubusercontent.com/Steinbeck-Lab/cheminformatics-microservice/main/public/img/logo_small.png";
128128

129-
// Calculate header background classes based on scroll state
129+
// Calculate header background classes based on scroll state - always white in light mode
130130
const headerBgClasses = isScrolled
131-
? `backdrop-blur-lg ${isDarkMode ? 'bg-slate-900/90' : 'bg-white/90'} shadow-lg ${isDarkMode ? 'shadow-slate-900/30' : 'shadow-slate-200/50'}`
132-
: `backdrop-blur-sm ${isDarkMode ? 'bg-slate-900/80' : 'bg-white/80'} shadow-md ${isDarkMode ? 'shadow-slate-900/20' : 'shadow-slate-200/30'}`;
131+
? `backdrop-blur-lg ${isDarkMode ? 'bg-slate-900/90' : 'bg-white'} shadow-lg ${isDarkMode ? 'shadow-slate-900/30' : 'shadow-slate-200/50'}`
132+
: `backdrop-blur-sm ${isDarkMode ? 'bg-slate-900/80' : 'bg-white'} shadow-md ${isDarkMode ? 'shadow-slate-900/20' : 'shadow-slate-200/30'}`;
133133

134134
return (
135135
<motion.header
@@ -295,7 +295,7 @@ const Header = () => {
295295
className={`md:hidden absolute top-full left-0 right-0 overflow-hidden backdrop-blur-md ${
296296
isDarkMode
297297
? 'bg-slate-900/95 border-t border-slate-800/40 shadow-lg shadow-slate-900/50'
298-
: 'bg-white/95 border-t border-slate-200/70 shadow-lg shadow-slate-200/50'
298+
: 'bg-white border-t border-slate-200/70 shadow-lg shadow-slate-200/50'
299299
}`}
300300
variants={mobileMenuVariants}
301301
initial="hidden"

frontend/src/components/depict/Depict2DMultiView.jsx

Lines changed: 46 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -337,31 +337,52 @@ const BatchDepictionView = () => {
337337
};
338338

339339
// Download a single depiction image
340-
const downloadSingleDepiction = (depiction) => {
341-
// Check if depictService and the method exist before proceeding
342-
if (!depictService || typeof depictService.get2DDepictionUrl !== 'function') {
343-
console.error("depictService.get2DDepictionUrl is not available for single download.");
344-
setError("Depiction service is not configured correctly.");
345-
return;
340+
const downloadSingleDepiction = async (depiction) => {
341+
try {
342+
// Check if depictService and the method exist before proceeding
343+
if (!depictService || typeof depictService.get2DDepictionUrl !== 'function') {
344+
console.error("depictService.get2DDepictionUrl is not available for single download.");
345+
setError("Depiction service is not configured correctly.");
346+
return;
347+
}
348+
349+
setLoading(true); // Show loading indicator while downloading
350+
const rotation = rotations[depiction.id] || 0;
351+
352+
// Generate URL with current options and selected download format
353+
const options = {
354+
toolkit, width, height, rotate: rotation,
355+
CIP: toolkit === 'cdk' ? showCIP : undefined,
356+
unicolor: useUnicolor, highlight: highlight || undefined,
357+
format: downloadFormat // Use selected format for single download too
358+
};
359+
360+
// Get the URL for fetching the image
361+
const url = depictService.get2DDepictionUrl(depiction.smiles, options);
362+
363+
// Fetch the image data as a blob
364+
const response = await fetch(url);
365+
if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
366+
367+
const blob = await response.blob();
368+
const downloadUrl = URL.createObjectURL(blob);
369+
370+
// Trigger download using an anchor tag
371+
const a = document.createElement('a');
372+
a.href = downloadUrl;
373+
a.download = `${depiction.title.replace(/[^a-z0-9]/gi, '_').toLowerCase() || 'molecule'}.${downloadFormat}`;
374+
document.body.appendChild(a);
375+
a.click();
376+
document.body.removeChild(a);
377+
378+
// Clean up the blob URL
379+
URL.revokeObjectURL(downloadUrl);
380+
} catch (err) {
381+
console.error("Error downloading single depiction:", err);
382+
setError(`Error downloading depiction: ${err.message || 'Unknown error'}`);
383+
} finally {
384+
setLoading(false); // Hide loading indicator
346385
}
347-
const rotation = rotations[depiction.id] || 0;
348-
// Generate URL with current options and selected download format
349-
const options = {
350-
toolkit, width, height, rotate: rotation,
351-
CIP: toolkit === 'cdk' ? showCIP : undefined,
352-
unicolor: useUnicolor, highlight: highlight || undefined,
353-
format: downloadFormat // Use selected format for single download too
354-
};
355-
// Use a potentially different URL for download if format differs
356-
const url = depictService.get2DDepictionUrl(depiction.smiles, options);
357-
358-
// Trigger download using an anchor tag
359-
const a = document.createElement('a');
360-
a.href = url;
361-
a.download = `${depiction.title.replace(/[^a-z0-9]/gi, '_').toLowerCase() || 'molecule'}.${downloadFormat}`;
362-
document.body.appendChild(a);
363-
a.click();
364-
document.body.removeChild(a);
365386
};
366387

367388

@@ -722,6 +743,7 @@ const BatchDepictionView = () => {
722743
className="p-1.5 rounded-md text-gray-500 dark:text-gray-400 hover:text-gray-800 dark:hover:text-white hover:bg-gray-200 dark:hover:bg-gray-600 transition-colors focus:outline-none focus:ring-1 focus:ring-blue-500"
723744
title={`Download ${downloadFormat.toUpperCase()}`}
724745
aria-label={`Download ${depiction.title} as ${downloadFormat.toUpperCase()}`}
746+
disabled={loading}
725747
>
726748
<HiOutlineDownload className="h-5 w-5" />
727749
</button>

frontend/src/components/depict/Depict3DView.jsx

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -430,12 +430,33 @@ const Depict3DView = ({ isActive = true }) => {
430430

431431
// Handler to reset the camera view
432432
const handleResetView = () => {
433-
if (!viewerRef.current || !viewerInitialized) return;
433+
if (!viewerRef.current || !viewerInitialized || !modelRef.current) return;
434434
try {
435+
// Stop spinning if active
436+
if (spin) {
437+
viewerRef.current.spin(false);
438+
}
439+
440+
// Make sure we have a valid model before resetting
441+
if (viewerRef.current.getModel() && modelRef.current) {
442+
// Reset the view more safely
443+
viewerRef.current.setView(new Float32Array([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]),
444+
100); // Use identity matrix
445+
}
446+
447+
// Center the molecule
435448
viewerRef.current.zoomTo();
449+
450+
// Re-apply spin if needed
451+
if (spin) {
452+
viewerRef.current.spin(spin);
453+
}
454+
455+
// Render the updated view
436456
viewerRef.current.render();
437457
} catch (e) {
438-
console.warn("Error resetting view:", e);
458+
console.error("Error resetting view:", e);
459+
setError(`Failed to reset view: ${e.message}`);
439460
}
440461
};
441462

frontend/src/components/depict/StructureDrawView.jsx

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import {
33
HiOutlineClipboardCopy,
44
HiOutlineCheck,
55
HiOutlineExclamationCircle,
6-
HiOutlineBeaker,
76
HiOutlineInformationCircle,
87
HiOutlineRefresh,
98
HiOutlinePencil,
@@ -383,7 +382,7 @@ const StructureDrawView = () => {
383382
};
384383

385384
return (
386-
<div className="flex flex-col gap-6 p-4 md:p-6 bg-gradient-to-br from-sky-50 to-indigo-100 dark:from-gray-900 dark:to-slate-900 min-h-screen">
385+
<div className="flex flex-col gap-6 p-4 md:p-6 bg-white dark:bg-gray-900 min-h-screen">
387386
{/* Header with animated background */}
388387
<div className="bg-gradient-to-r from-blue-600 to-purple-700 dark:from-blue-700 dark:to-purple-900 rounded-xl shadow-xl overflow-hidden relative">
389388
{/* Animated background elements */}
@@ -393,20 +392,7 @@ const StructureDrawView = () => {
393392
<div className="absolute left-1/3 top-1/2 w-32 h-32 rounded-full bg-white transform -translate-y-1/2"></div>
394393
</div>
395394

396-
<div className="relative p-8 md:p-10 flex flex-col md:flex-row items-center justify-between gap-6">
397-
{/* Title and description */}
398-
<div className="text-white space-y-2 text-center md:text-left">
399-
<h1 className="text-3xl md:text-4xl font-bold">Molecular Structure Editor</h1>
400-
<p className="text-blue-100 dark:text-blue-200 opacity-90 max-w-xl">
401-
Draw, edit, and convert chemical structures
402-
</p>
403-
</div>
404-
405-
{/* Decorative icon */}
406-
<div className="hidden md:flex items-center justify-center bg-white/10 backdrop-blur-sm p-6 rounded-full w-24 h-24 border border-white/20 shadow-lg">
407-
<HiOutlineBeaker className="w-12 h-12 text-white" />
408-
</div>
409-
</div>
395+
410396
</div>
411397

412398
{/* Copy Modal - For fallback copying */}

frontend/src/components/depict/StructureVisualizerView.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ const StructureVisualizerView = () => {
172172
};
173173

174174
return (
175-
<div className="flex flex-col gap-6 p-4 md:p-6 bg-gradient-to-br from-sky-50 to-indigo-100 dark:from-gray-900 dark:to-slate-900 min-h-screen">
175+
<div className="flex flex-col gap-6 p-4 md:p-6 bg-white dark:bg-gray-900 min-h-screen">
176176
{/* Header with animated background */}
177177

178178
{/* Main content area */}

frontend/src/components/tools/StructureGenView.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,12 +106,12 @@ const StructureGenView = () => {
106106
value={formula}
107107
onChange={(e) => setFormula(e.target.value)}
108108
placeholder="e.g., C6H6"
109-
className="w-full form-control text-sm" // Use adaptive form-control
109+
className="w-full form-control text-sm text-[var(--text-primary)] dark:text-[var(--text-primary)] placeholder-slate-400 dark:placeholder-slate-500" // Enhanced styling for dark mode visibility
110110
required
111111
/>
112112
{/* Use adaptive text color */}
113113
<p className="mt-1 text-xs text-slate-500 dark:text-slate-400">
114-
Enter a molecular formula (e.g., C6H6, C8H10N4O2). Max 10 heavy atoms.
114+
Enter a molecular formula (e.g., C6H6, C8H10). Max 10 heavy atoms.
115115
</p>
116116
</div>
117117

frontend/src/pages/DepictPage.jsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,7 @@ const tabs = [
2828
name: "2D Depiction",
2929
component: Depict2DMultiView,
3030
icon: HiOutlineViewGrid,
31-
description: `Generate 2D depictions for multiple molecules at once.
32-
Enter one SMILES string per line.
33-
Optional: add a title after each SMILES separated by a space or tab.`,
31+
description: "Generate 2D depictions for multiple molecules at once.",
3432
},
3533
{
3634
id: "3d-depiction",

0 commit comments

Comments
 (0)