Result box: color-code by status + friendly error messages from error codes (#105)
- Backend create/can validation paths emit machine-readable error codes (slug_taken, slug_invalid, content_empty, content_too_large, expiry_invalid, rate_limited, ...) alongside the human message - new.html JS maps codes to plain-language guidance with generic fallback - Result card colored via --ok/--err/--warn left border (result-ok/err/warn) - docs/API.md error section documents the code field - Tests assert the code on every validation path
This commit is contained in:
@@ -171,10 +171,37 @@ $('can-add').addEventListener('click', addCanItem);
|
||||
|
||||
let guessed = ''; // last auto-detected language, '' = user override
|
||||
|
||||
function showResult(html, isError) {
|
||||
// #105: map backend machine-readable error codes to plain-language guidance.
|
||||
// Unknown codes fall back to a generic message; the technical detail stays
|
||||
// in the API response for API consumers.
|
||||
const ERROR_MESSAGES = {
|
||||
slug_taken: 'That Custom URL is already taken. Try another.',
|
||||
slug_reserved: 'That Custom URL is reserved. Try another.',
|
||||
slug_invalid: 'Please keep the Custom URL under 64 characters, using only letters, numbers, dashes, or underscores.',
|
||||
content_empty: 'Write or paste something first.',
|
||||
content_too_large: 'This paste is too large. The limit is 5 MB.',
|
||||
expiry_invalid: 'Please pick an expiry between 1 minute and 1 year.',
|
||||
rate_limited: 'Too many tries. Wait a minute and try again.',
|
||||
};
|
||||
const GENERIC_ERROR = 'Something went wrong. Please try again.';
|
||||
|
||||
function friendlyError(data) {
|
||||
return ERROR_MESSAGES[data && data.code] || GENERIC_ERROR;
|
||||
}
|
||||
|
||||
// #105: color the result box by outcome — success (ok), error (err),
|
||||
// warning (warn) — with a colored left border (CSS .result-ok/.result-err).
|
||||
function setResultKind(kind) {
|
||||
const card = $('result-card');
|
||||
card.classList.remove('result-ok', 'result-err', 'result-warn');
|
||||
if (kind) card.classList.add('result-' + kind);
|
||||
}
|
||||
|
||||
function showResult(html, kind) {
|
||||
$('result').innerHTML = html;
|
||||
$('result').dataset.token = isError ? '' : ($('result').dataset.token || '');
|
||||
$('result').dataset.token = kind === 'ok' ? ($('result').dataset.token || '') : ($('result').dataset.token || '');
|
||||
$('result-card').style.display = 'block';
|
||||
setResultKind(kind === 'ok' ? 'ok' : (kind === 'warn' ? 'warn' : 'err'));
|
||||
}
|
||||
function defaultFilename(lang) {
|
||||
const names = {
|
||||
@@ -249,12 +276,12 @@ async function create() {
|
||||
});
|
||||
const data = await res.json();
|
||||
if (!res.ok) {
|
||||
showResult('Error: ' + (data.error || res.status), true);
|
||||
showResult(friendlyError(data), 'err');
|
||||
toast('Create failed', 'error');
|
||||
return;
|
||||
}
|
||||
const url = location.origin + '/' + (data.custom_slug || data.id);
|
||||
showResult('<a href="' + url + '">' + url + '</a> <button class="btn btn-icon" id="result-copy" title="Copy URL" type="button">⧉</button>', false);
|
||||
showResult('<a href="' + url + '">' + url + '</a> <button class="btn btn-icon" id="result-copy" title="Copy URL" type="button">⧉</button>', 'ok');
|
||||
$('result').dataset.token = data.deletion_token || '';
|
||||
const copyBtn = document.getElementById('result-copy');
|
||||
copyBtn.addEventListener('click', () => {
|
||||
@@ -312,12 +339,12 @@ async function createCan() {
|
||||
const res = await fetch('/api/pastes/can', {method: 'POST', body: fd});
|
||||
const data = await res.json();
|
||||
if (!res.ok) {
|
||||
showResult('Error: ' + (data.error || res.status), true);
|
||||
showResult(friendlyError(data), 'err');
|
||||
toast('Can create failed', 'error');
|
||||
return;
|
||||
}
|
||||
const url = location.origin + data.url;
|
||||
showResult('<a href="' + url + '">' + url + '</a> <button class="btn btn-icon" id="result-copy" title="Copy URL" type="button">⧉</button>', false);
|
||||
showResult('<a href="' + url + '">' + url + '</a> <button class="btn btn-icon" id="result-copy" title="Copy URL" type="button">⧉</button>', 'ok');
|
||||
const copyBtn = document.getElementById('result-copy');
|
||||
copyBtn.addEventListener('click', () => {
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user