mirror of
https://github.com/Dictionarry-Hub/profilarr.git
synced 2026-01-22 10:51:02 +01:00
refactor: remove API key from clone functionality
This commit is contained in:
@@ -5,7 +5,6 @@ from .branches.manager import Branch_Manager
|
||||
from .operations.manager import GitOperations
|
||||
from .repo.unlink import unlink_repository
|
||||
from .repo.clone import clone_repository
|
||||
from .auth.authenticate import validate_git_token
|
||||
from ..settings_utils import save_settings
|
||||
import logging
|
||||
|
||||
@@ -18,6 +17,7 @@ REPO_PATH = '/app/data/db'
|
||||
branch_manager = Branch_Manager(REPO_PATH)
|
||||
git_operations = GitOperations(REPO_PATH)
|
||||
|
||||
|
||||
@bp.route('/clone', methods=['POST'])
|
||||
def handle_clone_repository():
|
||||
try:
|
||||
@@ -25,25 +25,21 @@ def handle_clone_repository():
|
||||
logger.info(f"Received new settings: {new_settings}")
|
||||
|
||||
# Validate required fields
|
||||
required_fields = ['gitRepo', 'gitToken']
|
||||
for field in required_fields:
|
||||
if field not in new_settings:
|
||||
logger.error(f"Missing required field: {field}")
|
||||
return jsonify({"error": f"Missing required field: {field}"}), 400
|
||||
|
||||
# Validate Git token
|
||||
if not validate_git_token(new_settings['gitRepo'], new_settings['gitToken']):
|
||||
logger.warning("Invalid Git token provided")
|
||||
return jsonify({"error": "Invalid Git token. Please check your credentials and try again."}), 401
|
||||
if 'gitRepo' not in new_settings:
|
||||
logger.error("Missing required field: gitRepo")
|
||||
return jsonify({"error": "Missing required field: gitRepo"}), 400
|
||||
|
||||
# Attempt to clone the repository
|
||||
success, message = clone_repository(new_settings['gitRepo'], REPO_PATH, new_settings['gitToken'])
|
||||
success, message = clone_repository(new_settings['gitRepo'], REPO_PATH)
|
||||
|
||||
if success:
|
||||
# Only save the settings if the clone was successful
|
||||
save_settings(new_settings)
|
||||
# Only save the repository URL if the clone was successful
|
||||
save_settings({'gitRepo': new_settings['gitRepo']})
|
||||
logger.info("Settings updated and repository cloned successfully")
|
||||
return jsonify({"message": "Repository cloned and settings updated successfully"}), 200
|
||||
return jsonify({
|
||||
"message":
|
||||
"Repository cloned and settings updated successfully"
|
||||
}), 200
|
||||
else:
|
||||
logger.error(f"Failed to clone repository: {message}")
|
||||
return jsonify({"error": message}), 400
|
||||
@@ -64,11 +60,13 @@ def get_status():
|
||||
logger.error(f"Failed to retrieve git status: {message}")
|
||||
return jsonify({'success': False, 'error': message}), 400
|
||||
|
||||
|
||||
@bp.route('/branch', methods=['POST'])
|
||||
def create_branch():
|
||||
branch_name = request.json.get('name')
|
||||
base_branch = request.json.get('base', 'main')
|
||||
logger.debug(f"Received request to create branch {branch_name} from {base_branch}")
|
||||
logger.debug(
|
||||
f"Received request to create branch {branch_name} from {base_branch}")
|
||||
success, result = branch_manager.create(branch_name, base_branch)
|
||||
if success:
|
||||
logger.debug(f"Successfully created branch: {branch_name}")
|
||||
@@ -77,6 +75,7 @@ def create_branch():
|
||||
logger.error(f"Failed to create branch: {result}")
|
||||
return jsonify({'success': False, 'error': result}), 400
|
||||
|
||||
|
||||
@bp.route('/branches', methods=['GET'])
|
||||
def get_branches():
|
||||
logger.debug("Received request for branches")
|
||||
@@ -88,6 +87,7 @@ def get_branches():
|
||||
logger.error(f"Failed to retrieve branches: {result}")
|
||||
return jsonify({'success': False, 'error': result}), 400
|
||||
|
||||
|
||||
@bp.route('/checkout', methods=['POST'])
|
||||
def checkout_branch():
|
||||
branch_name = request.json.get('branch')
|
||||
@@ -100,6 +100,7 @@ def checkout_branch():
|
||||
logger.error(f"Failed to checkout branch: {result}")
|
||||
return jsonify({'success': False, 'error': result}), 400
|
||||
|
||||
|
||||
@bp.route('/branch/<branch_name>', methods=['DELETE'])
|
||||
def delete_branch(branch_name):
|
||||
logger.debug(f"Received request to delete branch: {branch_name}")
|
||||
@@ -110,25 +111,31 @@ def delete_branch(branch_name):
|
||||
else:
|
||||
logger.error(f"Failed to delete branch: {result}")
|
||||
return jsonify({'success': False, 'error': result}), 400
|
||||
|
||||
|
||||
|
||||
@bp.route('/branch/push', methods=['POST'])
|
||||
def push_branch():
|
||||
data = request.json
|
||||
logger.debug(f"Received request to push branch: {data}")
|
||||
branch_name = data.get('branch')
|
||||
if not branch_name:
|
||||
return jsonify({"success": False, "error": "Branch name is required"}), 400
|
||||
|
||||
return jsonify({
|
||||
"success": False,
|
||||
"error": "Branch name is required"
|
||||
}), 400
|
||||
|
||||
success, result = branch_manager.push(branch_name)
|
||||
if success:
|
||||
return jsonify({"success": True, "data": result}), 200
|
||||
else:
|
||||
return jsonify({"success": False, "error": result["error"]}), 500
|
||||
|
||||
|
||||
@bp.route('/push', methods=['POST'])
|
||||
def push_files():
|
||||
files = request.json.get('files', [])
|
||||
user_commit_message = request.json.get('commit_message', "Commit and push staged files")
|
||||
user_commit_message = request.json.get('commit_message',
|
||||
"Commit and push staged files")
|
||||
logger.debug(f"Received request to push files: {files}")
|
||||
commit_message = generate_commit_message(user_commit_message, files)
|
||||
success, message = git_operations.push(files, commit_message)
|
||||
@@ -139,11 +146,15 @@ def push_files():
|
||||
logger.error(f"Error pushing files: {message}")
|
||||
return jsonify({'success': False, 'error': message}), 400
|
||||
|
||||
|
||||
@bp.route('/revert', methods=['POST'])
|
||||
def revert_file():
|
||||
file_path = request.json.get('file_path')
|
||||
if not file_path:
|
||||
return jsonify({'success': False, 'error': "File path is required."}), 400
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'error': "File path is required."
|
||||
}), 400
|
||||
success, message = git_operations.revert(file_path)
|
||||
if success:
|
||||
return jsonify({'success': True, 'message': message}), 200
|
||||
@@ -151,6 +162,7 @@ def revert_file():
|
||||
logger.error(f"Error reverting file: {message}")
|
||||
return jsonify({'success': False, 'error': message}), 400
|
||||
|
||||
|
||||
@bp.route('/revert-all', methods=['POST'])
|
||||
def revert_all():
|
||||
success, message = git_operations.revert_all()
|
||||
@@ -160,11 +172,15 @@ def revert_all():
|
||||
logger.error(f"Error reverting all changes: {message}")
|
||||
return jsonify({'success': False, 'error': message}), 400
|
||||
|
||||
|
||||
@bp.route('/file', methods=['DELETE'])
|
||||
def delete_file():
|
||||
file_path = request.json.get('file_path')
|
||||
if not file_path:
|
||||
return jsonify({'success': False, 'error': "File path is required."}), 400
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'error': "File path is required."
|
||||
}), 400
|
||||
success, message = git_operations.delete(file_path)
|
||||
if success:
|
||||
return jsonify({'success': True, 'message': message}), 200
|
||||
@@ -172,6 +188,7 @@ def delete_file():
|
||||
logger.error(f"Error deleting file: {message}")
|
||||
return jsonify({'success': False, 'error': message}), 400
|
||||
|
||||
|
||||
@bp.route('/pull', methods=['POST'])
|
||||
def pull_branch():
|
||||
branch_name = request.json.get('branch')
|
||||
@@ -182,6 +199,7 @@ def pull_branch():
|
||||
logger.error(f"Error pulling branch: {message}")
|
||||
return jsonify({'success': False, 'error': message}), 400
|
||||
|
||||
|
||||
@bp.route('/diff', methods=['POST'])
|
||||
def diff_file():
|
||||
file_path = request.json.get('file_path')
|
||||
@@ -190,8 +208,13 @@ def diff_file():
|
||||
logger.debug(f"Diff for file {file_path}: {diff}")
|
||||
return jsonify({'success': True, 'diff': diff if diff else ""}), 200
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting diff for file {file_path}: {str(e)}", exc_info=True)
|
||||
return jsonify({'success': False, 'error': f"Error getting diff for file: {str(e)}"}), 400
|
||||
logger.error(f"Error getting diff for file {file_path}: {str(e)}",
|
||||
exc_info=True)
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'error': f"Error getting diff for file: {str(e)}"
|
||||
}), 400
|
||||
|
||||
|
||||
@bp.route('/stage', methods=['POST'])
|
||||
def handle_stage_files():
|
||||
@@ -202,6 +225,7 @@ def handle_stage_files():
|
||||
else:
|
||||
return jsonify({'success': False, 'error': message}), 400
|
||||
|
||||
|
||||
@bp.route('/unlink', methods=['POST'])
|
||||
def unlink():
|
||||
data = request.get_json()
|
||||
@@ -212,6 +236,7 @@ def unlink():
|
||||
else:
|
||||
return jsonify({'success': False, 'error': message}), 400
|
||||
|
||||
|
||||
def generate_commit_message(user_message, files):
|
||||
file_changes = []
|
||||
for file in files:
|
||||
@@ -223,4 +248,4 @@ def generate_commit_message(user_message, files):
|
||||
file_changes.append(f"Update: {file}")
|
||||
|
||||
commit_message = f"{user_message}\n\nChanges:\n" + "\n".join(file_changes)
|
||||
return commit_message
|
||||
return commit_message
|
||||
|
||||
@@ -10,24 +10,21 @@ from ..auth.authenticate import validate_git_token
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
def clone_repository(repo_url, repo_path, git_token):
|
||||
try:
|
||||
if not validate_git_token(repo_url, git_token):
|
||||
logger.error("Invalid Git token provided")
|
||||
return False, "Invalid Git token. Please check your credentials and try again."
|
||||
|
||||
def clone_repository(repo_url, repo_path):
|
||||
try:
|
||||
temp_dir = f"{repo_path}_temp"
|
||||
backup_dir = f"{repo_path}_backup"
|
||||
|
||||
|
||||
logger.info(f"Cloning repository from {repo_url} to {temp_dir}")
|
||||
auth_repo_url = repo_url.replace('https://', f'https://{git_token}:x-oauth-basic@')
|
||||
|
||||
|
||||
try:
|
||||
repo = git.Repo.clone_from(auth_repo_url, temp_dir)
|
||||
repo = git.Repo.clone_from(repo_url, temp_dir)
|
||||
logger.info("Repository cloned successfully")
|
||||
except GitCommandError as e:
|
||||
if "remote: Repository not found" in str(e):
|
||||
logger.info("Repository not found. Creating a new empty repository.")
|
||||
logger.info(
|
||||
"Repository not found. Creating a new empty repository.")
|
||||
repo = git.Repo.init(temp_dir)
|
||||
repo.create_remote('origin', repo_url)
|
||||
else:
|
||||
@@ -37,7 +34,8 @@ def clone_repository(repo_url, repo_path, git_token):
|
||||
try:
|
||||
repo.head.reference
|
||||
except ValueError:
|
||||
logger.info("Repository is empty. Initializing with basic structure.")
|
||||
logger.info(
|
||||
"Repository is empty. Initializing with basic structure.")
|
||||
_initialize_empty_repo(repo)
|
||||
|
||||
if os.path.exists(repo_path):
|
||||
@@ -55,11 +53,16 @@ def clone_repository(repo_url, repo_path, git_token):
|
||||
logger.info(f"Creating missing folder: {folder_name}")
|
||||
os.makedirs(folder_path)
|
||||
|
||||
cloned_files = [f for f in os.listdir(folder_path) if f.endswith('.yml')]
|
||||
cloned_files = [
|
||||
f for f in os.listdir(folder_path) if f.endswith('.yml')
|
||||
]
|
||||
cloned_ids = set(int(f.split('.')[0]) for f in cloned_files)
|
||||
|
||||
if os.path.exists(backup_folder_path):
|
||||
local_files = [f for f in os.listdir(backup_folder_path) if f.endswith('.yml')]
|
||||
local_files = [
|
||||
f for f in os.listdir(backup_folder_path)
|
||||
if f.endswith('.yml')
|
||||
]
|
||||
for file_name in local_files:
|
||||
old_file_path = os.path.join(backup_folder_path, file_name)
|
||||
with open(old_file_path, 'r') as file:
|
||||
@@ -90,15 +93,21 @@ def clone_repository(repo_url, repo_path, git_token):
|
||||
shutil.move(backup_dir, repo_path)
|
||||
return False, f"Unexpected error: {str(e)}"
|
||||
|
||||
|
||||
def _initialize_empty_repo(repo):
|
||||
# Create basic folder structure
|
||||
os.makedirs(os.path.join(repo.working_tree_dir, 'regex_patterns'), exist_ok=True)
|
||||
os.makedirs(os.path.join(repo.working_tree_dir, 'custom_formats'), exist_ok=True)
|
||||
os.makedirs(os.path.join(repo.working_tree_dir, 'quality_profiles'), exist_ok=True)
|
||||
os.makedirs(os.path.join(repo.working_tree_dir, 'regex_patterns'),
|
||||
exist_ok=True)
|
||||
os.makedirs(os.path.join(repo.working_tree_dir, 'custom_formats'),
|
||||
exist_ok=True)
|
||||
os.makedirs(os.path.join(repo.working_tree_dir, 'quality_profiles'),
|
||||
exist_ok=True)
|
||||
|
||||
# Create a README file
|
||||
with open(os.path.join(repo.working_tree_dir, 'README.md'), 'w') as f:
|
||||
f.write("# Profilarr Repository\n\nThis repository contains regex patterns, custom formats and quality profiles.")
|
||||
f.write(
|
||||
"# Profilarr Repository\n\nThis repository contains regex patterns, custom formats and quality profiles."
|
||||
)
|
||||
|
||||
repo.git.add(A=True)
|
||||
repo.index.commit("Initial commit: Basic repository structure")
|
||||
@@ -108,4 +117,6 @@ def _initialize_empty_repo(repo):
|
||||
origin.push('main')
|
||||
origin.push('main:main')
|
||||
|
||||
logger.info(f"Initialized empty repository with basic structure and pushed to main")
|
||||
logger.info(
|
||||
f"Initialized empty repository with basic structure and pushed to main"
|
||||
)
|
||||
|
||||
@@ -3,306 +3,336 @@ import axios from 'axios';
|
||||
const API_BASE_URL = 'http://localhost:5000';
|
||||
|
||||
export const getRegexes = async () => {
|
||||
try {
|
||||
const response = await axios.get(`${API_BASE_URL}/regex`);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Error fetching regexes:', error);
|
||||
throw error;
|
||||
}
|
||||
try {
|
||||
const response = await axios.get(`${API_BASE_URL}/regex`);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Error fetching regexes:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export const saveRegex = async (regex) => {
|
||||
try {
|
||||
const response = await axios.post(`${API_BASE_URL}/regex`, regex);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Error saving regex:', error);
|
||||
throw error;
|
||||
}
|
||||
export const saveRegex = async regex => {
|
||||
try {
|
||||
const response = await axios.post(`${API_BASE_URL}/regex`, regex);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Error saving regex:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export const updateRegex = async (id, regex) => {
|
||||
try {
|
||||
const response = await axios.put(`${API_BASE_URL}/regex/${id}`, regex);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Error updating regex:', error);
|
||||
throw error;
|
||||
}
|
||||
try {
|
||||
const response = await axios.put(`${API_BASE_URL}/regex/${id}`, regex);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Error updating regex:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export const deleteRegex = async (id, force = false) => {
|
||||
try {
|
||||
const response = await axios.delete(`${API_BASE_URL}/regex/${id}${force ? '?force=true' : ''}`, {
|
||||
validateStatus: (status) => {
|
||||
return status >= 200 && status < 300 || status === 400 || status === 409;
|
||||
}
|
||||
});
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Error deleting regex:', error);
|
||||
throw error;
|
||||
}
|
||||
try {
|
||||
const response = await axios.delete(
|
||||
`${API_BASE_URL}/regex/${id}${force ? '?force=true' : ''}`,
|
||||
{
|
||||
validateStatus: status => {
|
||||
return (
|
||||
(status >= 200 && status < 300) || status === 400 || status === 409
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Error deleting regex:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export const getFormats = async () => {
|
||||
try {
|
||||
const response = await axios.get(`${API_BASE_URL}/format`);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Error fetching formats:', error);
|
||||
throw error;
|
||||
}
|
||||
try {
|
||||
const response = await axios.get(`${API_BASE_URL}/format`);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Error fetching formats:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export const saveFormat = async (format) => {
|
||||
try {
|
||||
const response = await axios.post(`${API_BASE_URL}/format`, format);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Error saving format:', error);
|
||||
throw error;
|
||||
}
|
||||
export const saveFormat = async format => {
|
||||
try {
|
||||
const response = await axios.post(`${API_BASE_URL}/format`, format);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Error saving format:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export const updateFormat = async (id, format) => {
|
||||
try {
|
||||
const response = await axios.put(`${API_BASE_URL}/format/${id}`, format);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Error updating format:', error);
|
||||
throw error;
|
||||
}
|
||||
try {
|
||||
const response = await axios.put(`${API_BASE_URL}/format/${id}`, format);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Error updating format:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export const deleteFormat = async (id, force = false) => {
|
||||
try {
|
||||
const response = await axios.delete(`${API_BASE_URL}/format/${id}${force ? '?force=true' : ''}`, {
|
||||
validateStatus: (status) => {
|
||||
return status >= 200 && status < 300 || status === 400 || status === 409;
|
||||
}
|
||||
});
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Error deleting format:', error);
|
||||
throw error;
|
||||
}
|
||||
try {
|
||||
const response = await axios.delete(
|
||||
`${API_BASE_URL}/format/${id}${force ? '?force=true' : ''}`,
|
||||
{
|
||||
validateStatus: status => {
|
||||
return (
|
||||
(status >= 200 && status < 300) || status === 400 || status === 409
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Error deleting format:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export const createRegex101Link = async (regexData) => {
|
||||
try {
|
||||
const response = await axios.post(`${API_BASE_URL}/regex/regex101`, regexData);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Error creating regex101 link:', error);
|
||||
throw error;
|
||||
}
|
||||
export const createRegex101Link = async regexData => {
|
||||
try {
|
||||
const response = await axios.post(
|
||||
`${API_BASE_URL}/regex/regex101`,
|
||||
regexData
|
||||
);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Error creating regex101 link:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export const getSettings = async () => {
|
||||
try {
|
||||
const response = await axios.get(`${API_BASE_URL}/settings`);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Error fetching settings:', error);
|
||||
throw error;
|
||||
}
|
||||
try {
|
||||
const response = await axios.get(`${API_BASE_URL}/settings`);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Error fetching settings:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export const getGitStatus = async () => {
|
||||
try {
|
||||
const response = await axios.get(`${API_BASE_URL}/git/status`);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Error fetching Git status:', error);
|
||||
throw error;
|
||||
}
|
||||
try {
|
||||
const response = await axios.get(`${API_BASE_URL}/git/status`);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Error fetching Git status:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export const getBranches = async () => {
|
||||
try {
|
||||
const response = await axios.get(`${API_BASE_URL}/git/branches`);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Error fetching branches:', error);
|
||||
throw error;
|
||||
}
|
||||
try {
|
||||
const response = await axios.get(`${API_BASE_URL}/git/branches`);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Error fetching branches:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export const checkoutBranch = async (branchName) => {
|
||||
try {
|
||||
const response = await axios.post(`${API_BASE_URL}/git/checkout`, { branch: branchName });
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Error checking out branch:', error);
|
||||
throw error;
|
||||
}
|
||||
export const checkoutBranch = async branchName => {
|
||||
try {
|
||||
const response = await axios.post(`${API_BASE_URL}/git/checkout`, {
|
||||
branch: branchName
|
||||
});
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Error checking out branch:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export const createBranch = async (branchName, baseBranch) => {
|
||||
try {
|
||||
const response = await axios.post(`${API_BASE_URL}/git/branch`, { name: branchName, base: baseBranch });
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Error creating branch:', error);
|
||||
throw error;
|
||||
}
|
||||
try {
|
||||
const response = await axios.post(`${API_BASE_URL}/git/branch`, {
|
||||
name: branchName,
|
||||
base: baseBranch
|
||||
});
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Error creating branch:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export const deleteBranch = async (branchName) => {
|
||||
try {
|
||||
const response = await axios.delete(`${API_BASE_URL}/git/branch/${branchName}`);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Error deleting branch:', error);
|
||||
throw error;
|
||||
}
|
||||
export const deleteBranch = async branchName => {
|
||||
try {
|
||||
const response = await axios.delete(
|
||||
`${API_BASE_URL}/git/branch/${branchName}`
|
||||
);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Error deleting branch:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export const addFiles = async (files) => {
|
||||
try {
|
||||
const response = await axios.post(`${API_BASE_URL}/git/stage`, { files });
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Error staging files:', error);
|
||||
throw error;
|
||||
}
|
||||
export const addFiles = async files => {
|
||||
try {
|
||||
const response = await axios.post(`${API_BASE_URL}/git/stage`, {files});
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Error staging files:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export const pushFiles = async (files, commitMessage) => {
|
||||
try {
|
||||
const response = await axios.post(`${API_BASE_URL}/git/push`, {
|
||||
files,
|
||||
commit_message: commitMessage
|
||||
});
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Error pushing files:', error);
|
||||
throw error;
|
||||
}
|
||||
try {
|
||||
const response = await axios.post(`${API_BASE_URL}/git/push`, {
|
||||
files,
|
||||
commit_message: commitMessage
|
||||
});
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Error pushing files:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export const revertFile = async (filePath) => {
|
||||
try {
|
||||
const response = await axios.post(`${API_BASE_URL}/git/revert`, {
|
||||
file_path: filePath
|
||||
});
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Error reverting file:', error);
|
||||
throw error;
|
||||
}
|
||||
export const revertFile = async filePath => {
|
||||
try {
|
||||
const response = await axios.post(`${API_BASE_URL}/git/revert`, {
|
||||
file_path: filePath
|
||||
});
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Error reverting file:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export const revertAll = async () => {
|
||||
try {
|
||||
const response = await axios.post(`${API_BASE_URL}/git/revert-all`);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Error reverting all changes:', error);
|
||||
throw error;
|
||||
}
|
||||
try {
|
||||
const response = await axios.post(`${API_BASE_URL}/git/revert-all`);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Error reverting all changes:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export const deleteFile = async (filePath) => {
|
||||
try {
|
||||
const response = await axios.delete(`${API_BASE_URL}/git/file`, {
|
||||
data: { file_path: filePath },
|
||||
});
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Error deleting file:', error);
|
||||
return { success: false, error: 'Error deleting file' };
|
||||
}
|
||||
export const deleteFile = async filePath => {
|
||||
try {
|
||||
const response = await axios.delete(`${API_BASE_URL}/git/file`, {
|
||||
data: {file_path: filePath}
|
||||
});
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Error deleting file:', error);
|
||||
return {success: false, error: 'Error deleting file'};
|
||||
}
|
||||
};
|
||||
|
||||
export const pullBranch = async (branchName) => {
|
||||
try {
|
||||
const response = await axios.post(`${API_BASE_URL}/git/pull`, { branch: branchName });
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Error pulling branch:', error);
|
||||
throw error;
|
||||
}
|
||||
export const pullBranch = async branchName => {
|
||||
try {
|
||||
const response = await axios.post(`${API_BASE_URL}/git/pull`, {
|
||||
branch: branchName
|
||||
});
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Error pulling branch:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export const getDiff = async (filePath) => {
|
||||
try {
|
||||
const response = await axios.post(`${API_BASE_URL}/git/diff`, { file_path: filePath });
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Error fetching diff:', error);
|
||||
throw error;
|
||||
}
|
||||
export const getDiff = async filePath => {
|
||||
try {
|
||||
const response = await axios.post(`${API_BASE_URL}/git/diff`, {
|
||||
file_path: filePath
|
||||
});
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Error fetching diff:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export const cloneRepo = async (gitRepo, gitToken) => {
|
||||
try {
|
||||
const response = await axios.post(`${API_BASE_URL}/git/clone`, { gitRepo, gitToken });
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Error cloning repository:', error);
|
||||
throw error;
|
||||
}
|
||||
export const cloneRepo = async gitRepo => {
|
||||
try {
|
||||
const response = await axios.post(`${API_BASE_URL}/git/clone`, {
|
||||
gitRepo
|
||||
});
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Error cloning repository:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export const getProfiles = async () => {
|
||||
try {
|
||||
const response = await axios.get(`${API_BASE_URL}/profile`);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Error fetching profiles:', error);
|
||||
throw error;
|
||||
}
|
||||
try {
|
||||
const response = await axios.get(`${API_BASE_URL}/profile`);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Error fetching profiles:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export const saveProfile = async (profile) => {
|
||||
try {
|
||||
const response = await axios.post(`${API_BASE_URL}/profile`, profile);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Error saving profile:', error);
|
||||
throw error;
|
||||
}
|
||||
export const saveProfile = async profile => {
|
||||
try {
|
||||
const response = await axios.post(`${API_BASE_URL}/profile`, profile);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Error saving profile:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export const updateProfile = async (id, profile) => {
|
||||
try {
|
||||
const response = await axios.put(`${API_BASE_URL}/profile/${id}`, profile);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Error updating profile:', error);
|
||||
throw error;
|
||||
}
|
||||
try {
|
||||
const response = await axios.put(`${API_BASE_URL}/profile/${id}`, profile);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Error updating profile:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export const deleteProfile = async (id) => {
|
||||
try {
|
||||
const response = await axios.delete(`${API_BASE_URL}/profile/${id}`);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Error deleting profile:', error);
|
||||
throw error;
|
||||
}
|
||||
export const deleteProfile = async id => {
|
||||
try {
|
||||
const response = await axios.delete(`${API_BASE_URL}/profile/${id}`);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Error deleting profile:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export const unlinkRepo = async (removeFiles = false) => {
|
||||
try {
|
||||
const response = await axios.post(`${API_BASE_URL}/git/unlink`, { removeFiles });
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Error unlinking repository:', error);
|
||||
throw error;
|
||||
}
|
||||
try {
|
||||
const response = await axios.post(`${API_BASE_URL}/git/unlink`, {
|
||||
removeFiles
|
||||
});
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Error unlinking repository:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export const pushBranchToRemote = async (branchName) => {
|
||||
try {
|
||||
const response = await axios.post(`${API_BASE_URL}/git/branch/push`, { branch: branchName });
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Error pushing branch to remote:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
export const pushBranchToRemote = async branchName => {
|
||||
try {
|
||||
const response = await axios.post(`${API_BASE_URL}/git/branch/push`, {
|
||||
branch: branchName
|
||||
});
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Error pushing branch to remote:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
import React, { useState } from 'react';
|
||||
import Modal from '../ui/Modal';
|
||||
import { Loader } from 'lucide-react';
|
||||
import { cloneRepo } from '../../api/api';
|
||||
import Alert from '../ui/Alert';
|
||||
|
||||
const ApiKeyModal = ({ isOpen, onClose, onSubmit }) => {
|
||||
const [gitRepo, setGitRepo] = useState('');
|
||||
const [apiKey, setApiKey] = useState('');
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const handleSubmit = async () => {
|
||||
if (!gitRepo || !apiKey) {
|
||||
Alert.error("Please fill in all fields.");
|
||||
return;
|
||||
}
|
||||
setLoading(true);
|
||||
try {
|
||||
const response = await cloneRepo(gitRepo, apiKey);
|
||||
Alert.success(response.message || "Repository cloned successfully!");
|
||||
onSubmit();
|
||||
} catch (error) {
|
||||
Alert.error("An unexpected error occurred while cloning the repository.");
|
||||
console.error("Error cloning repository:", error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal isOpen={isOpen} onClose={onClose} title="Link Git Repository">
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-300 mb-2">Git Repository URL:</label>
|
||||
<input
|
||||
type="text"
|
||||
value={gitRepo}
|
||||
onChange={(e) => setGitRepo(e.target.value)}
|
||||
className="w-full p-2 border rounded bg-gray-900 text-gray-100 border-gray-600 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
placeholder="https://github.com/your-repo.git"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-300 mb-2">GitHub Access Token:</label>
|
||||
<input
|
||||
type="password"
|
||||
value={apiKey}
|
||||
onChange={(e) => setApiKey(e.target.value)}
|
||||
className="w-full p-2 border rounded bg-gray-900 text-gray-100 border-gray-600 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
placeholder="Your GitHub Token"
|
||||
/>
|
||||
</div>
|
||||
<div className="mt-6 flex justify-end">
|
||||
<button
|
||||
className="bg-blue-600 text-white px-4 py-2 rounded hover:bg-blue-700 transition-colors flex items-center"
|
||||
disabled={loading}
|
||||
onClick={handleSubmit}
|
||||
>
|
||||
{loading ? (
|
||||
<>
|
||||
<Loader size={16} className="animate-spin mr-2" />
|
||||
Cloning...
|
||||
</>
|
||||
) : (
|
||||
'Clone Repository'
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
export default ApiKeyModal;
|
||||
71
frontend/src/components/settings/LinkRepoModal.jsx
Normal file
71
frontend/src/components/settings/LinkRepoModal.jsx
Normal file
@@ -0,0 +1,71 @@
|
||||
import React, {useState} from 'react';
|
||||
import Modal from '../ui/Modal';
|
||||
import {Loader} from 'lucide-react';
|
||||
import {cloneRepo} from '../../api/api';
|
||||
import Alert from '../ui/Alert';
|
||||
|
||||
const LinkRepoModal = ({isOpen, onClose, onSubmit}) => {
|
||||
const [gitRepo, setGitRepo] = useState('');
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const handleSubmit = async () => {
|
||||
if (!gitRepo) {
|
||||
Alert.error('Please enter a repository URL.');
|
||||
return;
|
||||
}
|
||||
setLoading(true);
|
||||
try {
|
||||
const response = await cloneRepo(gitRepo);
|
||||
Alert.success(
|
||||
response.message || 'Repository linked successfully!'
|
||||
);
|
||||
onSubmit();
|
||||
} catch (error) {
|
||||
Alert.error(
|
||||
'An unexpected error occurred while linking the repository.'
|
||||
);
|
||||
console.error('Error linking repository:', error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal isOpen={isOpen} onClose={onClose} title='Link Git Repository'>
|
||||
<div className='space-y-4'>
|
||||
<div>
|
||||
<label className='block text-sm font-medium text-gray-300 mb-2'>
|
||||
Git Repository URL:
|
||||
</label>
|
||||
<input
|
||||
type='text'
|
||||
value={gitRepo}
|
||||
onChange={e => setGitRepo(e.target.value)}
|
||||
className='w-full p-2 border rounded bg-gray-900 text-gray-100 border-gray-600 focus:outline-none focus:ring-2 focus:ring-blue-500'
|
||||
placeholder='https://github.com/your-repo.git'
|
||||
/>
|
||||
</div>
|
||||
<div className='mt-6 flex justify-end'>
|
||||
<button
|
||||
className='bg-blue-600 text-white px-4 py-2 rounded hover:bg-blue-700 transition-colors flex items-center'
|
||||
disabled={loading}
|
||||
onClick={handleSubmit}>
|
||||
{loading ? (
|
||||
<>
|
||||
<Loader
|
||||
size={16}
|
||||
className='animate-spin mr-2'
|
||||
/>
|
||||
Linking...
|
||||
</>
|
||||
) : (
|
||||
'Link Repository'
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
export default LinkRepoModal;
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user