importer feature
This commit is contained in:
@@ -33,6 +33,7 @@
|
||||
{% if let Some(uid) = ctx.user_id %}
|
||||
<a href="/users/{{ uid }}">Profile</a>
|
||||
<a href="/reviews/new">Add Review</a>
|
||||
<a href="/import">Import</a>
|
||||
<a href="/logout">Logout</a>
|
||||
{% else %}
|
||||
<a href="/login">Login</a>
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<h1>Map Columns</h1>
|
||||
{% if let Some(err) = error %}
|
||||
<p class="error">{{ err }}</p>
|
||||
{% endif %}
|
||||
|
||||
<p>Showing up to 5 sample rows. Map each column to a diary field.</p>
|
||||
|
||||
<form method="POST" action="/import/{{ session_id }}/mapping">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
{% for col in columns %}<th>{{ col }}</th>{% endfor %}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for row in sample_rows %}
|
||||
<tr>{% for cell in row %}<td>{{ cell }}</td>{% endfor %}</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
{% for col in columns %}
|
||||
<fieldset>
|
||||
<legend>{{ col }}</legend>
|
||||
<label>Maps to
|
||||
<select name="mapping_{{ loop.index0 }}_field">
|
||||
<option value="">— skip —</option>
|
||||
{% for (val, label) in domain_fields %}
|
||||
<option value="{{ val }}">{{ label }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</label>
|
||||
<label>Rating scale
|
||||
<select name="mapping_{{ loop.index0 }}_scale">
|
||||
<option value="1.0">Same (0–5)</option>
|
||||
<option value="0.5">10-point (/2)</option>
|
||||
<option value="0.05">Percentage (/20)</option>
|
||||
</select>
|
||||
</label>
|
||||
<label>Date format
|
||||
<input type="text" name="mapping_{{ loop.index0 }}_datefmt" placeholder="%Y-%m-%d">
|
||||
</label>
|
||||
<input type="hidden" name="mapping_{{ loop.index0 }}_col" value="{{ col }}">
|
||||
</fieldset>
|
||||
{% endfor %}
|
||||
|
||||
<input type="hidden" name="_csrf" value="{{ ctx.csrf_token }}">
|
||||
<button type="submit">Preview Import</button>
|
||||
</form>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,45 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<h1>Preview Import</h1>
|
||||
|
||||
<form method="POST" action="/import/{{ session_id }}/confirm">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Include?</th>
|
||||
{% for col in columns %}<th>{{ col }}</th>{% endfor %}
|
||||
<th>Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for row in rows %}
|
||||
<tr>
|
||||
<td>
|
||||
{% match row.status %}
|
||||
{% when ImportRowStatus::Invalid with (_e) %}
|
||||
<input type="checkbox" disabled>
|
||||
{% when _ %}
|
||||
<input type="checkbox" name="confirmed" value="{{ row.index }}" checked>
|
||||
{% endmatch %}
|
||||
</td>
|
||||
{% for cell in row.cells %}<td>{{ cell }}</td>{% endfor %}
|
||||
<td>
|
||||
{% match row.status %}
|
||||
{% when ImportRowStatus::Valid %}✓
|
||||
{% when ImportRowStatus::Duplicate %}⚠ duplicate
|
||||
{% when ImportRowStatus::Invalid with (e) %}✗ {{ e }}
|
||||
{% endmatch %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<label>Save this mapping as a profile?
|
||||
<input type="text" name="profile_name" placeholder="e.g. Letterboxd">
|
||||
</label>
|
||||
|
||||
<input type="hidden" name="_csrf" value="{{ ctx.csrf_token }}">
|
||||
<button type="submit">Import Selected</button>
|
||||
</form>
|
||||
{% endblock %}
|
||||
42
crates/adapters/template-askama/templates/import_upload.html
Normal file
42
crates/adapters/template-askama/templates/import_upload.html
Normal file
@@ -0,0 +1,42 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<h1>Import Reviews</h1>
|
||||
{% if let Some(err) = error %}
|
||||
<p class="error">{{ err }}</p>
|
||||
{% endif %}
|
||||
|
||||
{% if !profiles.is_empty() %}
|
||||
<section>
|
||||
<h2>Saved Profiles</h2>
|
||||
<ul>
|
||||
{% for p in profiles %}
|
||||
<li>
|
||||
{{ p.name }}
|
||||
<form method="POST" action="/import/profiles/{{ p.id }}/delete" style="display:inline">
|
||||
<input type="hidden" name="_csrf" value="{{ ctx.csrf_token }}">
|
||||
<button type="submit">Delete</button>
|
||||
</form>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</section>
|
||||
{% endif %}
|
||||
|
||||
<h2>Upload File</h2>
|
||||
<form method="POST" action="/import/upload" enctype="multipart/form-data">
|
||||
<label>
|
||||
File (CSV, TSV, JSON, XLSX)<br>
|
||||
<input type="file" name="file" accept=".csv,.tsv,.json,.xlsx" required>
|
||||
</label>
|
||||
<label>
|
||||
Format<br>
|
||||
<select name="format">
|
||||
<option value="csv">CSV / TSV</option>
|
||||
<option value="json">JSON</option>
|
||||
<option value="xlsx">XLSX</option>
|
||||
</select>
|
||||
</label>
|
||||
<input type="hidden" name="_csrf" value="{{ ctx.csrf_token }}">
|
||||
<button type="submit">Upload</button>
|
||||
</form>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user