LocalScriptsWeb/frontend/templates/index.html

281 lines
13 KiB
HTML

{% extends "base.html" %}
{% block content %}
<div class="min-h-full">
<!-- Navbar -->
<nav class="bg-white shadow-sm">
<div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
<div class="flex h-16 justify-between">
<div class="flex">
<div class="flex flex-shrink-0 items-center">
<h1 class="text-xl font-semibold text-gray-900">Local Scripts Web</h1>
</div>
</div>
<div class="flex items-center gap-4">
<select id="profileSelect"
class="rounded-md border-0 py-1.5 pl-3 pr-10 text-gray-900 ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-indigo-600"
onchange="changeProfile()">
<option value="">Select Profile</option>
</select>
<button onclick="editProfile()"
class="rounded-md bg-white px-2.5 py-1.5 text-sm font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-50">
Edit Profile
</button>
<button onclick="newProfile()"
class="rounded-md bg-indigo-600 px-2.5 py-1.5 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500">
New Profile
</button>
</div>
</div>
</div>
</nav>
<!-- Main content -->
<main>
<div class="mx-auto max-w-7xl py-6 sm:px-6 lg:px-8">
<div class="space-y-6">
<!-- Profile Config Section -->
<div class="bg-white shadow sm:rounded-lg">
<div class="px-4 py-5 sm:p-6">
<h3 class="text-base font-semibold leading-6 text-gray-900">Profile Configuration</h3>
<div id="profileConfig" class="mt-4">
<!-- Profile config will be loaded here -->
</div>
</div>
</div>
<!-- Script Groups Section -->
<div class="bg-white shadow sm:rounded-lg">
<div class="px-4 py-5 sm:p-6">
<div class="flex justify-between items-center">
<h3 class="text-base font-semibold leading-6 text-gray-900">Script Groups</h3>
<button onclick="editGroupSchema()"
class="rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500">
Edit Schema
</button>
</div>
<div class="mt-4 space-y-4">
<select id="groupSelect"
class="w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-inset focus:ring-indigo-600">
<option value="">Select Script Group</option>
</select>
<!-- Group Configuration -->
<div id="groupConfig" class="mt-4">
<!-- Group config will be loaded here -->
</div>
<!-- Work Directory Configuration -->
<div id="workDirConfig" class="mt-4">
<!-- Work dir config will be loaded here -->
</div>
</div>
</div>
</div>
<!-- Scripts Section -->
<div class="bg-white shadow sm:rounded-lg">
<div class="px-4 py-5 sm:p-6">
<h3 class="text-base font-semibold leading-6 text-gray-900">Scripts</h3>
<div id="scriptList" class="mt-4 space-y-4">
<!-- Scripts will be loaded here -->
</div>
</div>
</div>
<!-- Output Section -->
<div class="bg-white shadow sm:rounded-lg">
<div class="px-4 py-5 sm:p-6">
<div class="flex justify-between items-center">
<h3 class="text-base font-semibold leading-6 text-gray-900">Output</h3>
<button onclick="clearOutput()"
class="rounded-md bg-red-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-red-500">
Clear
</button>
</div>
<div id="outputArea"
class="mt-4 h-64 overflow-y-auto p-4 font-mono text-sm bg-gray-50 rounded-md border border-gray-200">
</div>
</div>
</div>
</div>
</div>
</main>
</div>
{% endblock %}
{% block scripts %}
<!-- Load utilities first -->
<script src="{{ url_for('static', filename='js/utils.js') }}"></script>
<!-- Utility Functions -->
<script>
function generateFormField(key, field, value) {
switch (field.type) {
case 'string':
return `
<input type="text" name="${key}"
value="${value || field.default || ''}"
class="${STYLES.editableInput}">
`;
case 'number':
return `
<input type="number" name="${key}"
value="${value || field.default || 0}"
class="${STYLES.editableInput}">
`;
case 'boolean':
return `
<select name="${key}" class="${STYLES.editableInput}">
<option value="true" ${value ? 'selected' : ''}>Yes</option>
<option value="false" ${!value ? 'selected' : ''}>No</option>
</select>
`;
case 'select':
return `
<select name="${key}" class="${STYLES.editableInput}">
${field.options.map(opt => `
<option value="${opt}" ${value === opt ? 'selected' : ''}>
${opt}
</option>
`).join('')}
</select>
`;
case 'directory':
return `
<div class="flex gap-2">
<input type="text" name="${key}"
value="${value || field.default || ''}"
readonly
class="${STYLES.readonlyInput}">
<button type="button"
onclick="selectDirectory('${key}')"
class="${STYLES.buttonSecondary}">
Browse
</button>
</div>
`;
default:
return `
<input type="text" name="${key}"
value="${value || field.default || ''}"
class="${STYLES.editableInput}">
`;
}
}
function generateSchemaField(key = '', field = {}) {
const fieldId = `field_${Math.random().toString(36).substr(2, 9)}`;
return `
<div class="schema-field bg-gray-50 p-4 rounded-md relative" id="${fieldId}">
<button type="button"
onclick="removeSchemaField('${fieldId}')"
class="absolute top-2 right-2 text-red-600 hover:text-red-700">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M6 18L18 6M6 6l12 12"/>
</svg>
</button>
<div class="grid grid-cols-2 gap-4">
<div>
<label class="block text-sm font-medium text-gray-700">Field Name</label>
<input type="text" name="field_name"
value="${key}"
class="${STYLES.editableInput}">
</div>
<div>
<label class="block text-sm font-medium text-gray-700">Type</label>
<select name="field_type"
onchange="handleFieldTypeChange(this)"
class="${STYLES.editableInput}">
<option value="string" ${field.type === 'string' ? 'selected' : ''}>String</option>
<option value="number" ${field.type === 'number' ? 'selected' : ''}>Number</option>
<option value="boolean" ${field.type === 'boolean' ? 'selected' : ''}>Boolean</option>
<option value="select" ${field.type === 'select' ? 'selected' : ''}>Select</option>
<option value="directory" ${field.type === 'directory' ? 'selected' : ''}>Directory</option>
</select>
</div>
<div class="col-span-2">
<label class="block text-sm font-medium text-gray-700">Description</label>
<input type="text" name="field_description"
value="${field.description || ''}"
class="${STYLES.editableInput}">
</div>
<div>
<label class="block text-sm font-medium text-gray-700">Default Value</label>
<input type="text" name="field_default"
value="${field.default || ''}"
class="${STYLES.editableInput}">
</div>
<div>
<label class="block text-sm font-medium text-gray-700">Required</label>
<select name="field_required" class="${STYLES.editableInput}">
<option value="true" ${field.required ? 'selected' : ''}>Yes</option>
<option value="false" ${!field.required ? 'selected' : ''}>No</option>
</select>
</div>
${field.type === 'select' ? `
<div class="col-span-2">
<label class="block text-sm font-medium text-gray-700">Options (comma-separated)</label>
<input type="text" name="field_options"
value="${(field.options || []).join(', ')}"
class="${STYLES.editableInput}">
</div>
` : ''}
</div>
</div>
`;
}
function handleFieldTypeChange(select) {
const fieldDiv = select.closest('.schema-field');
const optionsDiv = fieldDiv.querySelector('[name="field_options"]')?.closest('.col-span-2');
if (select.value === 'select' && !optionsDiv) {
const div = document.createElement('div');
div.className = 'col-span-2';
div.innerHTML = `
<label class="block text-sm font-medium text-gray-700">Options (comma-separated)</label>
<input type="text" name="field_options" class="${STYLES.editableInput}">
`;
fieldDiv.querySelector('.grid').appendChild(div);
} else if (select.value !== 'select' && optionsDiv) {
optionsDiv.remove();
}
}
function addSchemaField() {
const container = document.getElementById('schemaFields');
const field = document.createElement('div');
field.innerHTML = generateSchemaField();
container.appendChild(field.firstElementChild);
}
function removeSchemaField(fieldId) {
document.getElementById(fieldId).remove();
}
async function selectDirectory(inputName) {
try {
const response = await apiRequest('/select-directory');
if (response.path) {
const input = document.querySelector(`input[name="${inputName}"]`);
if (input) {
input.value = response.path;
}
}
} catch (error) {
showError('Error selecting directory');
}
}
</script>
<!-- Initialize app -->
<script>
document.addEventListener('DOMContentLoaded', async () => {
console.log('DOM loaded, initializing...');
await initializeApp();
});
</script>
{% endblock %}