updated backup script to include vendor directory added git suggestion and also spell check on comments

This commit is contained in:
Mark Gregory
2026-06-25 16:47:17 +01:00
parent 1af5f0f338
commit b5530a4cdf
6 changed files with 246 additions and 14 deletions
@@ -451,7 +451,7 @@
<label for="ticket-comment-subject"
class="mb-2 block text-xs font-bold text-zinc-700 dark:text-zinc-200">Subject</label>
<input id="ticket-comment-subject" name="subject" value="{{ old('subject') }}"
placeholder="Response subject"
placeholder="Response subject" spellcheck="true" lang="en-GB" autocorrect="on" autocomplete="on" autocapitalize="sentences" inputmode="text"
class="block min-h-10 w-full rounded-lg border border-zinc-300 bg-white px-3 py-2 text-sm font-semibold text-zinc-900 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:border-zinc-700 dark:bg-zinc-950 dark:text-zinc-100"
data-helpdesk-comment-subject>
</div>
@@ -481,7 +481,7 @@
<div id="ticket-comment-body-editor" dusk="comment-body" data-dusk="comment-body"
data-helpdesk-rich-editor data-helpdesk-sync-target="ticket-comment-body"
contenteditable="true" spellcheck="true" lang="en-GB" autocorrect="on" autocomplete="on"
contenteditable="true" role="textbox" aria-multiline="true" spellcheck="true" lang="en-GB" autocorrect="on" autocomplete="on" autocapitalize="sentences" inputmode="text"
class="prose prose-sm min-h-[12rem] max-w-none bg-white p-4 text-sm leading-6 text-zinc-900 outline-none dark:prose-invert dark:bg-zinc-950 dark:text-zinc-100"
data-placeholder="Write a public reply or internal note. Right-click or Ctrl-click underlined words for spelling suggestions.">{!! $oldCommentBody !!}</div>
@@ -534,7 +534,7 @@
@if ($canSeeInternalNotes)
<div class="grid gap-3 sm:grid-cols-2">
<label class="flex cursor-pointer items-start gap-3 rounded-xl border border-emerald-300 bg-emerald-50 p-3 text-emerald-950 shadow-sm transition hover:bg-emerald-100 dark:border-emerald-900 dark:bg-emerald-950/60 dark:text-emerald-100">
<label class="flex cursor-pointer items-start gap-3 rounded-xl border border-emerald-300 bg-emerald-50 p-3 text-emerald-950 shadow-sm transition hover:border-emerald-400 hover:bg-emerald-100/80 focus-within:border-emerald-500 focus-within:bg-emerald-100/80 focus-within:ring-2 focus-within:ring-emerald-400/30 active:bg-emerald-100/80 dark:border-emerald-900 dark:bg-emerald-950/60 dark:text-emerald-100 dark:hover:border-emerald-700 dark:hover:bg-emerald-900/50 dark:focus-within:bg-emerald-900/50">
<input type="radio" name="internal" value="0" @checked(! old('internal')) class="mt-1 border-emerald-400 text-emerald-600 focus:ring-emerald-500">
<span>
<span class="block text-sm font-extrabold">Public reply</span>
@@ -542,7 +542,7 @@
</span>
</label>
<label class="flex cursor-pointer items-start gap-3 rounded-xl border border-purple-300 bg-purple-50 p-3 text-purple-950 shadow-sm transition hover:bg-purple-100 dark:border-purple-900 dark:bg-purple-950/60 dark:text-purple-100">
<label class="flex cursor-pointer items-start gap-3 rounded-xl border border-purple-300 bg-purple-50 p-3 text-purple-950 shadow-sm transition hover:border-purple-400 hover:bg-purple-100/80 focus-within:border-purple-500 focus-within:bg-purple-100/80 focus-within:ring-2 focus-within:ring-purple-400/30 active:bg-purple-100/80 dark:border-purple-900 dark:bg-purple-950/60 dark:text-purple-100 dark:hover:border-purple-700 dark:hover:bg-purple-900/50 dark:focus-within:bg-purple-900/50">
<input type="radio" name="internal" value="1" @checked((bool) old('internal')) class="mt-1 border-purple-400 text-purple-600 focus:ring-purple-500">
<span>
<span class="block text-sm font-extrabold">Internal note</span>
@@ -643,6 +643,13 @@
return;
}
const copyBranchButton = event.target.closest('[data-helpdesk-copy-branch-command]');
if (copyBranchButton) {
copyHelpdeskBranchCommand(copyBranchButton);
return;
}
const replyButton = event.target.closest('[data-helpdesk-reply-toggle]');
if (!replyButton) {
@@ -695,6 +702,12 @@
});
}
const branchSuffix = event.target.closest('[data-helpdesk-branch-suffix]');
if (branchSuffix) {
updateHelpdeskBranchCommand(branchSuffix.closest('[data-helpdesk-branch-command]'));
}
const fileInput = event.target.closest('[data-helpdesk-file-input]');
if (fileInput) {
@@ -712,6 +725,66 @@
}
});
function updateHelpdeskBranchCommand(container) {
if (!container) {
return '';
}
const prefix = container.dataset.helpdeskBranchPrefix || '';
const input = container.querySelector('[data-helpdesk-branch-suffix]');
const output = container.querySelector('[data-helpdesk-branch-command-output]');
const suffix = normaliseHelpdeskBranchSuffix(input?.value || 'short-description');
const command = `${prefix}${suffix}`;
if (output) {
output.textContent = command;
}
return command;
}
function normaliseHelpdeskBranchSuffix(value) {
const slug = String(value || '')
.toLowerCase()
.trim()
.replace(/[^a-z0-9]+/g, '-')
.replace(/^-+|-+$/g, '')
.replace(/-{2,}/g, '-');
return slug || 'short-description';
}
async function copyHelpdeskBranchCommand(button) {
const container = button.closest('[data-helpdesk-branch-command]');
const status = container?.querySelector('[data-helpdesk-branch-copy-status]');
const command = updateHelpdeskBranchCommand(container);
if (!command) {
return;
}
try {
await navigator.clipboard.writeText(command);
} catch (error) {
const fallback = document.createElement('textarea');
fallback.value = command;
fallback.setAttribute('readonly', 'readonly');
fallback.style.position = 'fixed';
fallback.style.opacity = '0';
document.body.appendChild(fallback);
fallback.select();
document.execCommand('copy');
fallback.remove();
}
if (status) {
status.classList.remove('hidden');
window.setTimeout(() => status.classList.add('hidden'), 2200);
}
}
document.querySelectorAll('[data-helpdesk-branch-command]').forEach(updateHelpdeskBranchCommand);
function updateCommentToggleButtons() {
const commentCards = Array.from(document.querySelectorAll('[data-helpdesk-comment-card]'));
const expandButton = document.querySelector('[data-helpdesk-expand-comments]');
@@ -1222,24 +1295,80 @@
<i class="fa-solid fa-code-branch text-lg" aria-hidden="true"></i>
</span>
<div class="min-w-0">
<h2 class="text-lg font-black uppercase tracking-wide">Git commits</h2>
<p class="text-xs font-semibold text-violet-100">Code commits linked to this ticket</p>
<h2 class="text-lg font-black uppercase tracking-wide">Git activity</h2>
<p class="text-xs font-semibold text-violet-100">Branches and commits linked to this ticket</p>
</div>
</div>
</div>
@can('update', $ticket)
<div class="mb-4 rounded-xl border border-violet-200 bg-violet-50/80 p-3 shadow-sm dark:border-violet-900/70 dark:bg-violet-950/30"
data-helpdesk-branch-command
data-helpdesk-branch-prefix="git checkout -b bugfix/{{ $ticket->reference }}-">
<div class="flex items-start gap-3">
<span class="mt-0.5 inline-flex h-9 w-9 shrink-0 items-center justify-center rounded-lg bg-violet-700 text-white shadow-sm">
<i class="fa-solid fa-terminal text-sm" aria-hidden="true"></i>
</span>
<div class="min-w-0 flex-1">
<label for="helpdesk-branch-command-suffix" class="block text-xs font-black uppercase tracking-[0.16em] text-violet-900 dark:text-violet-100">
Branch command
</label>
<p class="mt-1 text-xs font-semibold text-violet-800/80 dark:text-violet-200/80">
Ticket reference is fixed. Enter the short branch description after {{ $ticket->reference }}-.
</p>
</div>
</div>
<div class="mt-3 grid gap-2">
<div class="flex flex-col gap-2 sm:flex-row">
<div class="flex min-h-10 flex-1 overflow-hidden rounded-lg border border-violet-200 bg-white shadow-sm focus-within:border-violet-500 focus-within:ring-2 focus-within:ring-violet-400/30 dark:border-violet-800 dark:bg-zinc-950">
<span class="hidden items-center border-r border-violet-100 bg-violet-100/70 px-3 font-mono text-[0.68rem] font-black text-violet-900 dark:border-violet-900 dark:bg-violet-950 dark:text-violet-100 sm:inline-flex">
bugfix/{{ $ticket->reference }}-
</span>
<input id="helpdesk-branch-command-suffix" type="text" inputmode="text" autocomplete="off" spellcheck="false"
value="helpdesk-ticket-branch-linking"
class="min-h-10 flex-1 border-0 bg-transparent px-3 py-2 font-mono text-xs font-semibold text-zinc-900 outline-none placeholder:text-zinc-400 focus:ring-0 dark:text-zinc-100"
placeholder="short-description"
data-helpdesk-branch-suffix>
</div>
<button type="button"
class="inline-flex min-h-10 items-center justify-center rounded-lg bg-violet-700 px-3 py-2 text-xs font-black text-white shadow-sm transition hover:bg-violet-800 focus:outline-none focus:ring-2 focus:ring-violet-400/70"
data-helpdesk-copy-branch-command>
<i class="fa-solid fa-copy mr-2" aria-hidden="true"></i>
Copy command
</button>
</div>
<code class="block overflow-x-auto rounded-lg border border-violet-100 bg-white/80 px-3 py-2 font-mono text-[0.68rem] font-bold text-violet-950 dark:border-violet-900 dark:bg-zinc-950/80 dark:text-violet-100"
data-helpdesk-branch-command-output>git checkout -b bugfix/{{ $ticket->reference }}-helpdesk-ticket-branch-linking</code>
<p class="hidden text-xs font-bold text-emerald-700 dark:text-emerald-300" data-helpdesk-branch-copy-status>
Copied to clipboard.
</p>
</div>
</div>
@endcan
<div class="space-y-2">
@forelse ($ticket->gitCommits as $commit)
<a href="{{ $commit->url ?: '#' }}" target="_blank"
class="block rounded-lg border border-zinc-100 p-2 dark:border-zinc-800">
<div class="font-mono text-[0.68rem] text-zinc-500">{{ $commit->short_hash }} ·
{{ $commit->repository?->name }}</div>
<div class="font-mono text-[0.68rem] text-zinc-500">
{{ $commit->short_hash === 'branch' ? 'branch' : $commit->short_hash }} ·
{{ $commit->repository?->name }}
</div>
@if ($commit->branch)
<div class="mt-1 break-words font-mono text-[0.68rem] font-semibold text-violet-700 dark:text-violet-300">
{{ $commit->branch }}
</div>
@endif
<div class="mt-1 text-xs font-medium text-zinc-900 dark:text-zinc-100">
{{ $commit->message }}</div>
{{ $commit->message }}
</div>
</a>
@empty
<div
class="rounded-lg border border-dashed border-zinc-300 p-3 text-center text-xs text-zinc-500 dark:border-zinc-700">
No commits linked.
No Git activity linked.
</div>
@endforelse
</div>
@@ -202,6 +202,7 @@
class="mb-2 block text-sm font-bold text-zinc-700 dark:text-zinc-200">Subject</label>
<input id="reply-subject-{{ $comment->id }}" name="subject"
value="{{ old('subject', 'RE: ' . $commentSubject) }}"
spellcheck="true" lang="en-GB" autocorrect="on" autocomplete="on" autocapitalize="sentences" inputmode="text"
class="block w-full rounded-xl border border-zinc-300 bg-white p-3 text-sm font-semibold text-zinc-900 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:border-zinc-700 dark:bg-zinc-950 dark:text-zinc-100">
</div>
<label for="reply-body-{{ $comment->id }}"
@@ -232,7 +233,7 @@
@can('update', $currentTicket)
@if ($canSeeInternalNotes)
<div class="mt-3 grid gap-3 sm:grid-cols-2">
<label class="flex cursor-pointer items-start gap-3 rounded-xl border border-emerald-300 bg-emerald-50 p-3 text-emerald-950 shadow-sm transition hover:bg-emerald-100 dark:border-emerald-900 dark:bg-emerald-950/60 dark:text-emerald-100">
<label class="flex cursor-pointer items-start gap-3 rounded-xl border border-emerald-300 bg-emerald-50 p-3 text-emerald-950 shadow-sm transition hover:border-emerald-400 hover:bg-emerald-100/80 focus-within:border-emerald-500 focus-within:bg-emerald-100/80 focus-within:ring-2 focus-within:ring-emerald-400/30 active:bg-emerald-100/80 dark:border-emerald-900 dark:bg-emerald-950/60 dark:text-emerald-100 dark:hover:border-emerald-700 dark:hover:bg-emerald-900/50 dark:focus-within:bg-emerald-900/50">
<input type="radio" name="internal" value="0" checked class="mt-1 border-emerald-400 text-emerald-600 focus:ring-emerald-500">
<span>
<span class="block text-sm font-extrabold">Public reply</span>
@@ -240,7 +241,7 @@
</span>
</label>
<label class="flex cursor-pointer items-start gap-3 rounded-xl border border-purple-300 bg-purple-50 p-3 text-purple-950 shadow-sm transition hover:bg-purple-100 dark:border-purple-900 dark:bg-purple-950/60 dark:text-purple-100">
<label class="flex cursor-pointer items-start gap-3 rounded-xl border border-purple-300 bg-purple-50 p-3 text-purple-950 shadow-sm transition hover:border-purple-400 hover:bg-purple-100/80 focus-within:border-purple-500 focus-within:bg-purple-100/80 focus-within:ring-2 focus-within:ring-purple-400/30 active:bg-purple-100/80 dark:border-purple-900 dark:bg-purple-950/60 dark:text-purple-100 dark:hover:border-purple-700 dark:hover:bg-purple-900/50 dark:focus-within:bg-purple-900/50">
<input type="radio" name="internal" value="1" class="mt-1 border-purple-400 text-purple-600 focus:ring-purple-500">
<span>
<span class="block text-sm font-extrabold">Internal note</span>
@@ -47,8 +47,9 @@ final class GitSpellcheckSettingsUiFilesTest extends TestCase
$ticketShowContents = file_get_contents($ticketShow) ?: '';
$commentThreadContents = file_get_contents($commentThread) ?: '';
self::assertStringContainsString('contenteditable="true" spellcheck="true" lang="en-GB"', $ticketShowContents);
self::assertStringContainsString('contenteditable="true" role="textbox" aria-multiline="true" spellcheck="true" lang="en-GB"', $ticketShowContents);
self::assertStringContainsString('name="commentBody" required spellcheck="true" lang="en-GB"', $ticketShowContents);
self::assertStringContainsString('data-helpdesk-comment-subject', $ticketShowContents);
self::assertStringContainsString('spellcheck="true" lang="en-GB" autocorrect="on"', $commentThreadContents);
self::assertStringContainsString('autocapitalize="sentences" inputmode="text"', $commentThreadContents);
}
@@ -0,0 +1,78 @@
<?php
/**
* TicketBranchCommandUiFilesTest.php
*
* Guards the ticket-level Git activity branch command builder and comment UI polish.
*/
declare(strict_types=1);
namespace Modules\Helpdesk\Tests\Feature;
use PHPUnit\Framework\TestCase;
final class TicketBranchCommandUiFilesTest extends TestCase
{
/**
* Ensure ticket Git activity exposes a professional branch command copy workflow.
*/
public function test_ticket_git_activity_has_branch_command_builder_and_copy_button(): void
{
$viewPath = dirname(__DIR__, 2) . '/Resources/views/livewire/ticket-show.blade.php';
self::assertFileExists($viewPath);
$view = file_get_contents($viewPath);
self::assertIsString($view);
self::assertStringContainsString('data-helpdesk-branch-command', $view);
self::assertStringContainsString('git checkout -b bugfix/{{ $ticket->reference }}-', $view);
self::assertStringContainsString('data-helpdesk-branch-suffix', $view);
self::assertStringContainsString('data-helpdesk-copy-branch-command', $view);
self::assertStringContainsString('copyHelpdeskBranchCommand', $view);
self::assertStringContainsString('normaliseHelpdeskBranchSuffix', $view);
self::assertStringContainsString('Copied to clipboard.', $view);
}
/**
* Ensure visibility selectors keep their accent backgrounds during interaction.
*/
public function test_visibility_controls_keep_accent_backgrounds_on_hover_and_focus(): void
{
$ticketViewPath = dirname(__DIR__, 2) . '/Resources/views/livewire/ticket-show.blade.php';
$threadViewPath = dirname(__DIR__, 2) . '/Resources/views/partials/comment-thread.blade.php';
$ticketView = file_get_contents($ticketViewPath);
$threadView = file_get_contents($threadViewPath);
self::assertIsString($ticketView);
self::assertIsString($threadView);
self::assertStringContainsString('hover:bg-emerald-100/80', $ticketView);
self::assertStringContainsString('focus-within:bg-emerald-100/80', $ticketView);
self::assertStringContainsString('hover:bg-purple-100/80', $ticketView);
self::assertStringContainsString('focus-within:bg-purple-100/80', $ticketView);
self::assertStringContainsString('hover:bg-emerald-100/80', $threadView);
self::assertStringContainsString('hover:bg-purple-100/80', $threadView);
}
/**
* Ensure ticket comments and threaded replies expose browser spelling hints.
*/
public function test_ticket_comment_subjects_and_bodies_enable_spellcheck(): void
{
$ticketViewPath = dirname(__DIR__, 2) . '/Resources/views/livewire/ticket-show.blade.php';
$threadViewPath = dirname(__DIR__, 2) . '/Resources/views/partials/comment-thread.blade.php';
$ticketView = file_get_contents($ticketViewPath);
$threadView = file_get_contents($threadViewPath);
self::assertIsString($ticketView);
self::assertIsString($threadView);
self::assertStringContainsString('data-helpdesk-comment-subject', $ticketView);
self::assertStringContainsString('spellcheck="true" lang="en-GB" autocorrect="on" autocomplete="on" autocapitalize="sentences" inputmode="text"', $ticketView);
self::assertStringContainsString('role="textbox" aria-multiline="true" spellcheck="true"', $ticketView);
self::assertStringContainsString('id="reply-subject-{{ $comment->id }}"', $threadView);
self::assertStringContainsString('spellcheck="true" lang="en-GB" autocorrect="on" autocomplete="on" autocapitalize="sentences" inputmode="text"', $threadView);
}
}
+23
View File
@@ -573,3 +573,26 @@
- Added regression coverage for create/edit spellcheck wiring and directly linked Git commit visibility for ticket-level views.
- Preserved append-only changelog history.
- version: 1.10.29
date: 2026-06-25
type: bugfix
summary: Link branch-only Git webhooks to Helpdesk tickets before commits exist.
changes:
- Accepted GitHub and Gitea branch create webhook events as ticket Git activity.
- Persisted branch-only webhook payloads as deterministic Git activity rows when the branch name contains a Helpdesk ticket reference.
- Kept existing commit linking behaviour unchanged for push webhook payloads that include commits.
- Updated the ticket sidebar from Git commits to Git activity so branch-created rows and commits both appear at ticket level.
- Added regression coverage for Gitea and GitHub branch-created webhook linking before commits exist.
- Preserved append-only changelog history.
- version: 1.10.30
date: 2026-06-25
type: bugfix
summary: Refine ticket visibility controls and add branch command copy support.
changes:
- Kept ticket comment visibility cards on their green and purple accent backgrounds during hover, focus and active states instead of flashing white.
- Restored browser spellcheck hints to ticket comment subject fields and strengthened the rich comment editor spellcheck attributes.
- Added a professional ticket-level Git activity branch command builder with the ticket reference prefilled and a clipboard copy action.
- Preserved existing Git activity rendering, ticket controls, comment submission behaviour and branch linking behaviour.
- Preserved append-only changelog history.
+1 -1
View File
@@ -23,5 +23,5 @@
"Modules\\Helpdesk\\Providers\\HelpdeskServiceProvider"
],
"files": [],
"version": "1.10.28"
"version": "1.10.30"
}