enabled uploading images from clipboard on ticket edit.

This commit is contained in:
tp_dhu 2025-03-24 11:14:13 +00:00
parent 2a3465fff8
commit 8c8de5ec34
5 changed files with 136 additions and 1 deletions

View File

@ -145,4 +145,41 @@ class AttachmentController {
// remove DB row
$db->exec('DELETE FROM attachments WHERE id =?', [$attachment_id]);
}
// view attachment
public function view($f3){
$this->check_access($f3);
$attachment_id = (int) $f3->get('PARAMS.id');
$db = $f3->get('DB');
$rows = $db->exec('SELECt * FROM attachments WHERE id = ?', [$attachment_id]);
if(!$rows){
$f3->error(404, "File not found");
return;
}
$attachment = $rows[0];
$file_path = $attachment['path'];
$file_name = $attachment['file_name'];
if(!file_exists($file_path)){
$f3->error(404, "File not found");
return;
}
// detect mime type
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mime_type = finfo_file($finfo, $file_path);
finfo_close($finfo);
header('Content-Type: ' . $mime_type);
header('Content-Disposition: inline; filename="' . basename($file_name) . '"');
header('Content-Length: ' . filesize($file_path));
flush();
readfile($file_path);
exit;
}
}

89
ui/parts/clipboard.html Normal file
View File

@ -0,0 +1,89 @@
<div class="block">
<style>
#upload-area {
height: 250px;
border: 2px dashed #aaa;
display: flex;
align-items: center;
margin-top: 10px;
color: #555;
font-family: sans-serif;
text-align: center;
}
#upload-area.hover {
background-color: #f0f0f0;
border-color: #444;
}
#preview {
max-width:100%;
margin-top: 10px;
}
</style>
<div id="upload-area" contenteditable="true">
Paste or drag an image here
</div>
<img id="preview" alt="image preview" hidden>
<p id="status"></p>
<script>
const area = document.getElementById('upload-area');
const preview = document.getElementById('preview');
const status = document.getElementById('status');
async function uploadImage(file){
const reader = new FileReader();
reader.onload = () => {
preview.src = reader.result;
preview.hidden = false;
};
reader.readAsDataURL(file);
const formData = new FormData();
formData.append('attachment', file);
try {
const res = await fetch('/ticket/{{@ticket->id}}/attachments/upload', {
method: 'POST',
body: formData
});
const text = await res.text();
status.textContent = text;
} catch (e) {
status.textContent = 'upload failed.'
}
}
// paste
area.addEventListener('paste', (e) => {
for(let item of e.clipboardData.items){
if(item.type.startsWith('image/')){
uploadImage(item.getAsFile());
}
}
});
// drag and drop
area.addEventListener('dragover', (e) => {
e.preventDefault();
area.classList.add('hover');
});
area.addEventListener('dragLeave', ()=> {
area.classList.remove('hover');
});
area.addEventListener('drop', (e) => {
e.preventDefault();
area.classList.remove('hover');
const files = e.dataTransfer.files;
for(let file of files){
if(file.type.startsWith('image/')){
uploadImage(file);
}
}
});
</script>
</div>

View File

@ -28,6 +28,12 @@
</repeat>
</tbody>
</table>
<hr>
<div>
<repeat group="{{ @attachments }}" value="{{ @attach }}">
<img src="/attachment/{{@attach.id}}/view">
</repeat>
</div>
</check>
</check>
<div class="block">

View File

@ -4,9 +4,10 @@
<form action="/ticket/create" method="POST">
<bulma type="H_FIELD_INPUT" label="Title:" name="title" value=""></bulma>
<bulma type="H_FIELD_INPUT" label="Created At:" name="created_at" value=""></bulma>
<bulma type="H_FIELD_TEXTAREA" label="Description:" name="description" value=""></bulma>
<!-- TODO implement priority and status -->
<bulma type="H_FIELD_SELECT" label="Priority:" name="priority" options="['Low', 'Medium', 'High']" selected="Medium"></bulma>
<bulma type="H_FIELD_SELECT" label="Status:" name="status" options="['New', 'In Progress', 'On Hold', 'Completed']" selected="New"></bulma>

View File

@ -3,12 +3,14 @@
<form action="/ticket/{{ @PARAMS.id }}/update" method="POST">
<bulma type="H_FIELD_INPUT" label="Title:" name="title" value="{{@ticket.title}}"></bulma>
<bulma type="H_FIELD_INPUT" label="Created At:" name="created_at" value="{{@ticket.created_at}}"></bulma>
<bulma type="H_FIELD_TEXTAREA" label="Description:" name="description" value="{{@ticket.description}}"></bulma>
<bulma type="H_FIELD_SELECT" label="Priority:" name="priority" options="['Low', 'Medium', 'High']" selected="{{@ticket.priority}}"></bulma>
<bulma type="H_FIELD_SELECT" label="Status:" name="status" options="['New', 'In Progress', 'On Hold', 'Completed']" selected="{{@ticket.status}}"></bulma>
<include href="/ui/parts/clipboard.html"></include>
<div class="block">
<h3 class="title is-5">Custom Fields</h3>