10 Commits
14 changed files with 234 additions and 174 deletions
@@ -683,3 +683,12 @@ html.dark .doc-content code {
}
.doc-pagination nav span[aria-disabled="true"] > span { color: #697180 !important; cursor: not-allowed; }
.doc-pagination nav svg { width: 1rem; height: 1rem; }
/* Documentation: professional contrast and strict light/dark mode parity. */
html:not(.dark) .documentation-surface,
html:not(.dark) [data-documentation-surface] { color:#18181b !important; }
html:not(.dark) .documentation-surface :is(.text-zinc-400,.text-zinc-500,.text-zinc-600,.text-gray-400,.text-gray-500,.text-gray-600),
html:not(.dark) [data-documentation-surface] :is(.text-zinc-400,.text-zinc-500,.text-zinc-600,.text-gray-400,.text-gray-500,.text-gray-600) { color:#52525b !important; }
html.dark .documentation-surface :is(.text-zinc-400,.text-zinc-500,.text-zinc-600,.text-gray-400,.text-gray-500,.text-gray-600),
html.dark [data-documentation-surface] :is(.text-zinc-400,.text-zinc-500,.text-zinc-600,.text-gray-400,.text-gray-500,.text-gray-600) { color:#a1a1aa !important; }
html:not(.dark) .documentation-surface :is(section,article,.card,[class*="rounded"]):not([class*="bg-"]){ color:#27272a; }
@@ -8,6 +8,7 @@ use App\Http\Controllers\Controller;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Gate;
use Illuminate\Validation\Rule;
@@ -1439,3 +1439,72 @@ html:not(.dark) .helpdesk-ticket-form select:-webkit-autofill:focus {
html:not(.dark) .hd-helpdesk-surface {
color: #1f2937;
}
/* Professional theme contract: readable contrast in both application modes. */
html:not(.dark) .hd-helpdesk-surface {
color: #18181b !important;
}
html:not(.dark) .hd-helpdesk-surface :is(.text-zinc-100,.text-zinc-200,.text-zinc-300,.text-zinc-400,.text-zinc-500,.text-zinc-600,.text-zinc-700,.text-zinc-900) {
color: #3f3f46 !important;
}
html:not(.dark) .hd-helpdesk-surface :is(h1,h2,h3,h4,.font-semibold,.font-bold,.font-black):not(.hd-btn):not([class*="text-white"]) {
color: #18181b;
}
html:not(.dark) .hd-helpdesk-surface .text-blue-100\/90,
html:not(.dark) .hd-helpdesk-surface .text-blue-100,
html:not(.dark) .hd-helpdesk-surface .text-blue-200,
html:not(.dark) .hd-helpdesk-surface .text-amber-100\/85,
html:not(.dark) .hd-helpdesk-surface .text-amber-100,
html:not(.dark) .hd-helpdesk-surface .text-amber-200 {
color: #475569 !important;
}
/* Heroes are light in light mode and intentionally dark in dark mode. */
html:not(.dark) .hd-helpdesk-surface :is(.hd-page-hero,.hd-settings-hero-inner) {
background: linear-gradient(135deg,#ffffff 0%,#f8fafc 55%,#eef4ff 100%) !important;
color: #18181b !important;
}
html.dark .hd-helpdesk-surface :is(.hd-page-hero,.hd-settings-hero-inner) {
background: linear-gradient(135deg,#020617 0%,#0f172a 55%,#172554 100%) !important;
color: #f8fafc !important;
}
html:not(.dark) .hd-helpdesk-surface :is(.hd-page-hero,.hd-settings-hero-inner) :is(h1,h2,h3) { color:#18181b !important; }
html:not(.dark) .hd-helpdesk-surface :is(.hd-page-hero,.hd-settings-hero-inner) p { color:#475569 !important; }
html.dark .hd-helpdesk-surface :is(.hd-page-hero,.hd-settings-hero-inner) :is(h1,h2,h3) { color:#f8fafc !important; }
html.dark .hd-helpdesk-surface :is(.hd-page-hero,.hd-settings-hero-inner) p { color:#cbd5e1 !important; }
/* Search/filter surface follows the switch instead of remaining black. */
html:not(.dark) .hd-helpdesk-surface .hd-filter-panel {
background:#ffffff !important; border-color:#d4d4d8 !important; color:#18181b !important;
}
html.dark .hd-helpdesk-surface .hd-filter-panel {
background:#18181b !important; border-color:#3f3f46 !important; color:#f4f4f5 !important;
}
html:not(.dark) .hd-ticket-search,
html:not(.dark) .hd-ticket-search-wrap { background:#fff !important; color:#18181b !important; border-color:#cbd5e1 !important; }
html:not(.dark) .hd-ticket-search::placeholder { color:#71717a !important; opacity:1; }
html:not(.dark) .hd-ticket-search-icon { color:#52525b !important; }
html.dark .hd-ticket-search,
html.dark .hd-ticket-search-wrap { background:#09090b !important; color:#f4f4f5 !important; border-color:#3f3f46 !important; }
html.dark .hd-ticket-search::placeholder { color:#a1a1aa !important; opacity:1; }
html.dark .hd-ticket-search-icon { color:#a1a1aa !important; }
/* Tables: body copy must never fade into its background. */
html:not(.dark) .hd-helpdesk-surface table tbody { color:#27272a !important; }
html:not(.dark) .hd-helpdesk-surface table tbody :is(.text-zinc-500,.text-zinc-600,.text-zinc-700) { color:#52525b !important; }
html:not(.dark) .hd-helpdesk-surface table tbody :is(.font-medium,.font-semibold) { color:#18181b !important; }
html.dark .hd-helpdesk-surface table tbody { color:#e4e4e7 !important; }
html.dark .hd-helpdesk-surface table tbody :is(.text-zinc-400,.text-zinc-500,.text-zinc-600,.text-zinc-700) { color:#a1a1aa !important; }
html.dark .hd-helpdesk-surface table tbody :is(.font-medium,.font-semibold) { color:#f4f4f5 !important; }
/* Settings navigation cards use dark copy on translucent pastel cards in light mode. */
.hd-settings-section-card { border-color:var(--hd-card-border) !important; background:var(--hd-card-bg) !important; }
html:not(.dark) .hd-settings-section-card { color:#18181b !important; box-shadow:0 8px 20px rgba(15,23,42,.08) !important; }
html:not(.dark) .hd-settings-section-card.is-active { color:#fff !important; background:var(--hd-card-active) !important; }
html.dark .hd-settings-section-card { color:#f8fafc !important; }
html.dark .hd-settings-section-card.is-active { background:var(--hd-card-active) !important; }
.hd-settings-section-card > div:first-child { opacity:.82 !important; }
/* Muted text remains secondary, but readable. */
html:not(.dark) .hd-helpdesk-surface .hd-muted { color:#52525b !important; }
html.dark .hd-helpdesk-surface .hd-muted { color:#a1a1aa !important; }
+23 -3
View File
@@ -29,10 +29,10 @@ host('develop')
->set('deploy_path', '/var/www/helpdesk_dev');
host('mpba')
->set('hostname', 'helpdesk.mpba.dev')
->set('hostname', 'sirius.absdev.net')
->set('remote_user', 'mag')
->set('branch', 'main')
->set('deploy_path', '/var/www/helpdesk_mpba');
->set('deploy_path', '/var/www/helpdesk');
/*
* Install the root npm tree, then every module that owns its own lock file,
@@ -86,9 +86,29 @@ task('artisan:clear', function (): void {
});
task('services:restart', function (): void {
// Validate and reload nginx.
run('sudo -n nginx -t');
run('sudo -n systemctl reload nginx');
run('sudo -n systemctl restart php8.3-fpm');
// Detect the PHP-FPM socket configured in nginx.
$socket = trim(run(
"sudo -n nginx -T 2>/dev/null"
. " | grep -oE 'php[0-9]+\\.[0-9]+-fpm\\.sock'"
. " | sort -Vu"
. " | tail -n 1"
));
if ($socket === '') {
throw new \RuntimeException(
'Unable to detect the PHP-FPM version from nginx configuration.'
);
}
// Convert php8.5-fpm.sock into php8.5-fpm.
$service = str_replace('.sock', '', $socket);
writeln("<info>Detected PHP-FPM service: {$service}</info>");
// Restart the detected PHP-FPM service.
run("sudo -n systemctl restart {$service}");
writeln("<info>PHP-FPM restarted successfully.</info>");
});
after('deploy:update_code', 'deploy:write_revision_file');
+88 -104
View File
@@ -2497,118 +2497,102 @@ html:not(.dark) .hd-appearance-choice.is-active { background: #fff; color: #1118
color: #3b82f6 !important;
}
/* ========================================================================
Appearance switch: final application-wide neutral surface normalisation
Keep semantic/action colours, but every neutral view follows html.dark.
======================================================================== */
html:not(.dark) .hd-dashboard-heading h1,
html:not(.dark) .hd-metric-card strong,
html:not(.dark) .hd-dashboard-card > header h2,
html:not(.dark) .hd-donut span,
html:not(.dark) .hd-priority-legend strong,
html:not(.dark) .hd-page-hero h1,
html:not(.dark) .hd-role-card h2,
html:not(.dark) .hd-role-card strong {
color: #111827 !important;
/* ============================================================
LIGHT APPEARANCE — COMPLETE MODULE SURFACE OVERRIDES
Keep semantic/action colours, but remove hard-coded dark chrome.
============================================================ */
html:not(.dark) .hd-page-hero {
background: linear-gradient(115deg,#ffffff,#eef4ff) !important;
border-color:#d8dee7 !important;
box-shadow:0 1px 2px rgba(15,23,42,.06) !important;
}
html:not(.dark) .hd-dashboard-heading p,
html:not(.dark) .hd-metric-card small,
html:not(.dark) .hd-metric-card em,
html:not(.dark) .hd-chart-legend,
html:not(.dark) .hd-chart-labels,
html:not(.dark) .hd-priority-legend > div,
html:not(.dark) .hd-latest-list small,
html:not(.dark) .hd-latest-list time,
html:not(.dark) .hd-requester-list em,
html:not(.dark) .hd-empty,
html:not(.dark) .hd-page-hero p,
html:not(.dark) .hd-role-card p,
html:not(.dark) .hd-field span,
html:not(.dark) .hd-role-options small {
color: #667085 !important;
}
html:not(.dark) .hd-range-select,
html:not(.dark) .hd-metric-card,
html:not(.dark) .hd-dashboard-card,
html:not(.dark) .hd-page-hero h1 { color:#111827 !important; }
html:not(.dark) .hd-page-hero p { color:#667085 !important; }
html:not(.dark) .hd-eyebrow { color:#41658f !important; }
html:not(.dark) .hd-panel,
html:not(.dark) .hd-role-card,
html:not(.dark) .hd-role-options label {
background: #ffffff !important;
border-color: #d8dee7 !important;
color: #1f2937 !important;
box-shadow: 0 8px 24px rgba(15, 23, 42, .06) !important;
html:not(.dark) .helpdesk-kanban-column,
html:not(.dark) .hd-dashboard-card,
html:not(.dark) .hd-role-card {
background:#ffffff !important;
border-color:#d8dee7 !important;
color:#1f2937 !important;
}
html:not(.dark) .hd-range-select select,
html:not(.dark) .hd-search-field input,
html:not(.dark) .hd-field input {
color: #1f2937 !important;
}
html:not(.dark) .hd-dashboard-card > header,
html:not(.dark) .hd-latest-list > a,
html:not(.dark) .hd-requester-list > div,
html:not(.dark) .hd-toolbar,
html:not(.dark) .hd-dashboard-card>header,
html:not(.dark) .hd-latest-list>a,
html:not(.dark) .hd-requester-list>div,
html:not(.dark) .hd-table th,
html:not(.dark) .hd-table td {
border-color: #e2e8f0 !important;
border-color:#e2e8f0 !important;
}
html:not(.dark) .hd-dashboard-card > header a,
html:not(.dark) .hd-action,
html:not(.dark) .hd-search-field,
html:not(.dark) .hd-toolbar { background:#f8fafc !important; }
html:not(.dark) .hd-search-field {
background:#ffffff !important;
border-color:#cfd6e1 !important;
color:#667085 !important;
}
html:not(.dark) .hd-search-field input { color:#1f2937 !important; }
html:not(.dark) .hd-table th { background:#f3f5f8 !important; color:#667085 !important; }
html:not(.dark) .hd-table td { background:#ffffff !important; color:#1f2937 !important; }
html:not(.dark) .hd-table tbody tr:hover td { background:#f8fafc !important; }
html:not(.dark) .hd-action:not(.hd-action-blue):not(.hd-action-green):not(.hd-action-red) {
background:#ffffff !important; border-color:#cfd6e1 !important; color:#1f2937 !important;
}
html:not(.dark) .hd-role-card h2,
html:not(.dark) .hd-role-card strong,
html:not(.dark) .hd-dashboard-card>header h2 { color:#111827 !important; }
html:not(.dark) .hd-role-card p,
html:not(.dark) .hd-dashboard-card>header span,
html:not(.dark) .hd-dashboard-card>header a,
html:not(.dark) .hd-requester-list em,
html:not(.dark) .hd-empty { color:#667085 !important; }
html:not(.dark) .hd-metric-card {
background:linear-gradient(145deg,#ffffff,#f8fafc) !important;
border-color:#d8dee7 !important;
box-shadow:0 8px 20px rgba(15,23,42,.07) !important;
}
html:not(.dark) .hd-donut:after { background:#ffffff !important; }
html:not(.dark) .hd-donut span,
html:not(.dark) .hd-priority-legend strong { color:#111827 !important; }
html:not(.dark) .hd-priority-legend>div,
html:not(.dark) .hd-latest-list>a { color:#374151 !important; }
html:not(.dark) .hd-latest-list>a:hover { background:#f8fafc !important; }
html:not(.dark) .hd-chart-grid-lines line { stroke:#d8dee7 !important; }
html:not(.dark) .hd-form-grid .hd-field span { color:#374151 !important; }
html:not(.dark) .hd-field input {
background: #f8fafc !important;
border-color: #d8dee7 !important;
color: #374151 !important;
background:#ffffff !important; color:#1f2937 !important; border-color:#cfd6e1 !important;
}
html:not(.dark) .hd-role-options label { background:#ffffff !important; border-color:#d8dee7 !important; }
html:not(.dark) .hd-role-options small { color:#667085 !important; }
html:not(.dark) .hd-kanban-drag-handle {
background:#f3f5f8 !important; border-color:#d8dee7 !important; color:#667085 !important;
}
html:not(.dark) .hd-kanban-drag-handle:hover { background:#e9eef5 !important; color:#111827 !important; }
html:not(.dark) .hd-dashboard-card > header a:hover,
html:not(.dark) .hd-latest-list > a:hover,
html:not(.dark) .hd-action:hover {
background: #eef2f7 !important;
color: #111827 !important;
}
html:not(.dark) .hd-latest-list > a,
html:not(.dark) .hd-table td,
html:not(.dark) .hd-priority-legend strong {
color: #374151 !important;
}
html:not(.dark) .hd-table th {
background: #f8fafc !important;
color: #667085 !important;
}
/* The page hero is a neutral container. Accent buttons/badges keep their colour. */
html:not(.dark) .hd-page-hero {
background: linear-gradient(115deg, #ffffff, #f1f5f9) !important;
border-color: #d8dee7 !important;
box-shadow: 0 8px 24px rgba(15, 23, 42, .06) !important;
}
html:not(.dark) .hd-eyebrow { color: #2563eb !important; }
/* Neutral Tailwind surfaces used by module views. */
html.dark .bg-white { background-color: #18181b !important; }
html.dark .bg-zinc-50,
html.dark .bg-zinc-100 { background-color: #27272a !important; }
html.dark .text-zinc-900,
html.dark .text-zinc-800,
html.dark .text-zinc-700 { color: #f4f4f5 !important; }
html.dark .border-zinc-200,
html.dark .border-zinc-300 { border-color: #3f3f46 !important; }
/* Native controls must follow the selected colour scheme in every module. */
html:not(.dark) .hd-shell-main input:not([type="checkbox"]):not([type="radio"]):not([type="color"]):not([type="file"]),
html:not(.dark) .hd-shell-main textarea,
html:not(.dark) .hd-shell-main select {
color-scheme: light;
}
html.dark .hd-shell-main input:not([type="checkbox"]):not([type="radio"]):not([type="color"]):not([type="file"]),
html.dark .hd-shell-main textarea,
html.dark .hd-shell-main select {
color-scheme: dark;
/* Tailwind utility surfaces used directly by Helpdesk Blade views. */
html:not(.dark) .bg-black,
html:not(.dark) .bg-slate-950,
html:not(.dark) .bg-slate-900,
html:not(.dark) .bg-slate-800,
html:not(.dark) .bg-slate-700,
html:not(.dark) .bg-slate-600,
html:not(.dark) .bg-neutral-950,
html:not(.dark) .bg-neutral-900,
html:not(.dark) .bg-neutral-800 {
background-color:#ffffff !important;
}
html:not(.dark) [class*="bg-slate-950/"],
html:not(.dark) [class*="bg-slate-900/"],
html:not(.dark) [class*="bg-black/"] { background-color:#ffffff !important; }
html:not(.dark) [class*="border-slate-"],
html:not(.dark) [class*="border-neutral-"] { border-color:#d8dee7 !important; }
html:not(.dark) [class*="text-slate-100"],
html:not(.dark) [class*="text-slate-200"],
html:not(.dark) [class*="text-neutral-100"],
html:not(.dark) [class*="text-neutral-200"] { color:#1f2937 !important; }
html:not(.dark) [class*="text-slate-300"],
html:not(.dark) [class*="text-neutral-300"] { color:#374151 !important; }
html:not(.dark) [class*="text-slate-400"],
html:not(.dark) [class*="text-slate-500"],
html:not(.dark) [class*="text-neutral-400"],
html:not(.dark) [class*="text-neutral-500"] { color:#667085 !important; }
+15 -14
View File
@@ -10,10 +10,11 @@
class="space-y-2"
x-data="{
model: @js($model),
value: @entangle($model),
value: '',
init() {
this.$nextTick(() => {
this.writeEditorValue(this.value || '');
this.value = this.$wire.get(this.model) || '';
this.writeEditorValue(this.value);
});
},
writeEditorValue(value) {
@@ -30,29 +31,29 @@
this.$refs.editor.textContent = nextValue;
},
syncToLivewire(live = true) {
this.value = this.$refs.editor?.innerText || '';
syncToLivewire(live = false) {
const text = this.$refs.editor?.innerText || '';
this.value = text;
if (this.$refs.input) {
this.$refs.input.value = this.value;
this.$refs.input.value = text;
}
this.$wire.set(this.model, this.value, live);
// Update Livewire's local state before the save request is assembled.
this.$wire.set(this.model, text, live);
},
resetEditor() {
this.value = '';
this.writeEditorValue('');
this.syncToLivewire(true);
this.syncToLivewire(false);
},
runCommand(command) {
this.$refs.editor?.focus();
document.execCommand(command, false, null);
this.syncToLivewire(true);
this.syncToLivewire(false);
},
wrapBlock(tagName) {
this.$refs.editor?.focus();
document.execCommand('formatBlock', false, tagName);
this.syncToLivewire(true);
this.syncToLivewire(false);
},
}"
x-on:helpdesk-editor-sync.window="if (! $event.detail?.model || $event.detail.model === @js($model)) syncToLivewire($event.detail?.live ?? true)"
@@ -116,14 +117,14 @@
data-helpdesk-sync-target="{{ $model }}"
data-helpdesk-editor-model="{{ $model }}"
@if ($editorDusk) data-dusk="{{ $editorDusk }}" dusk="{{ $editorDusk }}" @endif
x-on:paste="syncToLivewire(false)"
x-on:blur="syncToLivewire(true)"
x-on:input="syncToLivewire(false)"
x-on:paste="$nextTick(() => syncToLivewire(false))"
x-on:blur="syncToLivewire(false)"
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>
<textarea
x-ref="input"
wire:model.defer="{{ $model }}"
spellcheck="true"
lang="en-GB"
autocorrect="on"
@@ -1,6 +1,6 @@
<div class="hd-helpdesk-surface hd-mobile-ready space-y-6" dusk="helpdesk-ticket-archive">
<section class="overflow-hidden rounded-3xl border border-zinc-200 bg-white shadow-sm dark:border-zinc-700 dark:bg-zinc-900">
<div class="bg-gradient-to-br from-slate-950 via-slate-900 to-amber-950 px-6 py-7 text-white">
<div class="hd-page-hero bg-gradient-to-br from-slate-950 via-slate-900 to-amber-950 px-6 py-7 text-white">
<div class="flex flex-col gap-5 lg:flex-row lg:items-center lg:justify-between">
<div>
<p class="text-xs font-semibold uppercase tracking-[0.28em] text-amber-200">Ticket archive</p>
@@ -16,7 +16,7 @@
</div>
</section>
<section class="rounded-2xl border border-zinc-200 bg-white p-4 shadow-sm dark:border-zinc-700 dark:bg-zinc-900">
<section class="hd-filter-panel rounded-2xl border border-zinc-200 bg-white p-4 shadow-sm dark:border-zinc-700 dark:bg-zinc-900">
<div class="hd-ticket-search-wrap max-w-2xl">
<i class="fa-solid fa-magnifying-glass hd-ticket-search-icon" aria-hidden="true"></i>
<input type="search" class="hd-ticket-search" wire:model.live.debounce.350ms="search"
@@ -77,22 +77,13 @@
default => ['border' => '#71717a', 'bg' => 'rgba(63, 63, 70, .22)', 'active' => '#3f3f46'],
};
$sectionStyle =
$section === $key
? 'border-color: ' .
$sectionPalette['border'] .
'; background-color: ' .
$sectionPalette['active'] .
'; color: #ffffff; box-shadow: 0 16px 36px rgba(0,0,0,.32);'
: 'border-color: ' .
$sectionPalette['border'] .
'; background-color: ' .
$sectionPalette['bg'] .
'; color: #ffffff; box-shadow: 0 10px 24px rgba(0,0,0,.20);';
$sectionStyle = '--hd-card-border: ' . $sectionPalette['border'] .
'; --hd-card-bg: ' . $sectionPalette['bg'] .
'; --hd-card-active: ' . $sectionPalette['active'] . ';';
@endphp
<a href="{{ route('helpdesk.settings', ['section' => $key]) }}"
dusk="helpdesk-settings-section-{{ $key }}"
class="hd-settings-section-card rounded-xl border px-3 py-2 text-left shadow-sm transition hover:-translate-y-0.5"
class="hd-settings-section-card {{ $section === $key ? 'is-active' : '' }} rounded-xl border px-3 py-2 text-left shadow-sm transition hover:-translate-y-0.5"
style="{{ $sectionStyle }}">
<div class="text-xs font-semibold uppercase tracking-wide opacity-70">{{ $item['label'] }}</div>
<div class="mt-0.5 text-xl font-semibold">{{ $item['count'] }}</div>
+5 -25
View File
@@ -18,33 +18,9 @@
x-on:submit.capture="
if (helpdeskAttachmentsUploading) {
$event.preventDefault();
$event.stopImmediatePropagation();
return;
}
const editor = document.querySelector('[data-helpdesk-sync-target=&quot;body&quot;], [data-helpdesk-editor-model=&quot;body&quot;]');
const target = Array.from(document.querySelectorAll('textarea')).find(function (textarea) {
return textarea.getAttribute('wire:model.defer') === 'body'
|| textarea.getAttribute('wire:model') === 'body'
|| textarea.getAttribute('name') === 'body'
|| textarea.id === 'body';
});
const body = (editor?.innerText || editor?.textContent || editor?.value || '').trim();
if (target) {
target.value = body;
target.dispatchEvent(new Event('input', { bubbles: true }));
target.dispatchEvent(new Event('change', { bubbles: true }));
}
if ($wire) {
$wire.set('body', body, false);
}
$dispatch('helpdesk-editor-sync', { model: 'body', live: false });
"
class="helpdesk-ticket-form space-y-6"
@@ -245,6 +221,10 @@
editor-dusk="ticket-body-editor"
/>
@error('body')
<p class="mt-2 text-sm text-red-500" role="alert">{{ $message }}</p>
@enderror
<p class="mt-2 flex items-center gap-2 text-xs font-medium text-zinc-400">
<i class="fa-solid fa-circle-info text-blue-400" aria-hidden="true"></i>
Rich formatting is available. Browser spelling suggestions appear by right-clicking or Ctrl-clicking red-underlined words.
@@ -1,7 +1,7 @@
<div class="hd-helpdesk-surface hd-mobile-ready space-y-6" dusk="helpdesk-ticket-index">
<div
class="overflow-hidden rounded-3xl border border-zinc-200 bg-white shadow-sm dark:border-zinc-700 dark:bg-zinc-900">
<div class="bg-gradient-to-br from-slate-950 via-slate-900 to-blue-950 px-6 py-7 text-white">
<div class="hd-page-hero bg-gradient-to-br from-slate-950 via-slate-900 to-blue-950 px-6 py-7 text-white">
<div class="flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between">
<div>
<p class="text-xs font-semibold uppercase tracking-[0.28em] text-blue-200">Ticket management</p>
@@ -27,7 +27,7 @@
</div>
</div>
<div class="rounded-2xl border border-zinc-200 bg-white p-4 shadow-sm dark:border-zinc-700 dark:bg-zinc-900">
<div class="hd-filter-panel rounded-2xl border border-zinc-200 bg-white p-4 shadow-sm dark:border-zinc-700 dark:bg-zinc-900">
<div class="grid gap-4 md:grid-cols-4">
<div class="hd-ticket-search-wrap">
<i class="fa-solid fa-magnifying-glass hd-ticket-search-icon" aria-hidden="true"></i>
@@ -122,7 +122,7 @@
<span
class="inline-flex shrink-0 items-center gap-2 rounded-xl bg-white/15 px-3 py-1.5 text-xs font-extrabold ring-1 ring-white/20">
<i class="fa-solid fa-paperclip text-xs" aria-hidden="true"></i>
{{ $ticket->attachments->count() }} file{{ $ticket->attachments->count() === 1 ? '' : 's' }}
{{ $ticket->attachments->filter(fn ($attachment) => ! $attachment->isDeletedAttachment())->count() }} file{{ $ticket->attachments->filter(fn ($attachment) => ! $attachment->isDeletedAttachment())->count() === 1 ? '' : 's' }}
<i class="fa-solid fa-chevron-right transition group-open:rotate-90" aria-hidden="true"></i>
</span>
</summary>
@@ -510,12 +510,12 @@
class="inline-flex cursor-pointer items-center justify-center rounded-lg bg-blue-600 px-3 py-2 text-xs font-bold text-white shadow-sm transition hover:bg-blue-700 focus-within:outline-none focus-within:ring-2 focus-within:ring-blue-400/70">
<i class="fa-solid fa-paperclip mr-2 text-xs" aria-hidden="true"></i>
<span>Choose files</span>
<input name="comment_attachments[]" type="file" multiple accept="{{ $helpdeskAttachmentAccept }}" class="sr-only"
<input name="attachments[]" type="file" multiple accept="{{ $helpdeskAttachmentAccept }}" class="sr-only"
data-helpdesk-file-input>
</label>
</div>
@error('comment_attachments')
@error('attachments')
<p class="mt-2 text-xs font-semibold text-red-600 dark:text-red-400">{{ $message }}</p>
@enderror
@@ -175,7 +175,7 @@
Respond
</button>
@if (auth()->user()?->isMpbaPlatformAdmin())
@if (auth()->user()?->isHelpdeskAdmin())
<form method="POST"
action="{{ route('helpdesk.tickets.comments.destroy', [$currentTicket, $comment]) }}"
onsubmit="return confirm('Delete this response? This will remove it from the visible conversation but keep the replication identity/audit trail.');">
-7
View File
@@ -1,7 +0,0 @@
JAVA_HOME="/opt/homebrew/opt/openjdk" \
PATH="/opt/homebrew/opt/openjdk/bin:$PATH" \
sonar-scanner \
-Dsonar.projectKey=Helpdesk \
-Dsonar.sources=. \
-Dsonar.host.url=http://127.0.0.1:9001 \
-Dsonar.login=sqp_36027127786b9a8ed4d0d165bdb3405ed07421d8
+12
View File
@@ -0,0 +1,12 @@
#!/usr/bin/env bash
# sqp_c0b887930297d93cf088476023c244d901c51204
set -euo pipefail
JAVA_HOME="/opt/homebrew/opt/openjdk" \
PATH="/opt/homebrew/opt/openjdk/bin:$PATH" \
sonar-scanner \
-Dsonar.projectKey=Helpdesk-System \
-Dsonar.sources=. \
-Dsonar.host.url=https://sonarcube.absdev.net \
-Dsonar.token="${SONAR_TOKEN:?SONAR_TOKEN is not set}"