feat: Add stale process monitor, users route, landing page, archive old scripts

- Add backend stale process monitoring API (/api/stale-processes)
- Add users management route
- Add frontend landing page and stale process monitor UI on /scraper-tools
- Move old development scripts to backend/archive/
- Update frontend build with new features

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Kelly
2025-12-05 04:07:31 -07:00
parent d2d44d2aeb
commit d91c55a344
3115 changed files with 5755 additions and 719 deletions

View File

@@ -0,0 +1,39 @@
#!/bin/bash
# WordPress Plugin Build Script
# Builds the plugin zip with the correct naming convention: cb-wpmenu-{version}.zip
set -e
# Get the version from the main plugin file
VERSION=$(grep -oP "Version:\s*\K[0-9.]+" crawlsy-menus.php)
if [ -z "$VERSION" ]; then
echo "Error: Could not extract version from crawlsy-menus.php"
exit 1
fi
# Define paths
PLUGIN_DIR="$(cd "$(dirname "$0")" && pwd)"
OUTPUT_DIR="${PLUGIN_DIR}/../backend/public/downloads"
OUTPUT_FILE="cb-wpmenu-${VERSION}.zip"
echo "Building WordPress plugin..."
echo " Version: ${VERSION}"
echo " Output: ${OUTPUT_DIR}/${OUTPUT_FILE}"
# Ensure output directory exists
mkdir -p "${OUTPUT_DIR}"
# Create the zip file (from the plugin directory)
cd "${PLUGIN_DIR}"
rm -f "${OUTPUT_DIR}/${OUTPUT_FILE}"
zip -r "${OUTPUT_DIR}/${OUTPUT_FILE}" . -x "*.git*" -x "build-plugin.sh"
echo ""
echo "Build complete!"
echo " File: ${OUTPUT_DIR}/${OUTPUT_FILE}"
echo " Size: $(ls -lh "${OUTPUT_DIR}/${OUTPUT_FILE}" | awk '{print $5}')"
echo ""
echo "IMPORTANT: Update frontend/src/pages/LandingPage.tsx with the new version:"
echo " href=\"/downloads/cb-wpmenu-${VERSION}.zip\""
echo " Download Plugin v${VERSION}"

View File

@@ -3,7 +3,7 @@
* Plugin Name: Crawlsy Menus
* Plugin URI: https://creationshop.io
* Description: Display cannabis product menus from Crawlsy with Elementor integration
* Version: 1.5.0
* Version: 1.5.1
* Author: Creationshop
* Author URI: https://creationshop.io
* License: GPL v2 or later
@@ -15,7 +15,7 @@ if (!defined('ABSPATH')) {
exit; // Exit if accessed directly
}
define('CRAWLSY_MENUS_VERSION', '1.5.0');
define('CRAWLSY_MENUS_VERSION', '1.5.1');
define('CRAWLSY_MENUS_API_URL', 'https://dispos.crawlsy.com/api/v1');
define('CRAWLSY_MENUS_PLUGIN_DIR', plugin_dir_path(__FILE__));
define('CRAWLSY_MENUS_PLUGIN_URL', plugin_dir_url(__FILE__));
@@ -144,7 +144,7 @@ class Crawlsy_Menus_Plugin {
<hr />
<h2>Test Connection</h2>
<button type="button" id="test-api-connection" class="button">Test API Connection</button>
<button type="button" id="test-api-connection" class="button button-primary">Test API Connection</button>
<div id="api-test-result" style="margin-top: 10px;"></div>
<script>
@@ -153,7 +153,14 @@ class Crawlsy_Menus_Plugin {
var apiUrl = '<?php echo CRAWLSY_MENUS_API_URL; ?>';
var apiToken = $('#crawlsy_api_token').val();
$('#api-test-result').html('<p>Testing connection...</p>');
if (!apiToken || apiToken.trim() === '') {
$('#api-test-result').html(
'<div class="notice notice-warning"><p><strong>Warning:</strong> Please enter an API token first.</p></div>'
);
return;
}
$('#api-test-result').html('<p><span class="spinner is-active" style="float:none;margin:0 5px 0 0;"></span>Testing connection to ' + apiUrl + '...</p>');
$.ajax({
url: apiUrl + '/menu',
@@ -161,17 +168,79 @@ class Crawlsy_Menus_Plugin {
headers: {
'X-API-Key': apiToken
},
timeout: 30000,
success: function(response) {
$('#api-test-result').html(
'<div class="notice notice-success"><p><strong>Success!</strong> Connected to: ' +
response.dispensary + ' (' + response.menu.total_products + ' products)</p></div>'
);
var html = '<div class="notice notice-success"><p><strong>Success!</strong> Connected to: ' +
response.dispensary + '</p>';
if (response.menu) {
html += '<ul style="margin-left: 20px;">';
html += '<li>Total Products: ' + (response.menu.total_products || 0) + '</li>';
html += '<li>In Stock: ' + (response.menu.in_stock_count || 0) + '</li>';
html += '<li>Brands: ' + (response.menu.brand_count || 0) + '</li>';
html += '<li>Categories: ' + (response.menu.category_count || 0) + '</li>';
if (response.menu.last_updated) {
html += '<li>Last Updated: ' + new Date(response.menu.last_updated).toLocaleString() + '</li>';
}
html += '</ul>';
}
html += '</div>';
$('#api-test-result').html(html);
},
error: function(xhr) {
$('#api-test-result').html(
'<div class="notice notice-error"><p><strong>Error:</strong> ' +
(xhr.responseJSON?.error || 'Connection failed') + '</p></div>'
);
error: function(xhr, textStatus, errorThrown) {
var errorHtml = '<div class="notice notice-error">';
errorHtml += '<p><strong>Connection Failed</strong></p>';
// Show HTTP status
if (xhr.status) {
errorHtml += '<p><strong>HTTP Status:</strong> ' + xhr.status + ' ' + (xhr.statusText || '') + '</p>';
}
// Show error message from API
if (xhr.responseJSON) {
if (xhr.responseJSON.error) {
errorHtml += '<p><strong>Error:</strong> ' + xhr.responseJSON.error + '</p>';
}
if (xhr.responseJSON.message) {
errorHtml += '<p><strong>Details:</strong> ' + xhr.responseJSON.message + '</p>';
}
if (xhr.responseJSON.client_ip) {
errorHtml += '<p><strong>Your IP:</strong> ' + xhr.responseJSON.client_ip + '</p>';
}
if (xhr.responseJSON.origin) {
errorHtml += '<p><strong>Origin:</strong> ' + xhr.responseJSON.origin + '</p>';
}
} else if (textStatus === 'timeout') {
errorHtml += '<p><strong>Error:</strong> Request timed out. The API server may be unavailable.</p>';
} else if (textStatus === 'error' && !xhr.status) {
errorHtml += '<p><strong>Error:</strong> Could not connect to the API. This may be a CORS issue or network problem.</p>';
errorHtml += '<p><em>Note: If testing from wp-admin, try saving the token and testing on the frontend shortcode instead.</em></p>';
} else {
errorHtml += '<p><strong>Error:</strong> ' + (errorThrown || textStatus || 'Unknown error') + '</p>';
}
// Debug info
errorHtml += '<details style="margin-top: 10px;"><summary style="cursor:pointer;"><strong>Debug Info</strong></summary>';
errorHtml += '<pre style="background:#f5f5f5;padding:10px;margin-top:5px;overflow-x:auto;font-size:11px;">';
errorHtml += 'API URL: ' + apiUrl + '/menu\n';
errorHtml += 'Token Length: ' + apiToken.length + ' chars\n';
errorHtml += 'Token Preview: ' + apiToken.substring(0, 8) + '...' + apiToken.substring(apiToken.length - 4) + '\n';
errorHtml += 'Status: ' + xhr.status + '\n';
errorHtml += 'Response: ' + (xhr.responseText ? xhr.responseText.substring(0, 500) : 'none') + '\n';
errorHtml += '</pre></details>';
// Help text based on status
if (xhr.status === 401) {
errorHtml += '<p style="margin-top:10px;"><strong>Troubleshooting:</strong> Your API token is invalid or inactive. Please check that you copied the full token from the Crawlsy admin dashboard.</p>';
} else if (xhr.status === 403) {
errorHtml += '<p style="margin-top:10px;"><strong>Troubleshooting:</strong> Access denied. Your IP address or domain may not be in the allowed list. Contact support to update your permissions.</p>';
} else if (xhr.status === 500) {
errorHtml += '<p style="margin-top:10px;"><strong>Troubleshooting:</strong> Server error. This may be a temporary issue. Try again in a few minutes, or contact support if the problem persists.</p>';
} else if (xhr.status === 503) {
errorHtml += '<p style="margin-top:10px;"><strong>Troubleshooting:</strong> Menu data is not yet available for your dispensary. The data pipeline may still be processing.</p>';
}
errorHtml += '</div>';
$('#api-test-result').html(errorHtml);
}
});
});