ferrero-opentext/workflow_v3.php
DJP a179be5da8 Add Workflow V3 with status-based campaign management
New Features:
- ConfigV3 class with test/production environment switching
- StatusManager for campaign status updates (A1→A2→A3, A5→A6)
- workflow_v3.php with tabbed interface for different workflows
- Auto-refreshing OAuth2 token (60-second buffer before expiry)
- Download workflow: Load A1 campaigns → Download master assets → Update to A2
- Metadata display for all assets
- Configurable base URLs for certificate auth and IP filtering

Status Workflow:
- A1: Ready for localization → Download assets → A2
- A2: Assets sent to agency → Upload processed → A3 (coming soon)
- A5: Rework needed → Download rework assets → A6 (coming soon)

Technical:
- Uses Content Scaling Flow V3.postman_collection.json
- Supports multiple environments (test/production)
- Session-based workflow state management
- Master Assets folder always "01. Master Assets"

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-17 15:00:21 -04:00

834 lines
30 KiB
PHP
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
session_start();
// Clear session on reset
if (isset($_GET['reset'])) {
session_destroy();
session_start();
header('Location: workflow_v3.php');
exit;
}
require_once 'config_v3.php';
require_once 'src/TestRunner.php';
require_once 'src/CampaignFormatter.php';
require_once 'src/AssetDownloader.php';
require_once 'src/MetadataExtractor.php';
require_once 'src/StatusManager.php';
require_once 'src/ApiClient.php';
$configV3 = new ConfigV3();
$errors = $configV3->validate();
if (!empty($errors)) {
die("Configuration Error: " . implode(', ', $errors));
}
$config = [
'baseUrl' => $configV3->getBaseUrl(),
'timeout' => $configV3->get('api.timeout'),
'headers' => [
'Content-Type' => 'application/json',
'Accept' => 'application/json'
]
];
$collectionPath = __DIR__ . '/' . $configV3->get('postman_collection');
$testRunner = null;
$error = null;
$success = null;
$currentTab = $_GET['tab'] ?? $_POST['tab'] ?? 'download';
try {
if (file_exists($collectionPath)) {
$testRunner = new TestRunner($collectionPath, $config);
} else {
$error = "Postman collection file not found: " . $collectionPath;
}
} catch (Exception $e) {
$error = "Error initializing: " . $e->getMessage();
}
// Initialize results storage
if (!isset($_SESSION['workflow_results'])) {
$_SESSION['workflow_results'] = [];
}
$results = &$_SESSION['workflow_results'];
// Handle POST actions
if ($_POST && $testRunner) {
$action = $_POST['action'] ?? '';
try {
switch ($action) {
case 'load_campaigns_a1':
$results['a1_campaigns'] = loadCampaignsByStatus($testRunner, 'A1');
$success = "Loaded " . count($results['a1_campaigns']) . " campaigns with status A1";
break;
case 'select_campaign_a1':
$campaignId = $_POST['campaign_id'] ?? '';
if ($campaignId && isset($results['a1_campaigns'])) {
foreach ($results['a1_campaigns'] as $campaign) {
if ($campaign['asset_id'] === $campaignId) {
$results['selected_campaign'] = $campaign;
$success = "Campaign selected: " . $campaign['campaign_name'];
break;
}
}
}
break;
case 'get_master_assets':
if (isset($results['selected_campaign'])) {
$campaignId = $results['selected_campaign']['asset_id'];
$masterFolderId = findMasterAssetsFolder($testRunner, $campaignId, $configV3);
if ($masterFolderId) {
$results['master_folder_id'] = $masterFolderId;
$results['master_assets'] = getAssetsFromFolder($testRunner, $masterFolderId);
$success = "Found Master Assets folder with " . count($results['master_assets']) . " assets";
} else {
$error = "Master Assets folder not found in campaign";
}
}
break;
case 'download_asset':
$assetId = $_POST['asset_id'] ?? '';
$filename = $_POST['filename'] ?? '';
if ($assetId && isset($results['selected_campaign'])) {
$result = downloadAsset($testRunner, $assetId, $filename, $results['selected_campaign']['campaign_id']);
$results['last_download'] = $result;
if ($result['success']) {
$success = "Downloaded: " . $result['filename'];
} else {
$error = "Download failed: " . $result['error'];
}
}
break;
case 'download_all_assets':
if (isset($results['master_assets']) && isset($results['selected_campaign'])) {
$downloadResults = downloadAllAssets($testRunner, $results['master_assets'], $results['selected_campaign']['campaign_id']);
$results['bulk_download'] = $downloadResults;
$success = "Downloaded {$downloadResults['successful']} of {$downloadResults['total']} assets";
}
break;
case 'update_status_to_a2':
if (isset($results['selected_campaign'])) {
$statusManager = createStatusManager($testRunner);
$statusResult = $statusManager->updateCampaignStatus(
$results['selected_campaign']['asset_id'],
'A2'
);
if ($statusResult['success']) {
$results['status_update'] = $statusResult;
$results['selected_campaign']['status'] = 'A2';
$success = "Campaign status updated to A2: Selected Master Assets sent to Agency";
} else {
$error = "Failed to update status: " . ($statusResult['response']['error'] ?? 'Unknown error');
}
}
break;
case 'load_campaigns_a2':
$results['a2_campaigns'] = loadCampaignsByStatus($testRunner, 'A2');
$success = "Loaded " . count($results['a2_campaigns']) . " campaigns with status A2";
$currentTab = 'upload';
break;
case 'load_campaigns_a5':
$results['a5_campaigns'] = loadCampaignsByStatus($testRunner, 'A5');
$success = "Loaded " . count($results['a5_campaigns']) . " campaigns with status A5";
$currentTab = 'rework';
break;
}
} catch (Exception $e) {
$error = "Action failed: " . $e->getMessage();
}
}
// Helper Functions
function loadCampaignsByStatus($testRunner, $status)
{
$statusManager = createStatusManager($testRunner);
$response = $statusManager->searchCampaignsByStatus($status);
if ($response['success']) {
$data = json_decode($response['body'], true);
return CampaignFormatter::getActionableCampaigns($response['body'], ['status' => $status]);
}
return [];
}
function findMasterAssetsFolder($testRunner, $campaignId, $configV3)
{
$masterFolderName = $configV3->getFolderName('master_assets');
$requests = $testRunner->getAvailableRequests();
foreach ($requests as $index => $request) {
$name = strtolower($request['name']);
if (strpos($name, 'retrieve master asset folder') !== false ||
strpos($name, 'master asset folder and final') !== false) {
$modifiedRequest = $request;
$url = is_array($request['request']['url']) ? $request['request']['url']['raw'] : $request['request']['url'];
$url = preg_replace('/folders\/[a-f0-9]+\//', "folders/{$campaignId}/", $url);
$url = str_replace('{{baseUrl}}', $configV3->getBaseUrl(), $url);
if (is_array($modifiedRequest['request']['url'])) {
$modifiedRequest['request']['url']['raw'] = $url;
} else {
$modifiedRequest['request']['url'] = $url;
}
$result = $testRunner->runSingleTest($modifiedRequest, $index);
if ($result['status'] === 'PASS') {
$data = json_decode($result['response']['body'], true);
$folders = $data['folder_children']['asset_list'] ?? [];
foreach ($folders as $folder) {
$folderName = extractFolderName($folder);
if (strpos($folderName, 'Master') !== false || $folderName === $masterFolderName) {
return $folder['asset_id'];
}
}
}
break;
}
}
return null;
}
function extractFolderName($folder)
{
$nameFields = [
'ARTESIA.FIELD.NAME',
'FERRERO.FIELD.CAMPAIGN_NAME',
'ARTESIA.FIELD.TITLE'
];
if (isset($folder['metadata']['metadata_element_list'])) {
foreach ($folder['metadata']['metadata_element_list'] as $category) {
if (isset($category['metadata_element_list'])) {
foreach ($category['metadata_element_list'] as $field) {
if (in_array($field['id'], $nameFields) && isset($field['value']['value']['value'])) {
return $field['value']['value']['value'];
}
}
}
}
}
return $folder['name'] ?? $folder['title'] ?? 'Unnamed';
}
function getAssetsFromFolder($testRunner, $folderId)
{
$requests = $testRunner->getAvailableRequests();
foreach ($requests as $index => $request) {
$name = strtolower($request['name']);
if (strpos($name, 'retrieve all assets from') !== false) {
$modifiedRequest = $request;
$url = is_array($request['request']['url']) ? $request['request']['url']['raw'] : $request['request']['url'];
$url = preg_replace('/folders\/[a-f0-9]+\//', "folders/{$folderId}/", $url);
if (is_array($modifiedRequest['request']['url'])) {
$modifiedRequest['request']['url']['raw'] = $url;
} else {
$modifiedRequest['request']['url'] = $url;
}
$result = $testRunner->runSingleTest($modifiedRequest, $index);
if ($result['status'] === 'PASS') {
$data = json_decode($result['response']['body'], true);
$assets = $data['folder_children']['asset_list'] ?? [];
// Filter out folders, only return files
return array_filter($assets, function($asset) {
return ($asset['data_type'] ?? '') !== 'CONTAINER';
});
}
break;
}
}
return [];
}
function downloadAsset($testRunner, $assetId, $filename, $campaignId)
{
$apiClient = new ApiClient();
$configV3 = new ConfigV3();
$apiClient->setBaseUrl($configV3->getBaseUrl());
// Get OAuth2 token
$oauth2Handler = new ReflectionProperty($testRunner, 'oauth2Handler');
$oauth2Handler->setAccessible(true);
$oauth2HandlerInstance = $oauth2Handler->getValue($testRunner);
if ($oauth2HandlerInstance) {
$apiClient->setHeader('Authorization', $oauth2HandlerInstance->getAuthHeader());
}
$request = [
'method' => 'GET',
'url' => "/v6/assets/{$assetId}/contents"
];
$response = $apiClient->executeRequest($request);
if ($response['success'] && !empty($response['body'])) {
$downloadPath = $configV3->getDownloadPath($campaignId);
if (!is_dir($downloadPath)) {
mkdir($downloadPath, 0755, true);
}
$safeFilename = preg_replace('/[^a-zA-Z0-9._-]/', '_', $filename ?: "asset_{$assetId}");
$fullPath = $downloadPath . '/' . $safeFilename;
$bytesWritten = file_put_contents($fullPath, $response['body']);
return [
'success' => $bytesWritten !== false,
'filename' => $safeFilename,
'filepath' => $fullPath,
'size' => $bytesWritten,
'asset_id' => $assetId
];
}
return [
'success' => false,
'error' => $response['error'] ?? 'Download failed',
'http_code' => $response['http_code']
];
}
function downloadAllAssets($testRunner, $assets, $campaignId)
{
$results = [
'total' => count($assets),
'successful' => 0,
'failed' => 0,
'details' => []
];
foreach ($assets as $asset) {
$filename = extractFolderName($asset);
$result = downloadAsset($testRunner, $asset['asset_id'], $filename, $campaignId);
if ($result['success']) {
$results['successful']++;
} else {
$results['failed']++;
}
$results['details'][] = $result;
}
return $results;
}
function createStatusManager($testRunner)
{
$apiClient = new ApiClient();
$configV3 = new ConfigV3();
$apiClient->setBaseUrl($configV3->getBaseUrl());
$oauth2Handler = new ReflectionProperty($testRunner, 'oauth2Handler');
$oauth2Handler->setAccessible(true);
$oauth2HandlerInstance = $oauth2Handler->getValue($testRunner);
if ($oauth2HandlerInstance) {
$apiClient->setHeader('Authorization', $oauth2HandlerInstance->getAuthHeader());
}
return new StatusManager($apiClient);
}
$oauth2Status = $testRunner ? $testRunner->getOAuth2Status() : null;
$envInfo = $configV3->getEnvironmentInfo();
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Content Scaling Workflow V3</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background-color: #f5f5f5;
padding: 20px;
}
.container {
max-width: 1400px;
margin: 0 auto;
background: white;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
overflow: hidden;
}
.header {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 30px;
text-align: center;
}
.header h1 { margin-bottom: 10px; }
.header p { opacity: 0.9; }
.env-info {
background: rgba(255,255,255,0.2);
padding: 10px;
border-radius: 4px;
margin-top: 15px;
font-size: 13px;
}
.tabs {
display: flex;
background: #f8f9fa;
border-bottom: 2px solid #dee2e6;
}
.tab {
flex: 1;
padding: 15px 20px;
text-align: center;
cursor: pointer;
border: none;
background: transparent;
font-size: 16px;
font-weight: 500;
color: #6c757d;
transition: all 0.3s;
}
.tab:hover { background: #e9ecef; }
.tab.active {
background: white;
color: #667eea;
border-bottom: 3px solid #667eea;
}
.tab-content {
padding: 30px;
display: none;
}
.tab-content.active { display: block; }
.alert {
padding: 12px 20px;
border-radius: 6px;
margin-bottom: 20px;
}
.alert-error {
background: #f8d7da;
color: #721c24;
border: 1px solid #f5c6cb;
}
.alert-success {
background: #d4edda;
color: #155724;
border: 1px solid #c3e6cb;
}
.alert-info {
background: #d1ecf1;
color: #0c5460;
border: 1px solid #bee5eb;
}
.btn {
padding: 12px 24px;
border: none;
border-radius: 6px;
font-size: 14px;
font-weight: 500;
cursor: pointer;
transition: all 0.3s;
margin-right: 10px;
margin-bottom: 10px;
}
.btn-primary {
background: #667eea;
color: white;
}
.btn-primary:hover { background: #5568d3; }
.btn-success {
background: #28a745;
color: white;
}
.btn-success:hover { background: #218838; }
.btn-danger {
background: #dc3545;
color: white;
}
.btn-secondary {
background: #6c757d;
color: white;
}
.campaign-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(350px, 1fr));
gap: 20px;
margin: 20px 0;
}
.campaign-card {
background: #f8f9fa;
border: 2px solid #dee2e6;
border-radius: 8px;
padding: 20px;
cursor: pointer;
transition: all 0.3s;
}
.campaign-card:hover {
border-color: #667eea;
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.2);
}
.campaign-card.selected {
border-color: #28a745;
background: #f8fff9;
}
.campaign-card h3 {
color: #333;
margin-bottom: 10px;
}
.campaign-card p {
margin: 5px 0;
font-size: 14px;
color: #666;
}
.asset-list {
background: #f8f9fa;
border-radius: 8px;
padding: 20px;
margin: 20px 0;
}
.asset-item {
background: white;
border: 1px solid #dee2e6;
border-radius: 6px;
padding: 15px;
margin: 10px 0;
display: flex;
justify-content: space-between;
align-items: center;
}
.asset-info {
flex: 1;
}
.asset-actions {
display: flex;
gap: 10px;
}
.metadata-display {
background: #e9ecef;
padding: 15px;
border-radius: 6px;
margin-top: 10px;
font-size: 12px;
font-family: monospace;
max-height: 300px;
overflow-y: auto;
display: none;
}
.status-badge {
display: inline-block;
padding: 4px 12px;
border-radius: 12px;
font-size: 12px;
font-weight: 600;
}
.status-a1 { background: #fff3cd; color: #856404; }
.status-a2 { background: #cfe2ff; color: #084298; }
.status-a3 { background: #d1e7dd; color: #0f5132; }
.status-a5 { background: #f8d7da; color: #842029; }
.status-a6 { background: #e2d9f3; color: #432874; }
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>🎯 Content Scaling Workflow V3</h1>
<p>Status-based workflow management for Ferrero DAM</p>
<div class="env-info">
<strong>Environment:</strong> <?= htmlspecialchars($envInfo['description']) ?>
(<?= htmlspecialchars($envInfo['name']) ?>)
<br>
<strong>Base URL:</strong> <?= htmlspecialchars($envInfo['baseUrl']) ?>
</div>
</div>
<?php if ($error): ?>
<div style="padding: 20px;">
<div class="alert alert-error">
<strong>❌ Error:</strong> <?= htmlspecialchars($error) ?>
</div>
</div>
<?php endif; ?>
<?php if ($success): ?>
<div style="padding: 20px;">
<div class="alert alert-success">
<strong>✅ Success:</strong> <?= htmlspecialchars($success) ?>
</div>
</div>
<?php endif; ?>
<?php if ($oauth2Status && $oauth2Status['enabled']): ?>
<div style="padding: 20px; padding-bottom: 0;">
<div class="alert alert-<?= ($oauth2Status['has_token'] ?? false) ? 'success' : 'error' ?>">
<?= ($oauth2Status['has_token'] ?? false) ? '✅ OAuth2 Token Active' : '❌ OAuth2 Token Issue' ?>
<?php if (($oauth2Status['has_token'] ?? false) && isset($oauth2Status['expires_at'])): ?>
- Expires: <?= htmlspecialchars($oauth2Status['expires_at']) ?>
<?php endif; ?>
</div>
</div>
<?php endif; ?>
<div class="tabs">
<button class="tab <?= $currentTab === 'download' ? 'active' : '' ?>"
onclick="switchTab('download')">
📥 Download Workflow (A1→A2)
</button>
<button class="tab <?= $currentTab === 'upload' ? 'active' : '' ?>"
onclick="switchTab('upload')">
📤 Upload Workflow (A2→A3)
</button>
<button class="tab <?= $currentTab === 'rework' ? 'active' : '' ?>"
onclick="switchTab('rework')">
🔄 Rework Workflow (A5→A6)
</button>
</div>
<!-- Download Workflow Tab -->
<div id="tab-download" class="tab-content <?= $currentTab === 'download' ? 'active' : '' ?>">
<h2>📥 Download Workflow: A1 → A2</h2>
<p style="color: #666; margin: 10px 0 20px 0;">
Load campaigns with status A1, download master assets, and update status to A2
</p>
<form method="POST">
<input type="hidden" name="tab" value="download">
<input type="hidden" name="action" value="load_campaigns_a1">
<button type="submit" class="btn btn-primary">Load Campaigns with Status A1</button>
</form>
<?php if (isset($results['a1_campaigns']) && !empty($results['a1_campaigns'])): ?>
<h3 style="margin-top: 30px;">Found <?= count($results['a1_campaigns']) ?> Campaigns</h3>
<div class="campaign-grid">
<?php foreach ($results['a1_campaigns'] as $campaign): ?>
<div class="campaign-card <?= (isset($results['selected_campaign']) && $results['selected_campaign']['asset_id'] === $campaign['asset_id']) ? 'selected' : '' ?>"
onclick="selectCampaign('<?= htmlspecialchars($campaign['asset_id']) ?>')">
<h3><?= htmlspecialchars($campaign['campaign_name'] ?? 'Unnamed Campaign') ?></h3>
<p><strong>ID:</strong> <?= htmlspecialchars($campaign['campaign_id'] ?? 'N/A') ?></p>
<p><strong>Brand:</strong> <?= htmlspecialchars($campaign['brand'] ?? 'N/A') ?></p>
<p><strong>Market:</strong> <?= htmlspecialchars($campaign['market'] ?? 'N/A') ?></p>
<p><span class="status-badge status-a1">A1 - Ready for Localization</span></p>
</div>
<?php endforeach; ?>
</div>
<form method="POST" id="select-campaign-form">
<input type="hidden" name="tab" value="download">
<input type="hidden" name="action" value="select_campaign_a1">
<input type="hidden" name="campaign_id" id="selected-campaign-id">
<button type="submit" class="btn btn-success" id="select-campaign-btn" disabled>
Select Campaign & Continue
</button>
</form>
<?php endif; ?>
<?php if (isset($results['selected_campaign'])): ?>
<div class="alert alert-info" style="margin-top: 30px;">
<strong>Selected Campaign:</strong>
<?= htmlspecialchars($results['selected_campaign']['campaign_name']) ?>
(<?= htmlspecialchars($results['selected_campaign']['campaign_id']) ?>)
</div>
<form method="POST" style="margin-top: 20px;">
<input type="hidden" name="tab" value="download">
<input type="hidden" name="action" value="get_master_assets">
<button type="submit" class="btn btn-primary">Get Master Assets</button>
</form>
<?php endif; ?>
<?php if (isset($results['master_assets']) && !empty($results['master_assets'])): ?>
<h3 style="margin-top: 30px;">Master Assets (<?= count($results['master_assets']) ?> files)</h3>
<form method="POST" style="margin: 20px 0;">
<input type="hidden" name="tab" value="download">
<input type="hidden" name="action" value="download_all_assets">
<button type="submit" class="btn btn-success">📥 Download All Assets</button>
</form>
<div class="asset-list">
<?php foreach ($results['master_assets'] as $asset): ?>
<?php
$assetName = extractFolderName($asset);
$assetId = $asset['asset_id'];
?>
<div class="asset-item">
<div class="asset-info">
<strong><?= htmlspecialchars($assetName) ?></strong><br>
<small>ID: <?= htmlspecialchars($assetId) ?></small><br>
<small>Type: <?= htmlspecialchars($asset['mime_type'] ?? 'Unknown') ?></small>
<?php if (isset($asset['file_size'])): ?>
<small> | Size: <?= number_format($asset['file_size']) ?> bytes</small>
<?php endif; ?>
</div>
<div class="asset-actions">
<form method="POST" style="display: inline;">
<input type="hidden" name="tab" value="download">
<input type="hidden" name="action" value="download_asset">
<input type="hidden" name="asset_id" value="<?= htmlspecialchars($assetId) ?>">
<input type="hidden" name="filename" value="<?= htmlspecialchars($assetName) ?>">
<button type="submit" class="btn btn-success">📥 Download</button>
</form>
<button class="btn btn-secondary"
onclick="toggleMetadata('<?= htmlspecialchars($assetId) ?>')">
📋 Metadata
</button>
</div>
</div>
<div id="metadata-<?= htmlspecialchars($assetId) ?>" class="metadata-display">
<?= MetadataExtractor::formatMetadataForDisplay(MetadataExtractor::extractAllMetadata($asset)) ?>
</div>
<?php endforeach; ?>
</div>
<div style="margin-top: 30px; padding: 20px; background: #fff3cd; border-radius: 8px;">
<h4>⚠️ Update Status to A2</h4>
<p style="margin: 10px 0;">
Once all assets are downloaded, update the campaign status to A2
(Selected Master Assets sent to Agency)
</p>
<form method="POST">
<input type="hidden" name="tab" value="download">
<input type="hidden" name="action" value="update_status_to_a2">
<button type="submit" class="btn btn-success">Update Status: A1 → A2</button>
</form>
</div>
<?php endif; ?>
<?php if (isset($results['bulk_download'])): ?>
<div class="alert alert-<?= $results['bulk_download']['successful'] === $results['bulk_download']['total'] ? 'success' : 'error' ?>"
style="margin-top: 20px;">
<strong>Download Results:</strong>
<?= $results['bulk_download']['successful'] ?> of <?= $results['bulk_download']['total'] ?> assets downloaded successfully
</div>
<?php endif; ?>
</div>
<!-- Upload Workflow Tab -->
<div id="tab-upload" class="tab-content <?= $currentTab === 'upload' ? 'active' : '' ?>">
<h2>📤 Upload Workflow: A2 → A3</h2>
<p style="color: #666; margin: 10px 0 20px 0;">
Load campaigns with status A2, upload processed assets, and update status to A3
</p>
<form method="POST">
<input type="hidden" name="tab" value="upload">
<input type="hidden" name="action" value="load_campaigns_a2">
<button type="submit" class="btn btn-primary">Load Campaigns with Status A2</button>
</form>
<div class="alert alert-info" style="margin-top: 20px;">
<strong> Coming Soon:</strong> Upload functionality will be implemented in next phase
</div>
</div>
<!-- Rework Workflow Tab -->
<div id="tab-rework" class="tab-content <?= $currentTab === 'rework' ? 'active' : '' ?>">
<h2>🔄 Rework Workflow: A5 → A6</h2>
<p style="color: #666; margin: 10px 0 20px 0;">
Load campaigns with status A5 (rework needed), download assets for rework, and update status to A6
</p>
<form method="POST">
<input type="hidden" name="tab" value="rework">
<input type="hidden" name="action" value="load_campaigns_a5">
<button type="submit" class="btn btn-primary">Load Campaigns with Status A5</button>
</form>
<div class="alert alert-info" style="margin-top: 20px;">
<strong> Coming Soon:</strong> Rework workflow will be implemented in next phase
</div>
</div>
</div>
<script>
function switchTab(tabName) {
// Update tabs
document.querySelectorAll('.tab').forEach(tab => tab.classList.remove('active'));
document.querySelectorAll('.tab-content').forEach(content => content.classList.remove('active'));
event.target.classList.add('active');
document.getElementById('tab-' + tabName).classList.add('active');
// Update URL without reload
const url = new URL(window.location);
url.searchParams.set('tab', tabName);
window.history.pushState({}, '', url);
}
function selectCampaign(campaignId) {
document.querySelectorAll('.campaign-card').forEach(card => {
card.classList.remove('selected');
});
event.currentTarget.classList.add('selected');
document.getElementById('selected-campaign-id').value = campaignId;
document.getElementById('select-campaign-btn').disabled = false;
}
function toggleMetadata(assetId) {
const metadataDiv = document.getElementById('metadata-' + assetId);
metadataDiv.style.display = metadataDiv.style.display === 'none' ? 'block' : 'none';
}
</script>
</body>
</html>