Compare commits
4 Commits
v1.0.0
...
socket_rew
| Author | SHA1 | Date | |
|---|---|---|---|
| 305650925e | |||
| d3e0ef95d4 | |||
| 809505ec84 | |||
| 73fa23e434 |
47
.github/workflows/main.yml
vendored
Normal file
47
.github/workflows/main.yml
vendored
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
name: Release Monaco
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- 'v*' # Triggers on version tags like v1.0.0, v1.1.0-beta, etc.
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-and-release:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
go-version: [1.22.3] # Adjust to your Go version
|
||||||
|
os: [linux, darwin, windows]
|
||||||
|
arch: [amd64, arm64]
|
||||||
|
exclude:
|
||||||
|
- os: darwin
|
||||||
|
arch: arm64
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up Go
|
||||||
|
uses: actions/setup-go@v5
|
||||||
|
with:
|
||||||
|
go-version: ${{ matrix.go-version }}
|
||||||
|
|
||||||
|
- name: Build binary
|
||||||
|
env:
|
||||||
|
GOOS: ${{ matrix.os }}
|
||||||
|
GOARCH: ${{ matrix.arch }}
|
||||||
|
run: |
|
||||||
|
cd backend
|
||||||
|
go mod tidy
|
||||||
|
GOOS=$GOOS GOARCH=$GOARCH go build -o monaco-${{ matrix.os }}-${{ matrix.arch }} .
|
||||||
|
|
||||||
|
- name: Create Release
|
||||||
|
uses: softprops/action-gh-release@v2
|
||||||
|
if: startsWith(github.ref, 'refs/tags/')
|
||||||
|
with:
|
||||||
|
files: |
|
||||||
|
backend/monaco-${{ matrix.os }}-${{ matrix.arch }}
|
||||||
|
draft: false
|
||||||
|
prerelease: false
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
@@ -1 +1 @@
|
|||||||
VITE_API_URL="https://monacoapi.thearnab.tech"
|
VITE_API_URL="http://localhost:8080"
|
||||||
@@ -60,6 +60,11 @@ const EditorArea = ({
|
|||||||
const [terminalOutput, setTerminalOutput] = useState([]);
|
const [terminalOutput, setTerminalOutput] = useState([]);
|
||||||
const [activeRunningFile, setActiveRunningFile] = useState(null);
|
const [activeRunningFile, setActiveRunningFile] = useState(null);
|
||||||
|
|
||||||
|
// Add a new state for user input
|
||||||
|
const [userInput, setUserInput] = useState("");
|
||||||
|
// Add a new state for waiting for input
|
||||||
|
const [waitingForInput, setWaitingForInput] = useState(false);
|
||||||
|
|
||||||
// Focus the input when new file modal opens
|
// Focus the input when new file modal opens
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isNewFileModalOpen && newFileInputRef.current) {
|
if (isNewFileModalOpen && newFileInputRef.current) {
|
||||||
@@ -502,7 +507,7 @@ Happy coding!`;
|
|||||||
width: `calc(100% - ${sidebarVisible ? sidebarWidth : 0}px)`
|
width: `calc(100% - ${sidebarVisible ? sidebarWidth : 0}px)`
|
||||||
};
|
};
|
||||||
|
|
||||||
// Update the run code function to work with backend
|
// Modify the handleRunCode function to prompt for input first
|
||||||
const handleRunCode = async () => {
|
const handleRunCode = async () => {
|
||||||
if (!activeFile) return;
|
if (!activeFile) return;
|
||||||
|
|
||||||
@@ -512,8 +517,8 @@ Happy coding!`;
|
|||||||
setPanelVisible(true);
|
setPanelVisible(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set running state
|
// Set state to waiting for input
|
||||||
setIsRunning(true);
|
setWaitingForInput(true);
|
||||||
setActiveRunningFile(activeFile.id);
|
setActiveRunningFile(activeFile.id);
|
||||||
|
|
||||||
// Clear previous output and add new command
|
// Clear previous output and add new command
|
||||||
@@ -521,23 +526,40 @@ Happy coding!`;
|
|||||||
const language = getLanguageFromExtension(fileExtension);
|
const language = getLanguageFromExtension(fileExtension);
|
||||||
|
|
||||||
const newOutput = [
|
const newOutput = [
|
||||||
{ type: 'command', content: `$ run ${activeFile.id}` }
|
{ type: 'command', content: `$ run ${activeFile.id}` },
|
||||||
|
{ type: 'output', content: 'Waiting for input (press Enter if no input is needed)...' }
|
||||||
];
|
];
|
||||||
setTerminalOutput(newOutput);
|
setTerminalOutput(newOutput);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add a new function to handle input submission
|
||||||
|
const handleInputSubmit = async () => {
|
||||||
|
if (!activeFile || !waitingForInput) return;
|
||||||
|
|
||||||
|
// Set running state
|
||||||
|
setIsRunning(true);
|
||||||
|
setWaitingForInput(false);
|
||||||
|
|
||||||
|
// Add message that we're running with the input
|
||||||
|
setTerminalOutput(prev => [
|
||||||
|
...prev,
|
||||||
|
{ type: 'output', content: userInput ? `Using input: "${userInput}"` : 'Running without input...' }
|
||||||
|
]);
|
||||||
|
|
||||||
// Use API URL from environment variable
|
// Use API URL from environment variable
|
||||||
const apiUrl = import.meta.env.VITE_API_URL || 'http://localhost:8080';
|
const apiUrl = import.meta.env.VITE_API_URL || 'http://localhost:8080';
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Step 1: Submit code to backend
|
// Now make the API call with the input that was entered
|
||||||
const submitResponse = await fetch(`${apiUrl}/submit`, {
|
const submitResponse = await fetch(`${apiUrl}/submit`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
language: language,
|
language: getLanguageFromExtension(activeFile.id.split('.').pop().toLowerCase()),
|
||||||
code: activeFile.content
|
code: activeFile.content,
|
||||||
|
input: userInput
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -640,6 +662,37 @@ Happy coding!`;
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Add this function above the return statement
|
||||||
|
const handleDownloadFile = () => {
|
||||||
|
if (!activeFile) return;
|
||||||
|
|
||||||
|
// Create a blob with the file content
|
||||||
|
const blob = new Blob([activeFile.content], { type: 'text/plain' });
|
||||||
|
|
||||||
|
// Create a URL for the blob
|
||||||
|
const url = URL.createObjectURL(blob);
|
||||||
|
|
||||||
|
// Create a temporary anchor element
|
||||||
|
const a = document.createElement('a');
|
||||||
|
a.href = url;
|
||||||
|
|
||||||
|
// Get just the filename without path
|
||||||
|
const fileName = activeFile.id.includes('/') ?
|
||||||
|
activeFile.id.split('/').pop() :
|
||||||
|
activeFile.id;
|
||||||
|
|
||||||
|
// Set the download attribute with the filename
|
||||||
|
a.download = fileName;
|
||||||
|
|
||||||
|
// Append to the document, click it, and then remove it
|
||||||
|
document.body.appendChild(a);
|
||||||
|
a.click();
|
||||||
|
document.body.removeChild(a);
|
||||||
|
|
||||||
|
// Release the object URL
|
||||||
|
URL.revokeObjectURL(url);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="editor-container">
|
<div className="editor-container">
|
||||||
{sidebarVisible && (
|
{sidebarVisible && (
|
||||||
@@ -785,13 +838,18 @@ Happy coding!`;
|
|||||||
height={panelHeight}
|
height={panelHeight}
|
||||||
terminalOutput={terminalOutput}
|
terminalOutput={terminalOutput}
|
||||||
isRunning={isRunning}
|
isRunning={isRunning}
|
||||||
|
waitingForInput={waitingForInput}
|
||||||
activeRunningFile={activeRunningFile}
|
activeRunningFile={activeRunningFile}
|
||||||
initialTab="terminal"
|
initialTab="terminal"
|
||||||
onClose={togglePanel} // Use the new function
|
onClose={togglePanel}
|
||||||
|
userInput={userInput}
|
||||||
|
onUserInputChange={setUserInput}
|
||||||
|
onInputSubmit={handleInputSubmit}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{/* Modify the editor-actions div to include the download button */}
|
||||||
<div className="editor-actions">
|
<div className="editor-actions">
|
||||||
<button
|
<button
|
||||||
className="editor-action-button"
|
className="editor-action-button"
|
||||||
@@ -801,6 +859,30 @@ Happy coding!`;
|
|||||||
>
|
>
|
||||||
<Save size={16} />
|
<Save size={16} />
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
{/* Add download button */}
|
||||||
|
<button
|
||||||
|
className="editor-action-button"
|
||||||
|
onClick={handleDownloadFile}
|
||||||
|
disabled={!activeTab}
|
||||||
|
title="Download file"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
strokeWidth="2"
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
>
|
||||||
|
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path>
|
||||||
|
<polyline points="7 10 12 15 17 10"></polyline>
|
||||||
|
<line x1="12" y1="15" x2="12" y2="3"></line>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{isNewFileModalOpen && (
|
{isNewFileModalOpen && (
|
||||||
@@ -860,6 +942,61 @@ Happy coding!`;
|
|||||||
<Edit size={14} className="mr-1" />
|
<Edit size={14} className="mr-1" />
|
||||||
Rename
|
Rename
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Add download option - only show for files */}
|
||||||
|
{contextMenuTarget?.type === 'file' && (
|
||||||
|
<div className="context-menu-item" onClick={() => {
|
||||||
|
// Find the file in the files array
|
||||||
|
const file = files.find(f => f.id === contextMenuTarget.path);
|
||||||
|
if (file) {
|
||||||
|
// Create a blob with the file content
|
||||||
|
const blob = new Blob([file.content], { type: 'text/plain' });
|
||||||
|
|
||||||
|
// Create a URL for the blob
|
||||||
|
const url = URL.createObjectURL(blob);
|
||||||
|
|
||||||
|
// Create a temporary anchor element
|
||||||
|
const a = document.createElement('a');
|
||||||
|
a.href = url;
|
||||||
|
|
||||||
|
// Get just the filename without path
|
||||||
|
const fileName = file.id.includes('/') ?
|
||||||
|
file.id.split('/').pop() :
|
||||||
|
file.id;
|
||||||
|
|
||||||
|
// Set the download attribute with the filename
|
||||||
|
a.download = fileName;
|
||||||
|
|
||||||
|
// Append to the document, click it, and then remove it
|
||||||
|
document.body.appendChild(a);
|
||||||
|
a.click();
|
||||||
|
document.body.removeChild(a);
|
||||||
|
|
||||||
|
// Release the object URL
|
||||||
|
URL.revokeObjectURL(url);
|
||||||
|
}
|
||||||
|
closeContextMenu();
|
||||||
|
}}>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="14"
|
||||||
|
height="14"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
strokeWidth="2"
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
className="mr-1"
|
||||||
|
>
|
||||||
|
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path>
|
||||||
|
<polyline points="7 10 12 15 17 10"></polyline>
|
||||||
|
<line x1="12" y1="15" x2="12" y2="3"></line>
|
||||||
|
</svg>
|
||||||
|
Download
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
<div className="context-menu-item delete" onClick={() => {
|
<div className="context-menu-item delete" onClick={() => {
|
||||||
deleteItem(contextMenuTarget.path, contextMenuTarget.type);
|
deleteItem(contextMenuTarget.path, contextMenuTarget.type);
|
||||||
closeContextMenu();
|
closeContextMenu();
|
||||||
|
|||||||
@@ -6,9 +6,13 @@ const Panel = ({
|
|||||||
height,
|
height,
|
||||||
terminalOutput = [],
|
terminalOutput = [],
|
||||||
isRunning = false,
|
isRunning = false,
|
||||||
|
waitingForInput = false,
|
||||||
activeRunningFile = null,
|
activeRunningFile = null,
|
||||||
initialTab = "terminal",
|
initialTab = "terminal",
|
||||||
onClose
|
onClose,
|
||||||
|
userInput = "",
|
||||||
|
onUserInputChange,
|
||||||
|
onInputSubmit
|
||||||
}) => {
|
}) => {
|
||||||
const [activeTab, setActiveTab] = useState(initialTab);
|
const [activeTab, setActiveTab] = useState(initialTab);
|
||||||
|
|
||||||
@@ -28,9 +32,22 @@ const Panel = ({
|
|||||||
{line.type === 'command' ? <span className="terminal-prompt">$</span> : ''} {line.content}
|
{line.type === 'command' ? <span className="terminal-prompt">$</span> : ''} {line.content}
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
{isRunning && (
|
{waitingForInput && (
|
||||||
<div className="terminal-line">
|
<div className="terminal-line">
|
||||||
<span className="terminal-cursor"></span>
|
<span className="terminal-prompt">Input:</span>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
className="terminal-input"
|
||||||
|
value={userInput}
|
||||||
|
onChange={(e) => onUserInputChange && onUserInputChange(e.target.value)}
|
||||||
|
placeholder="Enter input for your program here..."
|
||||||
|
onKeyDown={(e) => {
|
||||||
|
if (e.key === 'Enter' && onInputSubmit) {
|
||||||
|
onInputSubmit();
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
autoFocus
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -924,6 +924,21 @@ body {
|
|||||||
color: #569cd6;
|
color: #569cd6;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.terminal-input {
|
||||||
|
background-color: transparent;
|
||||||
|
border: none;
|
||||||
|
color: inherit;
|
||||||
|
font-family: monospace;
|
||||||
|
font-size: inherit;
|
||||||
|
margin-left: 8px;
|
||||||
|
outline: none;
|
||||||
|
width: calc(100% - 60px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.terminal-input:focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
.terminal-line.info {
|
.terminal-line.info {
|
||||||
color: #75beff;
|
color: #75beff;
|
||||||
}
|
}
|
||||||
|
|||||||
56
backend/data.py
Normal file
56
backend/data.py
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
import os
|
||||||
|
import aiohttp
|
||||||
|
import asyncio
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
|
# Base URL template
|
||||||
|
BASE_URL = "https://bhuvan-app3.nrsc.gov.in/isroeodatadownloadutility/tiledownloadnew_cfr_new.php?f=nices_ssm2_{}_{}.zip&se=NICES&u=arnabafk"
|
||||||
|
|
||||||
|
# Directory to save files
|
||||||
|
SAVE_DIR = "data"
|
||||||
|
os.makedirs(SAVE_DIR, exist_ok=True)
|
||||||
|
|
||||||
|
async def download_file(session, file_url, file_path):
|
||||||
|
"""Download a file asynchronously."""
|
||||||
|
print(f"Downloading {file_url}...")
|
||||||
|
try:
|
||||||
|
async with session.get(file_url) as response:
|
||||||
|
if response.status == 200:
|
||||||
|
with open(file_path, 'wb') as file:
|
||||||
|
while chunk := await response.content.read(1024):
|
||||||
|
file.write(chunk)
|
||||||
|
print(f"Downloaded: {file_path}")
|
||||||
|
else:
|
||||||
|
print(f"Failed to download: {file_path}, Status Code: {response.status}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error downloading {file_url}: {e}")
|
||||||
|
|
||||||
|
async def fetch_data_for_year(session, year):
|
||||||
|
"""Fetch and download data for a given year."""
|
||||||
|
year_dir = os.path.join(SAVE_DIR, str(year))
|
||||||
|
os.makedirs(year_dir, exist_ok=True)
|
||||||
|
|
||||||
|
start_date = datetime(year, 1, 1)
|
||||||
|
end_date = datetime(year, 12, 31)
|
||||||
|
delta = timedelta(days=2)
|
||||||
|
tasks = []
|
||||||
|
|
||||||
|
date = start_date
|
||||||
|
while date <= end_date:
|
||||||
|
date_str = date.strftime("%Y%m%d")
|
||||||
|
file_url = BASE_URL.format(date_str, "NICES")
|
||||||
|
file_name = f"nices_ssm2_{date_str}.zip"
|
||||||
|
file_path = os.path.join(year_dir, file_name)
|
||||||
|
|
||||||
|
tasks.append(download_file(session, file_url, file_path))
|
||||||
|
date += delta
|
||||||
|
|
||||||
|
await asyncio.gather(*tasks)
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
"""Main function to download data for multiple years."""
|
||||||
|
async with aiohttp.ClientSession() as session:
|
||||||
|
await asyncio.gather(*(fetch_data_for_year(session, year) for year in range(2002, 2025)))
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
asyncio.run(main())
|
||||||
BIN
backend/tmp/main.exe
Normal file
BIN
backend/tmp/main.exe
Normal file
Binary file not shown.
Reference in New Issue
Block a user