File indexing completed on 2026-06-13 08:42:18
0001 {% extends 'base.html' %}
0002
0003 {% block title %}Create Dataset - PCS{% endblock %}
0004
0005 {% block content %}
0006 {% csrf_token %}
0007 <div class="container-fluid mt-4">
0008 <nav aria-label="breadcrumb">
0009 <ol class="breadcrumb">
0010 <li class="breadcrumb-item"><a href="{% url 'pcs:pcs_hub' %}">PCS</a></li>
0011 <li class="breadcrumb-item"><a href="{% url 'pcs:datasets_compose' %}">Datasets</a></li>
0012 <li class="breadcrumb-item active">Create</li>
0013 </ol>
0014 </nav>
0015
0016 <h2>Create Dataset</h2>
0017 <p>Compose a dataset from locked tags. Block 1 is created automatically. Only locked tags appear in the dropdowns.</p>
0018
0019 <div class="mt-3" style="max-width: 700px;" id="dataset-form">
0020
0021 <div class="row mb-3">
0022 <div class="col-md-4">
0023 <label for="id_scope" class="form-label"><strong>Scope</strong></label>
0024 <input type="text" name="scope" id="id_scope" class="form-control" value="{{ form.scope.value|default:"group.EIC" }}">
0025 </div>
0026 <div class="col-md-4">
0027 <label for="id_detector_version" class="form-label"><strong>Detector Version</strong></label>
0028 <input type="text" name="detector_version" id="id_detector_version" class="form-control" value="{{ form.detector_version.value|default:"" }}" placeholder="e.g. 26.02.0">
0029 </div>
0030 <div class="col-md-4">
0031 <label for="id_detector_config" class="form-label"><strong>Detector Config</strong></label>
0032 <input type="text" name="detector_config" id="id_detector_config" class="form-control" value="{{ form.detector_config.value|default:"" }}" placeholder="e.g. epic_craterlake">
0033 </div>
0034 </div>
0035
0036 <div class="row mb-3">
0037 <div class="col-md-6">
0038 <label for="id_physics_tag" class="form-label"><strong>Physics Tag</strong></label>
0039 <select name="physics_tag" id="id_physics_tag" class="form-select" onchange="updatePreview()">
0040 <option value="">Select physics tag</option>
0041 {% for tag in form.physics_tag.field.queryset %}
0042 <option value="{{ tag.pk }}" data-label="{{ tag.tag_label }}" {% if form.physics_tag.value|stringformat:"s" == tag.pk|stringformat:"s" %}selected{% endif %}>{{ tag.tag_label }} — {{ tag.description|truncatewords:8 }}</option>
0043 {% endfor %}
0044 </select>
0045 </div>
0046 <div class="col-md-6">
0047 <label for="id_evgen_tag" class="form-label"><strong>EvGen Tag</strong></label>
0048 <select name="evgen_tag" id="id_evgen_tag" class="form-select" onchange="updatePreview()">
0049 <option value="">Select evgen tag</option>
0050 {% for tag in form.evgen_tag.field.queryset %}
0051 <option value="{{ tag.pk }}" data-label="{{ tag.tag_label }}" {% if form.evgen_tag.value|stringformat:"s" == tag.pk|stringformat:"s" %}selected{% endif %}>{{ tag.tag_label }} — {{ tag.description|truncatewords:8 }}</option>
0052 {% endfor %}
0053 </select>
0054 </div>
0055 </div>
0056
0057 <div class="row mb-3">
0058 <div class="col-md-6">
0059 <label for="id_simu_tag" class="form-label"><strong>Simu Tag</strong></label>
0060 <select name="simu_tag" id="id_simu_tag" class="form-select" onchange="updatePreview()">
0061 <option value="">Select simu tag</option>
0062 {% for tag in form.simu_tag.field.queryset %}
0063 <option value="{{ tag.pk }}" data-label="{{ tag.tag_label }}" {% if form.simu_tag.value|stringformat:"s" == tag.pk|stringformat:"s" %}selected{% endif %}>{{ tag.tag_label }} — {{ tag.description|truncatewords:8 }}</option>
0064 {% endfor %}
0065 </select>
0066 </div>
0067 <div class="col-md-6">
0068 <label for="id_reco_tag" class="form-label"><strong>Reco Tag</strong></label>
0069 <select name="reco_tag" id="id_reco_tag" class="form-select" onchange="updatePreview()">
0070 <option value="">Select reco tag</option>
0071 {% for tag in form.reco_tag.field.queryset %}
0072 <option value="{{ tag.pk }}" data-label="{{ tag.tag_label }}" {% if form.reco_tag.value|stringformat:"s" == tag.pk|stringformat:"s" %}selected{% endif %}>{{ tag.tag_label }} — {{ tag.description|truncatewords:8 }}</option>
0073 {% endfor %}
0074 </select>
0075 </div>
0076 </div>
0077
0078 <div class="mb-3">
0079 <label class="form-label"><strong>Dataset Name Preview</strong></label>
0080 <div id="name-preview" class="form-control bg-light" style="font-family: monospace; min-height: 38px;"></div>
0081 <small class="text-muted">Max 255 characters. <span id="char-count"></span></small>
0082 </div>
0083
0084 <div class="mb-3">
0085 <label for="id_description" class="form-label"><strong>Description</strong></label>
0086 <textarea name="description" id="id_description" class="form-control" rows="3">{{ form.description.value|default:"" }}</textarea>
0087 </div>
0088
0089 <div class="form-check mb-3">
0090 <input class="form-check-input" type="checkbox" id="id_external_evgen" onchange="toggleExternalFields()">
0091 <label class="form-check-label" for="id_external_evgen"><strong>External EVGEN input</strong></label>
0092 </div>
0093
0094 <div id="external-fields" style="display:none;">
0095 <div class="row mb-3">
0096 <div class="col-md-4">
0097 <label for="id_source_kind" class="form-label"><strong>Source Kind</strong></label>
0098 <select id="id_source_kind" class="form-select">
0099 <option value="csv_manifest">CSV manifest</option>
0100 <option value="path">Path</option>
0101 <option value="url">URL</option>
0102 <option value="rucio_did">Rucio DID</option>
0103 <option value="file_list">File list</option>
0104 </select>
0105 </div>
0106 <div class="col-md-8">
0107 <label for="id_source_location" class="form-label"><strong>Source Location</strong></label>
0108 <input type="text" id="id_source_location" class="form-control" placeholder="CSV path, URL, DID, or file-list location">
0109 </div>
0110 </div>
0111 </div>
0112
0113 <div class="alert alert-danger" id="form-errors" style="display:none;"></div>
0114
0115 <button type="button" class="btn btn-primary btn-sm" onclick="createDataset()">Create Dataset</button>
0116 <a href="{% url 'pcs:datasets_compose' %}" class="btn btn-secondary btn-sm">Cancel</a>
0117 </div>
0118 </div>
0119
0120 <script>
0121 function getSelectedLabel(selectId) {
0122 const sel = document.getElementById(selectId);
0123 const opt = sel.options[sel.selectedIndex];
0124 return opt && opt.dataset.label ? opt.dataset.label : '?';
0125 }
0126
0127 function updatePreview() {
0128 const scope = document.getElementById('id_scope').value || '?';
0129 const version = document.getElementById('id_detector_version').value || '?';
0130 const config = document.getElementById('id_detector_config').value || '?';
0131 const p = getSelectedLabel('id_physics_tag');
0132 const e = getSelectedLabel('id_evgen_tag');
0133 const s = getSelectedLabel('id_simu_tag');
0134 const r = getSelectedLabel('id_reco_tag');
0135 const name = `${scope}.${version}.${config}.${p}.${e}.${s}.${r}`;
0136 document.getElementById('name-preview').textContent = name;
0137 const len = name.length;
0138 const counter = document.getElementById('char-count');
0139 counter.textContent = `${len}/255`;
0140 counter.style.color = len > 255 ? 'red' : 'inherit';
0141 }
0142
0143 document.getElementById('id_scope').addEventListener('input', updatePreview);
0144 document.getElementById('id_detector_version').addEventListener('input', updatePreview);
0145 document.getElementById('id_detector_config').addEventListener('input', updatePreview);
0146 updatePreview();
0147
0148 function toggleExternalFields() {
0149 const visible = document.getElementById('id_external_evgen').checked;
0150 document.getElementById('external-fields').style.display = visible ? 'block' : 'none';
0151 }
0152
0153 function buildMetadata() {
0154 if (!document.getElementById('id_external_evgen').checked) return null;
0155 return {
0156 stage: 'evgen',
0157 source: {
0158 kind: document.getElementById('id_source_kind').value,
0159 location: document.getElementById('id_source_location').value,
0160 },
0161 };
0162 }
0163
0164 async function createDataset() {
0165 const csrfToken = document.querySelector('[name=csrfmiddlewaretoken]')?.value || '';
0166 const headers = {'Content-Type': 'application/json'};
0167 if (csrfToken) headers['X-CSRFToken'] = csrfToken;
0168 const payload = {
0169 scope: document.getElementById('id_scope').value,
0170 detector_version: document.getElementById('id_detector_version').value,
0171 detector_config: document.getElementById('id_detector_config').value,
0172 physics_tag: document.getElementById('id_physics_tag').value,
0173 evgen_tag: document.getElementById('id_evgen_tag').value,
0174 simu_tag: document.getElementById('id_simu_tag').value,
0175 reco_tag: document.getElementById('id_reco_tag').value,
0176 description: document.getElementById('id_description').value,
0177 };
0178 const metadata = buildMetadata();
0179 if (metadata) payload.metadata = metadata;
0180 const errDiv = document.getElementById('form-errors');
0181 errDiv.style.display = 'none';
0182 const resp = await fetch('/swf-monitor/pcs/api/datasets/', {
0183 method: 'POST', headers, body: JSON.stringify(payload)
0184 });
0185 if (resp.ok) {
0186 const data = await resp.json();
0187 window.location.href = `{% url 'pcs:datasets_compose' %}?selected=${encodeURIComponent(data.dataset_name || data.name || data.id)}`;
0188 } else {
0189 const errors = await resp.json();
0190 let html = '';
0191 for (const [field, msgs] of Object.entries(errors)) {
0192 html += `<p><strong>${field}:</strong> ${Array.isArray(msgs) ? msgs.join(', ') : msgs}</p>`;
0193 }
0194 errDiv.innerHTML = html;
0195 errDiv.style.display = 'block';
0196 }
0197 }
0198 </script>
0199 {% endblock %}