let features = [];
let templates = {
'azure-service': {
name: 'azure-service-integration',
display_name: 'Azure Service Integration',
description: 'Integrate with Azure services for cloud resource management',
dependencies: ['azure-identity', 'azure-mgmt-compute', 'azure-mgmt-storage'],
handler_code: `def register_routes(app):
@app.route('/api/azure/services')
def azure_services():
return {'services': ['vm', 'storage', 'database']}
@app.route('/api/azure/deploy-vm', methods=['POST'])
def deploy_vm():
data = request.get_json()
# VM deployment logic here
return {'status': 'VM deployment initiated'}
def register_ui(app):
# Add Azure service UI components
pass`
},
'authentication': {
name: 'auth-provider',
display_name: 'Authentication Provider',
description: 'Add OAuth, OKTA, or custom authentication methods',
dependencies: ['requests-oauthlib', 'okta', 'flask-oauthlib'],
handler_code: `def register_routes(app):
@app.route('/api/auth/login')
def auth_login():
return {'providers': ['oauth', 'okta', 'custom']}
@app.route('/api/auth/callback')
def auth_callback():
# Handle authentication callback
return {'status': 'authenticated'}
def register_ui(app):
# Add authentication UI components
pass`
},
'ci-cd': {
name: 'ci-cd-pipeline',
display_name: 'CI/CD Pipeline',
description: 'Continuous integration and deployment pipeline management',
dependencies: ['jenkinsapi', 'gitlab', 'github'],
handler_code: `def register_routes(app):
@app.route('/api/cicd/pipelines')
def get_pipelines():
return {'pipelines': []}
@app.route('/api/cicd/deploy', methods=['POST'])
def deploy():
data = request.get_json()
# Deployif (template === 'github-load') {
openGithubModal();
} else if (template === 'script-load') {
openScriptModal();
} else {
loadTemplate(template);
}
return {'status': 'deployment started'}
// GitHub form submission
document.getElementById('github-form').addEventListener('submit', function(e) {
e.preventDefault();
loadFromGithub();
});
// Script form submission
document.getElementById('script-form').addEventListener('submit', function(e) {
e.preventDefault();
createFromScript();
});
def register_ui(app):
# Add CI/CD UI components
pass`
},
'github-integration': {
name: 'github-integration',
display_name: 'GitHub Integration',
description: 'Connect to GitHub repositories and manage resources',
dependencies: ['PyGitHub', 'requests'],
handler_code: `def register_routes(app):
@app.route('/api/github/repos')
def github_repos():
return {'repos': []}
@app.route('/api/github/clone', methods=['POST'])
def clone_repo():
data = request.get_json()
# Clone repository logic
return {'status': 'repository cloned'}
def register_ui(app):
# Add GitHub UI components
pass`
},
'cloud-management': {
name: 'cloud-management',
display_name: 'Cloud Management',
description: 'Multi-cloud resource management and monitoring',
dependencies: ['boto3', 'azure-identity', 'google-cloud'],
handler_code: `def register_routes(app):
@app.route('/api/cloud/resources')
def cloud_resources():
return {'providers': ['aws', 'azure', 'gcp']}
@app.route('/api/cloud/monitor')
def cloud_monitor():
# Monitoring logic here
return {'status': 'monitoring active'}
def register_ui(app):
# Add cloud management UI components
pass`
},
'custom': {
name: 'custom-feature',
display_name: 'Custom Feature',
description: 'Create a completely custom feature',
dependencies: [],
handler_code: `def register_routes(app):
@app.route('/api/custom')
def custom_endpoint():
return {'message': 'Custom feature endpoint'}
def register_ui(app):
# Add custom UI components
pass`
}
};
// Load features on page load
document.addEventListener('DOMContentLoaded', function() {
loadFeatures();
});
// Template selection
document.getElementById('template-grid').addEventListener('click', function(e) {
console.log('Template grid clicked', e.target);
if (e.target.closest('.template-card')) {
const templateCard = e.target.closest('.template-card');
const template = templateCard.dataset.template;
console.log('Template selected:', template);
loadTemplate(template);
}
});
// Form submission
document.getElementById('feature-form').addEventListener('submit', function(e) {
e.preventDefault();
createFeature();
});
document.getElementById('github-form').addEventListener('submit', function(e) {
e.preventDefault();
loadFromGithub();
});
document.getElementById('script-form').addEventListener('submit', function(e) {
e.preventDefault();
createFromScript();
});
document.getElementById('script-url-form').addEventListener('submit', function(e) {
e.preventDefault();
loadFromUrl();
});
async function loadFeatures() {
try {
const response = await fetch('/api/features');
const data = await response.json();
features = data.features || [];
renderFeatures();
} catch (error) {
showAlert('Error loading features: ' + error.message, 'error');
}
}
function renderFeatures() {
const grid = document.getElementById('features-grid');
if (features.length === 0) {
grid.innerHTML = '
No features available. Create your first feature!
';
return;
}
grid.innerHTML = features.map(feature => `
${feature.enabled ? 'Enabled' : 'Disabled'}
${feature.description}
Version: ${feature.version}
Deps: ${feature.dependencies.length}
${feature.ui_components && feature.ui_components.length > 0 ? `
${feature.ui_components.map(component =>
component.actions ? component.actions.map(action =>
action.action === 'navigate' ?
`` :
action.action === 'modal' ?
`` :
``
).join('') : ''
).join('')}
` : ''}
`).join('');
}
function loadTemplate(templateName) {
console.log('Loading template:', templateName);
if (templateName === 'github-load') {
console.log('Calling openGithubModal');
openGithubModal();
return;
} else if (templateName === 'script-load') {
openScriptModal();
return;
}
const template = templates[templateName];
if (!template) return;
document.getElementById('feature-name').value = template.name;
document.getElementById('feature-display-name').value = template.display_name;
document.getElementById('feature-description').value = template.description;
document.getElementById('feature-dependencies').value = template.dependencies.join(', ');
document.getElementById('handler-code').value = template.handler_code;
document.getElementById('feature-modal').style.display = 'block';
}
async function createFeature() {
const formData = new FormData(document.getElementById('feature-form'));
const data = {
name: formData.get('name'),
display_name: formData.get('display_name'),
description: formData.get('description'),
dependencies: formData.get('dependencies').split(',').map(d => d.trim()).filter(d => d),
handler_code: formData.get('handler_code')
};
try {
const response = await fetch('/api/features/create', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
});
const result = await response.json();
if (result.success) {
showAlert('Feature created successfully!', 'success');
closeModal();
loadFeatures();
} else {
showAlert('Error creating feature: ' + result.error, 'error');
}
} catch (error) {
showAlert('Error creating feature: ' + error.message, 'error');
}
}
async function toggleFeature(featureName, enabled) {
try {
const response = await fetch(\`/api/features/\${featureName}/toggle\`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ enabled })
});
const result = await response.json();
if (result.success) {
showAlert(\`Feature \${enabled ? 'enabled' : 'disabled'} successfully!\`, 'success');
loadFeatures();
} else {
showAlert('Error toggling feature: ' + result.error, 'error');
}
} catch (error) {
showAlert('Error toggling feature: ' + error.message, 'error');
}
}
function editFeature(featureName) {
// TODO: Implement feature editing
showAlert('Feature editing not yet implemented', 'error');
}
function deleteFeature(featureName) {
if (confirm(\`Are you sure you want to delete the feature "\${featureName}"?\`)) {
// TODO: Implement feature deletion
showAlert('Feature deletion not yet implemented', 'error');
}
}
function closeModal() {
document.getElementById('feature-modal').style.display = 'none';
document.getElementById('feature-form').reset();
}
function openGithubModal() {
console.log('Opening GitHub modal');
document.getElementById('github-modal').style.display = 'block';
}
function closeGithubModal() {
document.getElementById('github-modal').style.display = 'none';
}
async function loadFromGithub() {
const formData = new FormData(document.getElementById('github-form'));
const url = formData.get('github-url');
if (!url) {
showAlert('Please enter a GitHub repository URL', 'error');
return;
}
try {
const response = await fetch('/api/features/github/load', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ url: url })
});
const result = await response.json();
if (result.success) {
showAlert('Feature loaded from GitHub successfully', 'success');
closeGithubModal();
loadFeatures(); // Refresh the features list
} else {
showAlert(result.error || 'Failed to load from GitHub', 'error');
}
} catch (error) {
showAlert('Error loading from GitHub: ' + error.message, 'error');
}
}
function openScriptModal() {
document.getElementById('script-modal').style.display = 'block';
}
function closeScriptModal() {
document.getElementById('script-modal').style.display = 'none';
}
async function createFromScript() {
const formData = new FormData(document.getElementById('script-form'));
const scriptContent = formData.get('script-content');
if (!scriptContent) {
showAlert('Please enter script content', 'error');
return;
}
try {
const response = await fetch('/api/features/script/create', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ content: scriptContent })
});
const result = await response.json();
if (result.success) {
showAlert('Feature created from script successfully', 'success');
closeScriptModal();
loadFeatures(); // Refresh the features list
} else {
showAlert(result.error || 'Failed to create from script', 'error');
}
} catch (error) {
showAlert('Error creating from script: ' + error.message, 'error');
}
}
function showAlert(message, type) {
const alerts = document.getElementById('alerts');
const alert = document.createElement('div');
alert.className = \`alert alert-\${type}\`;
alert.textContent = message;
alerts.appendChild(alert);
setTimeout(() => {
alert.remove();
}, 5000);
}
// Tab switching functions
function switchGithubTab(tabName) {
// Hide all tabs
document.querySelectorAll('.tab-content').forEach(tab => tab.classList.remove('active'));
document.querySelectorAll('.tab-button').forEach(btn => btn.classList.remove('active'));
// Show selected tab
document.getElementById(`github-${tabName}-tab`).classList.add('active');
event.target.classList.add('active');
}
function switchScriptTab(tabName) {
// Hide all tabs
document.querySelectorAll('#script-modal .tab-content').forEach(tab => tab.classList.remove('active'));
document.querySelectorAll('#script-modal .tab-button').forEach(btn => btn.classList.remove('active'));
// Show selected tab
document.getElementById(`script-${tabName}-tab`).classList.add('active');
event.target.classList.add('active');
}
// GitHub browsing functions
async function loadUserRepos() {
const username = document.getElementById('github-user').value.trim();
if (!username) {
showAlert('Please enter a GitHub username or organization', 'error');
return;
}
try {
const response = await fetch(`/api/features/github/user/${username}/repos`);
const data = await response.json();
if (data.repos && data.repos.length > 0) {
displayRepos(data.repos);
} else {
showAlert('No repositories found for this user/organization', 'warning');
}
} catch (error) {
showAlert('Error loading repositories: ' + error.message, 'error');
}
}
async function searchGithubRepos() {
const query = document.getElementById('github-search').value.trim();
if (!query) {
showAlert('Please enter a search term', 'error');
return;
}
try {
const response = await fetch(`/api/features/github/search?q=${encodeURIComponent(query)}`);
const data = await response.json();
if (data.repos && data.repos.length > 0) {
displayRepos(data.repos);
} else {
showAlert('No repositories found matching your search', 'warning');
}
} catch (error) {
showAlert('Error searching repositories: ' + error.message, 'error');
}
}
function displayRepos(repos) {
const container = document.getElementById('github-repos-list') || document.getElementById('github-search-results');
container.innerHTML = '';
repos.forEach(repo => {
const repoItem = document.createElement('div');
repoItem.className = 'repo-item';
repoItem.innerHTML = `
${repo.name}
${repo.description || 'No description available'}
⭐ ${repo.stargazers_count || 0} • ${repo.language || 'Unknown'}
`;
container.appendChild(repoItem);
});
}
let selectedRepo = null;
function selectRepo(fullName) {
selectedRepo = fullName;
// Highlight selected repo
document.querySelectorAll('.repo-item').forEach(item => {
item.style.background = 'transparent';
});
event.target.closest('.repo-item').style.background = 'rgba(76, 175, 80, 0.2)';
}
async function loadFromSelectedRepo() {
if (!selectedRepo) {
showAlert('Please select a repository first', 'error');
return;
}
const featureName = document.getElementById('browse-feature-name').value ||
document.getElementById('search-feature-name').value;
const data = {
repo_url: `https://github.com/${selectedRepo}`,
feature_name: featureName || null
};
try {
const response = await fetch('/api/features/load-github', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
});
const result = await response.json();
if (result.success) {
showAlert('Feature loaded from GitHub successfully!', 'success');
closeGithubModal();
loadFeatures();
} else {
showAlert('Error loading from GitHub: ' + result.error, 'error');
}
} catch (error) {
showAlert('Error loading from GitHub: ' + error.message, 'error');
}
}
// Script loading functions
async function loadFromUrl() {
const formData = new FormData(document.getElementById('script-url-form'));
const data = {
script_url: formData.get('script_url'),
script_type: formData.get('script_type'),
feature_name: formData.get('feature_name'),
display_name: formData.get('display_name'),
description: formData.get('description')
};
try {
const response = await fetch('/api/features/create-from-url', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
});
const result = await response.json();
if (result.success) {
showAlert('Feature created from URL successfully!', 'success');
closeScriptModal();
loadFeatures();
} else {
showAlert('Error creating from URL: ' + result.error, 'error');
}
} catch (error) {
showAlert('Error creating from URL: ' + error.message, 'error');
}
}
async function loadRepoScripts() {
const repoUrl = document.getElementById('repo-url').value.trim();
if (!repoUrl) {
showAlert('Please enter a repository URL', 'error');
return;
}
try {
const response = await fetch('/api/features/github/repo-scripts', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ repo_url: repoUrl })
});
const data = await response.json();
if (data.scripts && data.scripts.length > 0) {
displayScripts(data.scripts);
} else {
showAlert('No script files found in this repository', 'warning');
}
} catch (error) {
showAlert('Error loading repository scripts: ' + error.message, 'error');
}
}
function displayScripts(scripts) {
const container = document.getElementById('repo-scripts-list');
container.innerHTML = '';
scripts.forEach(script => {
const scriptItem = document.createElement('div');
scriptItem.className = 'script-item';
scriptItem.innerHTML = `
${script.name}
${script.path}
Size: ${script.size} • Last modified: ${script.last_modified}
`;
container.appendChild(scriptItem);
});
}
let selectedScript = null;
function selectScript(scriptPath) {
selectedScript = scriptPath;
// Highlight selected script
document.querySelectorAll('.script-item').forEach(item => {
item.style.background = 'transparent';
});
event.target.closest('.script-item').style.background = 'rgba(76, 175, 80, 0.2)';
}
async function loadFromSelectedScript() {
if (!selectedScript) {
showAlert('Please select a script first', 'error');
return;
}
const repoUrl = document.getElementById('repo-url').value;
const scriptType = document.getElementById('repo-script-type').value;
const featureName = document.getElementById('repo-feature-name').value;
const displayName = document.getElementById('repo-display-name').value;
const description = document.getElementById('repo-description').value;
const data = {
repo_url: repoUrl,
script_path: selectedScript,
script_type: scriptType,
feature_name: featureName,
display_name: displayName,
description: description
};
try {
const response = await fetch('/api/features/create-from-repo-script', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
});
const result = await response.json();
if (result.success) {
showAlert('Feature created from repository script successfully!', 'success');
closeScriptModal();
loadFeatures();
} else {
showAlert('Error creating from repository script: ' + result.error, 'error');
}
} catch (error) {
showAlert('Error creating from repository script: ' + error.message, 'error');
}
}
function runFeatureAction(featureName, actionLabel) {
// Generic function for feature-specific actions
showAlert(`Running ${actionLabel} for ${featureName}...`, 'info');
// TODO: Implement specific actions based on actionLabel
}
function openModal(modalId) {
// Generic modal opener
const modal = document.getElementById(modalId);
if (modal) {
modal.style.display = 'block';
} else {
showAlert(`Modal ${modalId} not found`, 'error');
}
}
// Close modal when clicking outside
window.onclick = function(event) {
const modal = document.getElementById('feature-modal');
if (event.target == modal) {
closeModal();
}
}