misc updates with tests failing

This commit is contained in:
Mark Gregory
2026-06-29 09:42:00 +01:00
parent 7b40a55b0e
commit eaa8c6ebe3
6 changed files with 132 additions and 183 deletions
@@ -10,7 +10,7 @@
class="space-y-2"
x-data="{
model: @js($model),
value: @entangle($model).defer,
value: @entangle($model),
init() {
this.$nextTick(() => {
this.writeEditorValue(this.value || '');
@@ -21,33 +21,43 @@
return;
}
this.$refs.editor.textContent = value || '';
const nextValue = value || '';
const currentValue = this.$refs.editor.innerText || '';
if (document.activeElement === this.$refs.editor && currentValue !== '' && currentValue !== nextValue) {
return;
}
this.$refs.editor.textContent = nextValue;
},
syncToLivewire(live = false) {
syncToLivewire(live = true) {
const value = this.$refs.editor?.innerText || '';
this.value = value;
this.$refs.input.value = value;
this.$refs.input.dispatchEvent(new Event('input', { bubbles: true }));
this.$wire.set(this.model, this.value, live);
if (this.$refs.input) {
this.$refs.input.value = value;
}
this.$wire.set(this.model, value, live);
},
resetEditor() {
this.value = '';
this.writeEditorValue('');
this.syncToLivewire(false);
this.syncToLivewire(true);
},
runCommand(command) {
this.$refs.editor?.focus();
document.execCommand(command, false, null);
this.syncToLivewire(false);
this.syncToLivewire(true);
},
wrapBlock(tagName) {
this.$refs.editor?.focus();
document.execCommand('formatBlock', false, tagName);
this.syncToLivewire(false);
this.syncToLivewire(true);
},
}"
x-on:helpdesk-editor-sync.window="if (! $event.detail?.model || $event.detail.model === @js($model)) syncToLivewire(false)"
x-on:helpdesk-editor-sync.window="if (! $event.detail?.model || $event.detail.model === @js($model)) syncToLivewire($event.detail?.live ?? true)"
x-on:helpdesk-editor-reset.window="if (! $event.detail?.model || $event.detail.model === @js($model)) resetEditor()"
>
<label for="{{ $model }}-editor" class="block text-sm font-semibold text-zinc-200">
@@ -108,7 +118,9 @@
data-helpdesk-sync-target="{{ $model }}"
data-helpdesk-editor-model="{{ $model }}"
@if ($editorDusk) data-dusk="{{ $editorDusk }}" dusk="{{ $editorDusk }}" @endif
x-on:blur="syncToLivewire(false)"
x-on:input.debounce.350ms="syncToLivewire(true)"
x-on:paste.debounce.350ms="syncToLivewire(true)"
x-on:blur="syncToLivewire(true)"
class="helpdesk-rich-editor block min-h-[14rem] w-full overflow-y-auto whitespace-pre-wrap break-words border-0 bg-zinc-950 px-5 py-4 text-base leading-7 text-zinc-100 outline-none transition placeholder:text-zinc-500 empty:before:pointer-events-none empty:before:text-zinc-500 empty:before:content-[attr(data-placeholder)] focus:ring-2 focus:ring-blue-500"
></div>
@@ -129,6 +141,6 @@
</div>
<p class="text-xs font-semibold text-zinc-400">
Browser spellcheck stays active in the native editable area. Formatting is synchronised only on blur and submit to avoid Livewire keypress regressions.
Browser spellcheck stays active in the native editable area. Formatting is synchronised before uploads and submit so Livewire does not lose unsaved editor text during attachment refreshes.
</p>
</div>
@@ -767,14 +767,14 @@
@endif
}
let wmsSessionToastsShown = false;
window.wmsSessionToastsShown = window.wmsSessionToastsShown || false;
function showSessionToastsOnce() {
if (wmsSessionToastsShown) {
if (window.wmsSessionToastsShown) {
return;
}
wmsSessionToastsShown = true;
window.wmsSessionToastsShown = true;
showSessionToasts();
}
@@ -6,7 +6,6 @@
->implode(',');
@endphp
<div class="hd-helpdesk-surface space-y-6" dusk="helpdesk-ticket-create">
@vite(['resources/css/app.css', 'resources/js/app.js'])
@include('helpdesk::partials.page-header', [
'eyebrow' => 'Helpdesk',
'title' => 'Create ticket',
@@ -16,39 +15,18 @@
<form
wire:submit.prevent="save"
x-data="{ helpdeskAttachmentsUploading: false }"
x-on:livewire-upload-start="helpdeskAttachmentsUploading = true"
x-on:livewire-upload-finish="helpdeskAttachmentsUploading = false"
x-on:livewire-upload-error="helpdeskAttachmentsUploading = false"
x-on:livewire-upload-cancel="helpdeskAttachmentsUploading = false"
x-on:submit.capture="
const editor = document.querySelector('[data-helpdesk-sync-target=&quot;body&quot;], [data-helpdesk-editor-model=&quot;body&quot;]');
const target = document.querySelector('textarea[wire\:model\.defer=&quot;body&quot;], textarea[name=&quot;body&quot;], #body');
if (helpdeskAttachmentsUploading) {
if (editor && target) {
target.value = editor.innerHTML?.trim?.() || editor.value?.trim?.() || '';
target.dispatchEvent(new Event('input', { bubbles: true }));
target.dispatchEvent(new Event('change', { bubbles: true }));
}
$event.preventDefault();
return;
}
const editor = document.querySelector('[data-helpdesk-sync-target=&quot;body&quot;], [data-helpdesk-editor-model=&quot;body&quot;]');
const target = document.querySelector('textarea[wire\\:model\\.defer=&quot;body&quot;], textarea[name=&quot;body&quot;], #body');
if (editor && target) {
target.value = editor.innerHTML?.trim?.() || editor.value?.trim?.() || '';
target.dispatchEvent(new Event('input', { bubbles: true }));
target.dispatchEvent(new Event('change', { bubbles: true }));
}
$dispatch('helpdesk-editor-sync', { model: 'body' });
"
enctype="multipart/form-data"
$dispatch('helpdesk-editor-sync', { model: 'body' });
"
class="helpdesk-ticket-form space-y-6"
>
<div class="overflow-hidden rounded-2xl border border-zinc-700 bg-zinc-900 shadow-sm">
@@ -278,16 +256,16 @@
</div>
<div class="lg:col-span-3 xl:col-span-6">
<div class="rounded-2xl border border-zinc-700 bg-zinc-950/70 p-4"
x-data="helpdeskAttachmentDropzone('attachments')"
x-on:dragover.prevent="dragging = true"
x-on:dragleave.prevent="dragging = false"
x-on:drop.prevent="dropFiles($event)"
<div
wire:key="ticket-create-attachments-uploader"
class="rounded-2xl border border-zinc-700 bg-zinc-950/70 p-4"
x-data="{ uploading: false, progress: 0 }"
x-on:livewire-upload-start="uploading = true; progress = 0"
x-on:livewire-upload-progress="progress = $event.detail.progress"
x-on:livewire-upload-finish="uploading = false; progress = 100"
x-on:livewire-upload-error="uploading = false"
x-bind:class="dragging ? 'border-blue-400 bg-blue-500/10' : ''">
x-on:livewire-upload-cancel="uploading = false"
>
<div class="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
<div>
<label class="block text-sm font-semibold text-zinc-200" for="attachments">
@@ -295,7 +273,7 @@
</label>
<p class="mt-1 text-sm text-zinc-500">
Drag and drop screenshots, PDFs, logs, source files or documents. PHP, JS, RPG/RPGLE, CLLE and other source files are accepted.
Files are uploaded to Livewire temporary storage first. They are attached permanently only after the ticket is created.
</p>
</div>
@@ -307,27 +285,35 @@
</div>
<label for="attachments"
class="mt-4 flex cursor-pointer flex-col items-center justify-center rounded-2xl border border-dashed border-zinc-700 bg-zinc-900/70 px-4 py-8 text-center transition hover:border-blue-500 hover:bg-zinc-900"
x-bind:class="dragging ? 'border-blue-400 bg-blue-500/10' : ''">
class="mt-4 flex cursor-pointer flex-col items-center justify-center rounded-2xl border border-dashed border-zinc-700 bg-zinc-900/70 px-4 py-8 text-center transition hover:border-blue-500 hover:bg-zinc-900">
<i class="fa-solid fa-cloud-arrow-up text-2xl text-blue-300" aria-hidden="true"></i>
<span class="mt-3 text-sm font-bold text-zinc-100">Drop files here or click to browse</span>
<span class="mt-3 text-sm font-bold text-zinc-100">Click to choose files</span>
<span class="mt-1 text-xs text-zinc-500">Maximum {{ (int) config('helpdesk.max_upload_kb', 10240) }} KB per file.</span>
</label>
<input id="attachments" type="file" wire:model="attachments" multiple accept="{{ $helpdeskAttachmentAccept }}" class="sr-only"
x-ref="input" x-on:change="refreshSelectedFiles()">
<input
id="attachments"
type="file"
wire:model="attachments"
multiple
accept="{{ $helpdeskAttachmentAccept }}"
class="sr-only"
wire:key="ticket-create-attachments-input"
dusk="ticket-create-attachments-input"
data-dusk="ticket-create-attachments-input"
/>
<template x-if="selectedFiles.length > 0">
<div class="mt-4 grid gap-2 sm:grid-cols-2">
<template x-for="file in selectedFiles" :key="file.name + file.size">
<div class="flex items-center gap-3 rounded-xl border border-zinc-700 bg-zinc-900 px-3 py-2 text-xs text-zinc-300">
@if (count($attachments) > 0)
<div class="mt-4 grid gap-2 sm:grid-cols-2" dusk="ticket-create-selected-attachments">
@foreach ($attachments as $attachment)
<div class="flex items-center gap-3 rounded-xl border border-zinc-700 bg-zinc-900 px-3 py-2 text-xs text-zinc-300" wire:key="ticket-create-selected-attachment-{{ $loop->index }}">
<i class="fa-regular fa-file-lines text-blue-300" aria-hidden="true"></i>
<span class="min-w-0 flex-1 truncate" x-text="file.name"></span>
<span class="shrink-0 text-zinc-500" x-text="formatSize(file.size)"></span>
<span class="min-w-0 flex-1 truncate">{{ $attachment->getClientOriginalName() }}</span>
<span class="shrink-0 text-zinc-500">{{ number_format($attachment->getSize() / 1024, 1) }} KB</span>
</div>
</template>
@endforeach
</div>
</template>
@endif
<div x-show="uploading" x-cloak
class="mt-4 rounded-xl border border-blue-500/30 bg-blue-500/10 px-4 py-3 text-sm font-medium text-blue-200">
@@ -369,7 +355,7 @@
<button type="submit"
class="inline-flex min-h-10 items-center justify-center rounded-lg bg-emerald-600 px-4 py-2 text-xs font-black text-white shadow-sm transition hover:bg-emerald-700 focus:outline-none focus:ring-2 focus:ring-emerald-400/70 disabled:cursor-not-allowed disabled:opacity-50"
data-dusk="ticket-create-submit" dusk="ticket-create-submit" wire:loading.attr="disabled" wire:target="save,attachments" x-bind:disabled="helpdeskAttachmentsUploading" wire:dirty.class="ring-2 ring-amber-400/40">
data-dusk="ticket-create-submit" dusk="ticket-create-submit" wire:loading.attr="disabled" wire:target="save,attachments" wire:dirty.class="ring-2 ring-amber-400/40">
<i class="fa-regular fa-floppy-disk mr-2" aria-hidden="true"></i>
<span wire:loading.remove wire:target="save,attachments">Create ticket</span>
<span wire:loading wire:target="attachments">Uploading...</span>
@@ -378,71 +364,4 @@
</div>
</div>
</form>
<script>
(() => {
window.helpdeskAttachmentDropzone = window.helpdeskAttachmentDropzone || function (inputId) {
return {
dragging: false,
uploading: false,
progress: 0,
selectedFiles: [],
dropFiles(event) {
this.dragging = false;
const input = this.$refs.input || document.getElementById(inputId);
if (!input || !event.dataTransfer?.files?.length) {
return;
}
input.files = event.dataTransfer.files;
input.dispatchEvent(new Event('change', { bubbles: true }));
this.refreshSelectedFiles();
},
refreshSelectedFiles() {
const input = this.$refs.input || document.getElementById(inputId);
this.selectedFiles = input?.files ? Array.from(input.files) : [];
},
formatSize(bytes) {
if (!bytes) {
return '0 B';
}
const units = ['B', 'KB', 'MB', 'GB'];
const index = Math.min(Math.floor(Math.log(bytes) / Math.log(1024)), units.length - 1);
return `${(bytes / Math.pow(1024, index)).toFixed(index === 0 ? 0 : 1)} ${units[index]}`;
},
};
};
const resetTicketCreateFiles = () => {
document.querySelectorAll('.helpdesk-ticket-form #attachments').forEach((input) => {
input.value = '';
input.dispatchEvent(new Event('change', { bubbles: true }));
});
};
const appendPastedFiles = (event) => {
const files = Array.from(event.detail?.files || []);
const input = document.querySelector('.helpdesk-ticket-form #attachments');
if (!input || files.length === 0) {
return;
}
const transfer = new DataTransfer();
Array.from(input.files || []).forEach((file) => transfer.items.add(file));
files.forEach((file) => transfer.items.add(file));
input.files = transfer.files;
input.dispatchEvent(new Event('change', { bubbles: true }));
};
document.addEventListener('helpdesk-form-cleared', resetTicketCreateFiles);
document.addEventListener('helpdesk-editor-files-pasted', appendPastedFiles);
if (window.Livewire?.on) {
window.Livewire.on('helpdesk-form-cleared', resetTicketCreateFiles);
}
})();
</script>
</div>