Compare commits

...

8 commits

Author SHA1 Message Date
Christian Wedel
198324cf01
Merge pull request #4 from soulsites/claude/fix-project-saving-011CURum5vF5z5C7hXEiBEBw
Fix project saving functionality
2025-10-24 13:26:11 +02:00
Claude
24943e6d9a
Fix project saving functionality
- Fix is_private boolean conversion bug (jQuery sends '1'/'0', not 'true'/'false')
- Improve save button visibility logic (hide when no version selected)
- Add default "Select a version" option to version dropdown
- Hide save button when version loading fails or repo URL is empty

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-24 11:06:08 +00:00
Christian Wedel
49a11bad1b
Merge pull request #3 from soulsites/claude/fix-plugin-update-error-011CURu4WcQrkayzV7FrvGSr
Fix empty pathspec error in plugin update
2025-10-24 12:58:57 +02:00
Claude
fec905eb50
Fix empty pathspec error in plugin update
The plugin update was failing when version parameter was empty, causing git to try to checkout an empty string which resulted in "fatal: empty string is not a valid pathspec" error.

Changes:
- Added validation to check if version is not empty before attempting checkout
- If version is empty, fall back to git pull on default branch instead
- Applied fix to both install_update_github_plugin and sync_github_project functions
- Improved error handling to reset remote URL even when git operations fail

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-24 10:54:30 +00:00
Christian Wedel
3c50ea7fc4
Merge pull request #2 from soulsites/claude/fix-plugin-fetch-error-011CURsTR3T3fVFpGjm8m466
Fix git fetch error for private repositories
2025-10-24 12:51:00 +02:00
Claude
440a124833
Fix git fetch error for private repositories
This fix addresses the "Failed to update the plugin. Error: Fetching origin" error that occurred when updating plugins from private GitHub repositories.

Changes:
- Updated install_update_github_plugin() to temporarily set remote URL with access token before fetch
- Updated sync_github_project() to handle private repos with access token
- Added security measure to reset remote URL back to original (without token) after operations
- Added 2>&1 to capture stderr output for better error messages

The access token is now properly used during git fetch operations and removed afterwards for security.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-24 10:33:55 +00:00
Christian Wedel
57acf60bfa
Merge pull request #1 from soulsites/claude/add-multi-project-support-011CURrPCsFPgrgr5addnnir
Add multi-project support with card-based UI and synchronization
2025-10-24 12:26:09 +02:00
Claude
fd8f65bd43
Add multi-project support with card-based UI and synchronization
This major update (v2.0) adds comprehensive multi-project management capabilities:

Features:
- Save multiple GitHub projects with persistent storage in WordPress database
- Visual card-based interface displaying all saved projects
- One-click synchronization for each project to pull latest Git version
- Project management: save, delete, and sync operations
- Track last synchronization timestamp for each project
- Support for both public and private repositories with token storage

Technical changes:
- Added WordPress options API integration for project persistence
- New AJAX handlers: save_github_project, delete_github_project, sync_github_project
- Helper functions: get_saved_projects(), save_project(), delete_project()
- Enhanced UI with responsive grid layout and hover effects
- Real-time status indicators for sync operations
- Updated JavaScript with event handlers for all new features
- Comprehensive error handling and user feedback

Security:
- Proper nonce verification for all AJAX calls
- Capability checks for all operations
- Input sanitization for all user data
- Secure token storage with WordPress options API

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-24 10:22:59 +00:00
3 changed files with 550 additions and 47 deletions

View file

@ -14,12 +14,16 @@ This plugin is designed for:

## Features

- **Multi-Project Support**: Save and manage multiple GitHub projects in one place
- **Project Cards**: Visual card-based interface showing all your saved projects
- **One-Click Sync**: Synchronize any saved project to pull the latest version from Git
- Install plugins directly from public or private GitHub repositories
- Update existing plugins installed from GitHub
- Preview repository contents before installation
- Select specific versions (tags) of a plugin to install
- Support for private repositories using GitHub Personal Access Tokens
- Automatic plugin folder naming based on the repository name
- Track last synchronization time for each project

## Installation

@ -29,12 +33,33 @@ This plugin is designed for:

## Usage

### Installing a New Plugin

1. In the WordPress admin panel, go to Plugins > GitHub Installer.
2. Enter the GitHub repository URL of the plugin you want to install.
3. If it's a private repository, check the "Private Repository?" box and enter your GitHub Personal Access Token.
4. The plugin will fetch available versions and provide a preview of the repository contents.
5. Select the version you want to install from the dropdown menu.
6. Click "Install/Update Plugin" to proceed with the installation or update.
2. Enter a project name (optional) to save the project for later use.
3. Enter the GitHub repository URL of the plugin you want to install.
4. If it's a private repository, check the "Private Repository?" box and enter your GitHub Personal Access Token.
5. The plugin will fetch available versions and provide a preview of the repository contents.
6. Select the version you want to install from the dropdown menu.
7. Click "Install/Update Plugin" to proceed with the installation or update.
8. Optionally, click "Als Projekt speichern" (Save as Project) to save this configuration for future use.

### Managing Saved Projects

Once you've saved projects, they will appear as cards below the installation form:

- **View Project Details**: Each card shows the project name, repository URL, version, privacy status, and last sync time.
- **Synchronize**: Click the "Synchronisieren" button to pull the latest version from Git for that specific project.
- **Delete**: Click the "Löschen" button to remove a saved project from your list (this won't uninstall the plugin, just removes it from the saved projects).

### Synchronizing Projects

The synchronization feature allows you to quickly update any saved project:

1. Find the project card you want to sync.
2. Click the "Synchronisieren" (Synchronize) button.
3. The plugin will automatically fetch the latest version from Git and update the plugin.
4. You'll see a status message indicating success or failure.

## Requirements

@ -57,8 +82,10 @@ No additional configuration is required after installation. However, for private
## Security Considerations

- The plugin uses nonces and capability checks to ensure only authorized users can install plugins.
- Personal Access Tokens are not stored by the plugin and must be entered each time for private repositories.
- **Personal Access Tokens are stored in the WordPress database** when you save a project. Ensure your WordPress installation is secure.
- Only users with the `manage_options` capability (typically administrators) can access the plugin.
- Always review the contents of a repository before installing to ensure it's from a trusted source.
- Saved projects and their tokens are stored using WordPress options API with proper sanitization.

## Limitations


View file

@ -1,8 +1,8 @@
<?php
/**
* Plugin Name: GitHub Plugin Installer
* Description: Install or update WordPress plugins directly from GitHub repositories
* Version: 1.4
* Description: Install or update WordPress plugins directly from GitHub repositories with multi-project support
* Version: 2.0
* Author: Christian Wedel
*/

@ -12,6 +12,9 @@ add_action('admin_enqueue_scripts', 'github_plugin_installer_scripts');
add_action('wp_ajax_preview_github_repo', 'preview_github_repo');
add_action('wp_ajax_get_github_versions', 'get_github_versions');
add_action('wp_ajax_check_plugin_status', 'check_plugin_status');
add_action('wp_ajax_save_github_project', 'save_github_project');
add_action('wp_ajax_delete_github_project', 'delete_github_project');
add_action('wp_ajax_sync_github_project', 'sync_github_project');

function github_plugin_installer_menu() {
add_plugins_page('GitHub Plugin Installer', 'GitHub Installer', 'manage_options', 'github-plugin-installer', 'github_plugin_installer_page');
@ -28,6 +31,38 @@ function github_plugin_installer_scripts($hook) {
));
}

// Helper functions for project management
function get_saved_projects() {
$projects = get_option('github_installer_projects', array());
return is_array($projects) ? $projects : array();
}

function save_project($project_data) {
$projects = get_saved_projects();
$project_id = sanitize_title($project_data['name']);
$projects[$project_id] = array(
'id' => $project_id,
'name' => sanitize_text_field($project_data['name']),
'repo_url' => esc_url_raw($project_data['repo_url']),
'is_private' => (bool) $project_data['is_private'],
'access_token' => !empty($project_data['access_token']) ? sanitize_text_field($project_data['access_token']) : '',
'version' => sanitize_text_field($project_data['version']),
'last_synced' => current_time('mysql')
);
update_option('github_installer_projects', $projects);
return $project_id;
}

function delete_project($project_id) {
$projects = get_saved_projects();
if (isset($projects[$project_id])) {
unset($projects[$project_id]);
update_option('github_installer_projects', $projects);
return true;
}
return false;
}

function github_plugin_installer_page() {
if (!current_user_can('manage_options')) {
return;
@ -38,46 +73,201 @@ function github_plugin_installer_page() {
$is_private = isset($_POST['is_private']) ? true : false;
$access_token = $is_private ? sanitize_text_field($_POST['access_token']) : '';
$selected_version = sanitize_text_field($_POST['version']);

install_update_github_plugin($repo_url, $access_token, $selected_version);
}

$saved_projects = get_saved_projects();

?>
<style>
.github-projects-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 20px;
margin: 20px 0;
}
.github-project-card {
background: #fff;
border: 1px solid #c3c4c7;
border-radius: 4px;
padding: 20px;
box-shadow: 0 1px 1px rgba(0,0,0,.04);
transition: box-shadow 0.2s ease;
}
.github-project-card:hover {
box-shadow: 0 2px 6px rgba(0,0,0,.1);
}
.github-project-card h3 {
margin-top: 0;
margin-bottom: 10px;
font-size: 16px;
color: #1d2327;
}
.github-project-info {
font-size: 13px;
color: #50575e;
margin-bottom: 15px;
}
.github-project-info p {
margin: 5px 0;
word-break: break-all;
}
.github-project-actions {
display: flex;
gap: 10px;
flex-wrap: wrap;
}
.github-sync-btn {
background: #2271b1;
border-color: #2271b1;
color: #fff;
padding: 6px 12px;
border-radius: 3px;
cursor: pointer;
border: 1px solid;
font-size: 13px;
transition: background 0.2s ease;
}
.github-sync-btn:hover {
background: #135e96;
border-color: #135e96;
}
.github-sync-btn:disabled {
background: #c3c4c7;
border-color: #c3c4c7;
cursor: not-allowed;
}
.github-delete-btn {
background: #fff;
border-color: #c3c4c7;
color: #b32d2e;
padding: 6px 12px;
border-radius: 3px;
cursor: pointer;
border: 1px solid;
font-size: 13px;
transition: all 0.2s ease;
}
.github-delete-btn:hover {
background: #b32d2e;
border-color: #b32d2e;
color: #fff;
}
.github-sync-status {
font-size: 12px;
margin-top: 10px;
padding: 8px;
border-radius: 3px;
display: none;
}
.github-sync-status.success {
background: #d7f0db;
color: #00631e;
border: 1px solid #00631e;
}
.github-sync-status.error {
background: #fcf0f1;
color: #b32d2e;
border: 1px solid #b32d2e;
}
.github-sync-status.loading {
background: #f0f6fc;
color: #1d2327;
border: 1px solid #2271b1;
}
.github-add-project-section {
background: #fff;
border: 1px solid #c3c4c7;
border-radius: 4px;
padding: 20px;
margin-bottom: 30px;
}
.github-save-project-btn {
background: #00a32a;
border-color: #00a32a;
color: #fff;
margin-left: 10px;
}
.github-save-project-btn:hover {
background: #008a20;
border-color: #008a20;
}
</style>
<div class="wrap">
<h1><?php echo esc_html(get_admin_page_title()); ?></h1>
<form method="post" action="">
<table class="form-table">
<tr>
<th scope="row"><label for="repo_url">GitHub Repository URL</label></th>
<td><input type="text" id="repo_url" name="repo_url" class="regular-text" required placeholder="https://github.com/username/repo.git"></td>
</tr>
<tr>
<th scope="row"><label for="is_private">Private Repository?</label></th>
<td><input type="checkbox" id="is_private" name="is_private"></td>
</tr>
<tr id="access_token_row" style="display: none;">
<th scope="row"><label for="access_token">GitHub Access Token</label></th>
<td>
<input type="password" id="access_token" name="access_token" class="regular-text">
<p class="description">
To generate a Personal Access Token, go to
<a href="https://github.com/settings/tokens" target="_blank">GitHub Settings > Developer settings > Personal access tokens</a>.
Create a new token with the 'repo' scope for private repositories.
</p>
</td>
</tr>
<tr id="version_row" style="display: none;">
<th scope="row"><label for="version">Version</label></th>
<td><select id="version" name="version"></select></td>
</tr>
</table>
<div id="plugin_status"></div>
<?php submit_button('Install/Update Plugin', 'primary', 'install_update_plugin'); ?>
</form>
<div id="repo_preview" style="margin-top: 20px; padding: 10px; border: 1px solid #ccc; display: none;">
<h2>Repository Preview</h2>
<div id="repo_content"></div>

<div class="github-add-project-section">
<h2>Neues Projekt hinzufügen</h2>
<form method="post" action="" id="github-project-form">
<table class="form-table">
<tr>
<th scope="row"><label for="project_name">Projektname</label></th>
<td><input type="text" id="project_name" name="project_name" class="regular-text" placeholder="Mein GitHub Plugin"></td>
</tr>
<tr>
<th scope="row"><label for="repo_url">GitHub Repository URL</label></th>
<td><input type="text" id="repo_url" name="repo_url" class="regular-text" required placeholder="https://github.com/username/repo.git"></td>
</tr>
<tr>
<th scope="row"><label for="is_private">Privates Repository?</label></th>
<td><input type="checkbox" id="is_private" name="is_private"></td>
</tr>
<tr id="access_token_row" style="display: none;">
<th scope="row"><label for="access_token">GitHub Access Token</label></th>
<td>
<input type="password" id="access_token" name="access_token" class="regular-text">
<p class="description">
To generate a Personal Access Token, go to
<a href="https://github.com/settings/tokens" target="_blank">GitHub Settings > Developer settings > Personal access tokens</a>.
Create a new token with the 'repo' scope for private repositories.
</p>
</td>
</tr>
<tr id="version_row" style="display: none;">
<th scope="row"><label for="version">Version</label></th>
<td><select id="version" name="version"></select></td>
</tr>
</table>
<div id="plugin_status"></div>
<?php submit_button('Installieren/Aktualisieren', 'primary', 'install_update_plugin', false); ?>
<button type="button" id="save_project_btn" class="button github-save-project-btn" style="display:none;">Als Projekt speichern</button>
</form>
<div id="repo_preview" style="margin-top: 20px; padding: 10px; border: 1px solid #ccc; display: none;">
<h3>Repository Preview</h3>
<div id="repo_content"></div>
</div>
</div>

<?php if (!empty($saved_projects)): ?>
<h2>Gespeicherte Projekte</h2>
<div class="github-projects-grid">
<?php foreach ($saved_projects as $project): ?>
<div class="github-project-card" data-project-id="<?php echo esc_attr($project['id']); ?>">
<h3><?php echo esc_html($project['name']); ?></h3>
<div class="github-project-info">
<p><strong>Repository:</strong> <?php echo esc_html($project['repo_url']); ?></p>
<p><strong>Version:</strong> <?php echo esc_html($project['version']); ?></p>
<p><strong>Status:</strong> <?php echo $project['is_private'] ? 'Privat' : 'Öffentlich'; ?></p>
<p><strong>Zuletzt synchronisiert:</strong> <?php echo esc_html($project['last_synced']); ?></p>
</div>
<div class="github-project-actions">
<button class="github-sync-btn" data-project-id="<?php echo esc_attr($project['id']); ?>">
Synchronisieren
</button>
<button class="github-delete-btn" data-project-id="<?php echo esc_attr($project['id']); ?>">
Löschen
</button>
</div>
<div class="github-sync-status" data-project-id="<?php echo esc_attr($project['id']); ?>"></div>
</div>
<?php endforeach; ?>
</div>
<?php else: ?>
<div class="notice notice-info">
<p>Keine gespeicherten Projekte vorhanden. Fügen Sie oben ein neues Projekt hinzu.</p>
</div>
<?php endif; ?>
</div>
<?php
}
@ -95,19 +285,55 @@ function install_update_github_plugin($repo_url, $access_token, $selected_versio

if ($is_update) {
// Update existing plugin
$update_command = "cd " . escapeshellarg($plugin_dir) . " && git fetch --all && git checkout " . escapeshellarg($selected_version);
exec($update_command, $output, $return_var);
// Update remote URL with access token if provided
if (!empty($access_token)) {
$auth_repo_url = str_replace('https://', "https://{$access_token}@", $repo_url);
$set_url_command = "cd " . escapeshellarg($plugin_dir) . " && git remote set-url origin " . escapeshellarg($auth_repo_url) . " 2>&1";
exec($set_url_command, $url_output, $url_return);
}

if ($return_var !== 0) {
wp_die('Failed to update the plugin. Error: ' . implode("\n", $output));
// Validate version before checkout
if (!empty($selected_version)) {
$update_command = "cd " . escapeshellarg($plugin_dir) . " && git fetch --all && git checkout " . escapeshellarg($selected_version) . " 2>&1";
exec($update_command, $output, $return_var);

if ($return_var !== 0) {
// Reset remote URL to original (without token) for security
if (!empty($access_token)) {
$reset_url_command = "cd " . escapeshellarg($plugin_dir) . " && git remote set-url origin " . escapeshellarg($repo_url) . " 2>&1";
exec($reset_url_command, $reset_output, $reset_return);
}
wp_die('Failed to update the plugin. Error: ' . implode("\n", $output));
}
} else {
// If no version specified, just fetch and pull the default branch
$update_command = "cd " . escapeshellarg($plugin_dir) . " && git fetch --all && git pull 2>&1";
exec($update_command, $output, $return_var);

if ($return_var !== 0) {
// Reset remote URL to original (without token) for security
if (!empty($access_token)) {
$reset_url_command = "cd " . escapeshellarg($plugin_dir) . " && git remote set-url origin " . escapeshellarg($repo_url) . " 2>&1";
exec($reset_url_command, $reset_output, $reset_return);
}
wp_die('Failed to update the plugin. Error: ' . implode("\n", $output));
}
}

// Reset remote URL to original (without token) for security
if (!empty($access_token)) {
$reset_url_command = "cd " . escapeshellarg($plugin_dir) . " && git remote set-url origin " . escapeshellarg($repo_url) . " 2>&1";
exec($reset_url_command, $reset_output, $reset_return);
}
} else {
// Install new plugin
$clone_command = "git clone ";
if (!empty($access_token)) {
$repo_url = str_replace('https://', "https://{$access_token}@", $repo_url);
$repo_url_with_token = str_replace('https://', "https://{$access_token}@", $repo_url);
$clone_command .= escapeshellarg($repo_url_with_token) . " " . escapeshellarg($plugin_dir);
} else {
$clone_command .= escapeshellarg($repo_url) . " " . escapeshellarg($plugin_dir);
}
$clone_command .= escapeshellarg($repo_url) . " " . escapeshellarg($plugin_dir);

exec($clone_command, $output, $return_var);

@ -115,6 +341,12 @@ function install_update_github_plugin($repo_url, $access_token, $selected_versio
wp_die('Failed to clone the repository. Error: ' . implode("\n", $output));
}

// Reset remote URL to original (without token) for security
if (!empty($access_token)) {
$reset_url_command = "cd " . escapeshellarg($plugin_dir) . " && git remote set-url origin " . escapeshellarg($repo_url) . " 2>&1";
exec($reset_url_command, $reset_output, $reset_return);
}

// Checkout the selected version
if (!empty($selected_version)) {
$checkout_command = "cd " . escapeshellarg($plugin_dir) . " && git checkout " . escapeshellarg($selected_version);
@ -274,4 +506,124 @@ function check_plugin_status() {
} else {
wp_send_json_success(array('status' => 'not_installed'));
}
}

function save_github_project() {
check_ajax_referer('github_installer_nonce', 'nonce');

if (!current_user_can('manage_options')) {
wp_send_json_error('Insufficient permissions.');
}

$project_data = array(
'name' => sanitize_text_field($_POST['name']),
'repo_url' => esc_url_raw($_POST['repo_url']),
'is_private' => !empty($_POST['is_private']) && $_POST['is_private'] !== 'false' && $_POST['is_private'] !== '0',
'access_token' => isset($_POST['access_token']) ? sanitize_text_field($_POST['access_token']) : '',
'version' => sanitize_text_field($_POST['version'])
);

if (empty($project_data['name']) || empty($project_data['repo_url'])) {
wp_send_json_error('Name und Repository URL sind erforderlich.');
}

$project_id = save_project($project_data);
wp_send_json_success(array('message' => 'Projekt erfolgreich gespeichert!', 'project_id' => $project_id));
}

function delete_github_project() {
check_ajax_referer('github_installer_nonce', 'nonce');

if (!current_user_can('manage_options')) {
wp_send_json_error('Insufficient permissions.');
}

$project_id = sanitize_text_field($_POST['project_id']);

if (delete_project($project_id)) {
wp_send_json_success('Projekt erfolgreich gelöscht!');
} else {
wp_send_json_error('Projekt konnte nicht gelöscht werden.');
}
}

function sync_github_project() {
check_ajax_referer('github_installer_nonce', 'nonce');

if (!current_user_can('manage_options')) {
wp_send_json_error('Insufficient permissions.');
}

$project_id = sanitize_text_field($_POST['project_id']);
$projects = get_saved_projects();

if (!isset($projects[$project_id])) {
wp_send_json_error('Projekt nicht gefunden.');
}

$project = $projects[$project_id];

// Perform the sync
try {
$repo_url = $project['repo_url'];
$access_token = $project['access_token'];
$version = $project['version'];

$repo_name = strtolower(basename(parse_url($repo_url, PHP_URL_PATH), '.git'));
$plugin_dir = WP_PLUGIN_DIR . '/' . $repo_name;

if (!file_exists($plugin_dir)) {
wp_send_json_error('Plugin ist nicht installiert. Bitte installieren Sie es zuerst über das Formular oben.');
}

// Update remote URL with access token if private repository
if ($project['is_private'] && !empty($access_token)) {
$auth_repo_url = str_replace('https://', "https://{$access_token}@", $repo_url);
$set_url_command = "cd " . escapeshellarg($plugin_dir) . " && git remote set-url origin " . escapeshellarg($auth_repo_url) . " 2>&1";
exec($set_url_command, $url_output, $url_return);
}

// Update existing plugin - validate version before checkout
if (!empty($version)) {
$update_command = "cd " . escapeshellarg($plugin_dir) . " && git fetch --all && git checkout " . escapeshellarg($version) . " 2>&1";
exec($update_command, $output, $return_var);

if ($return_var !== 0) {
// Reset remote URL to original (without token) for security
if ($project['is_private'] && !empty($access_token)) {
$reset_url_command = "cd " . escapeshellarg($plugin_dir) . " && git remote set-url origin " . escapeshellarg($repo_url) . " 2>&1";
exec($reset_url_command, $reset_output, $reset_return);
}
wp_send_json_error('Synchronisierung fehlgeschlagen: ' . implode("\n", $output));
}
} else {
// If no version specified, just fetch and pull the default branch
$update_command = "cd " . escapeshellarg($plugin_dir) . " && git fetch --all && git pull 2>&1";
exec($update_command, $output, $return_var);

if ($return_var !== 0) {
// Reset remote URL to original (without token) for security
if ($project['is_private'] && !empty($access_token)) {
$reset_url_command = "cd " . escapeshellarg($plugin_dir) . " && git remote set-url origin " . escapeshellarg($repo_url) . " 2>&1";
exec($reset_url_command, $reset_output, $reset_return);
}
wp_send_json_error('Synchronisierung fehlgeschlagen: ' . implode("\n", $output));
}
}

// Reset remote URL to original (without token) for security
if ($project['is_private'] && !empty($access_token)) {
$reset_url_command = "cd " . escapeshellarg($plugin_dir) . " && git remote set-url origin " . escapeshellarg($repo_url) . " 2>&1";
exec($reset_url_command, $reset_output, $reset_return);
}

// Update last_synced timestamp
$project['last_synced'] = current_time('mysql');
$projects[$project_id] = $project;
update_option('github_installer_projects', $projects);

wp_send_json_success('Projekt erfolgreich synchronisiert!');
} catch (Exception $e) {
wp_send_json_error('Fehler bei der Synchronisierung: ' . $e->getMessage());
}
}

View file

@ -17,6 +17,15 @@ jQuery(document).ready(function() {
previewTimer = setTimeout(updatePreviewAndVersions, 500);
});

// Show "Save as Project" button when version is selected
jQuery('#version').on('change', function() {
if(jQuery(this).val()) {
jQuery('#save_project_btn').show();
} else {
jQuery('#save_project_btn').hide();
}
});

function updatePreviewAndVersions() {
previewRepo();
getVersions();
@ -78,22 +87,137 @@ jQuery(document).ready(function() {
var versions = response.data;
var versionSelect = jQuery('#version');
versionSelect.empty();
versionSelect.append(jQuery('<option></option>').attr('value', '').text('-- Wählen Sie eine Version --'));
jQuery.each(versions, function(index, version) {
versionSelect.append(jQuery('<option></option>').attr('value', version).text(version));
});
jQuery('#version_row').show();
} else {
jQuery('#version_row').hide();
jQuery('#save_project_btn').hide();
console.error('Failed to fetch versions:', response.data);
}
},
error: function() {
jQuery('#version_row').hide();
jQuery('#save_project_btn').hide();
console.error('An error occurred while fetching the repository versions.');
}
});
} else {
jQuery('#version_row').hide();
jQuery('#save_project_btn').hide();
}
}

// Save project button handler
jQuery('#save_project_btn').on('click', function(e) {
e.preventDefault();

var projectName = jQuery('#project_name').val();
var repoUrl = jQuery('#repo_url').val();
var isPrivate = jQuery('#is_private').is(':checked');
var accessToken = jQuery('#access_token').val();
var version = jQuery('#version').val();

if (!projectName) {
alert('Bitte geben Sie einen Projektnamen ein.');
return;
}

if (!repoUrl || !version) {
alert('Bitte füllen Sie alle erforderlichen Felder aus.');
return;
}

jQuery.ajax({
url: github_installer.ajax_url,
type: 'POST',
data: {
action: 'save_github_project',
nonce: github_installer.nonce,
name: projectName,
repo_url: repoUrl,
is_private: isPrivate,
access_token: accessToken,
version: version
},
success: function(response) {
if (response.success) {
alert(response.data.message);
location.reload();
} else {
alert('Fehler: ' + response.data);
}
},
error: function() {
alert('Ein Fehler ist beim Speichern des Projekts aufgetreten.');
}
});
});

// Sync project button handler
jQuery(document).on('click', '.github-sync-btn', function() {
var projectId = jQuery(this).data('project-id');
var button = jQuery(this);
var statusDiv = jQuery('.github-sync-status[data-project-id="' + projectId + '"]');

button.prop('disabled', true);
statusDiv.removeClass('success error').addClass('loading').text('Synchronisierung läuft...').show();

jQuery.ajax({
url: github_installer.ajax_url,
type: 'POST',
data: {
action: 'sync_github_project',
nonce: github_installer.nonce,
project_id: projectId
},
success: function(response) {
button.prop('disabled', false);
if (response.success) {
statusDiv.removeClass('loading error').addClass('success').text(response.data);
setTimeout(function() {
location.reload();
}, 1500);
} else {
statusDiv.removeClass('loading success').addClass('error').text('Fehler: ' + response.data);
}
},
error: function() {
button.prop('disabled', false);
statusDiv.removeClass('loading success').addClass('error').text('Ein Fehler ist aufgetreten.');
}
});
});

// Delete project button handler
jQuery(document).on('click', '.github-delete-btn', function() {
var projectId = jQuery(this).data('project-id');

if (!confirm('Möchten Sie dieses Projekt wirklich löschen?')) {
return;
}

jQuery.ajax({
url: github_installer.ajax_url,
type: 'POST',
data: {
action: 'delete_github_project',
nonce: github_installer.nonce,
project_id: projectId
},
success: function(response) {
if (response.success) {
alert(response.data);
location.reload();
} else {
alert('Fehler: ' + response.data);
}
},
error: function() {
alert('Ein Fehler ist beim Löschen des Projekts aufgetreten.');
}
});
});
});