fixed
This commit is contained in:
@@ -139,14 +139,6 @@ final class TicketCreate extends Component
|
|||||||
|
|
||||||
$this->subject = '';
|
$this->subject = '';
|
||||||
$this->body = '';
|
$this->body = '';
|
||||||
$this->company_id = null;
|
|
||||||
$this->board_id = null;
|
|
||||||
$this->priority_id = null;
|
|
||||||
$this->category_id = null;
|
|
||||||
$this->project_id = null;
|
|
||||||
$this->product_id = null;
|
|
||||||
$this->team_id = null;
|
|
||||||
$this->due_at = null;
|
|
||||||
$this->tag_ids = [];
|
$this->tag_ids = [];
|
||||||
$this->attachments = [];
|
$this->attachments = [];
|
||||||
|
|
||||||
|
|||||||
@@ -302,3 +302,20 @@ The module should keep tests around:
|
|||||||
- Reference sequence collision prevention.
|
- Reference sequence collision prevention.
|
||||||
- Browser spellcheck attributes on writable fields.
|
- Browser spellcheck attributes on writable fields.
|
||||||
|
|
||||||
|
|
||||||
|
## Rich Editor, Spellcheck, Clear and Close Workflow
|
||||||
|
|
||||||
|
The ticket create and reply forms use rich HTML editing controls. Do not replace the rich editor with a plain `<textarea>` to enable spelling suggestions. Spellcheck must be enabled on the actual `contenteditable` editor surface using `spellcheck="true"`, `lang="en-GB"`, `autocorrect="on"` and `autocomplete="on"`.
|
||||||
|
|
||||||
|
Browser spell suggestions appear inline as red underlines and are selected from the browser context menu by right-clicking or Ctrl-clicking the misspelled word.
|
||||||
|
|
||||||
|
The create-ticket **Clear** action must only clear transient user-entered content:
|
||||||
|
|
||||||
|
- subject
|
||||||
|
- details/body
|
||||||
|
- tags
|
||||||
|
- attachments
|
||||||
|
|
||||||
|
It must preserve configured routing defaults such as company, board, priority, category, project, team and due-date defaults.
|
||||||
|
|
||||||
|
When a user selects a closed ticket status, the professional closure modal must open on the first interaction. A closure comment remains mandatory, and the user can choose whether the closure comment is public or internal.
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
'label' => 'Details',
|
'label' => 'Details',
|
||||||
'rows' => 10,
|
'rows' => 10,
|
||||||
'placeholder' => 'Write your message...',
|
'placeholder' => 'Write your message...',
|
||||||
|
'editorDusk' => null,
|
||||||
])
|
])
|
||||||
|
|
||||||
@php
|
@php
|
||||||
@@ -65,8 +66,9 @@
|
|||||||
class="rounded-lg px-2 py-1 text-sm hover:bg-zinc-200 dark:hover:bg-zinc-800">Clear</button>
|
class="rounded-lg px-2 py-1 text-sm hover:bg-zinc-200 dark:hover:bg-zinc-800">Clear</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div x-ref="editor" contenteditable="true" spellcheck="true" lang="en-GB" x-on:input.debounce.150ms="sync" x-on:keyup="sync"
|
<div x-ref="editor" contenteditable="true" spellcheck="true" lang="en-GB" autocorrect="on" autocomplete="on"
|
||||||
x-on:paste="$nextTick(() => sync())" x-on:blur="sync"
|
@if ($editorDusk) data-dusk="{{ $editorDusk }}" dusk="{{ $editorDusk }}" @endif
|
||||||
|
x-on:input.debounce.150ms="sync" x-on:keyup="sync" x-on:paste="$nextTick(() => sync())" x-on:blur="sync"
|
||||||
class="prose prose-sm min-h-[{{ (int) $rows * 28 }}px] max-w-none bg-white p-4 text-sm text-zinc-900 outline-none dark:prose-invert dark:bg-zinc-950 dark:text-zinc-100"
|
class="prose prose-sm min-h-[{{ (int) $rows * 28 }}px] max-w-none bg-white p-4 text-sm text-zinc-900 outline-none dark:prose-invert dark:bg-zinc-950 dark:text-zinc-100"
|
||||||
data-placeholder="{{ $placeholder }}"></div>
|
data-placeholder="{{ $placeholder }}"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -220,42 +220,18 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="lg:col-span-3 xl:col-span-6">
|
<div class="lg:col-span-3 xl:col-span-6">
|
||||||
<label class="block text-sm font-semibold text-zinc-200" for="body-editor">
|
<x-helpdesk::html-editor
|
||||||
Details <span class="helpdesk-required-star">*</span>
|
label="Details"
|
||||||
</label>
|
rows="12"
|
||||||
|
placeholder="Describe the issue, expected outcome, steps to reproduce and any useful context..."
|
||||||
<div class="mt-2 rounded-xl border border-zinc-700 bg-zinc-950 shadow-sm focus-within:border-blue-500 focus-within:ring-2 focus-within:ring-blue-500/40">
|
wire:model="body"
|
||||||
<div class="flex flex-col gap-2 border-b border-zinc-700 bg-zinc-900 px-4 py-3 sm:flex-row sm:items-center sm:justify-between">
|
editor-dusk="ticket-body-editor"
|
||||||
<div>
|
/>
|
||||||
<p class="text-sm font-semibold text-zinc-100">Spellcheck writing area</p>
|
|
||||||
<p class="mt-1 text-xs text-zinc-400">
|
|
||||||
Misspelled words are underlined by the browser. Right-click or Ctrl-click an underlined word to choose a suggestion.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<span class="inline-flex items-center gap-2 rounded-full border border-emerald-500/30 bg-emerald-500/10 px-3 py-1 text-xs font-semibold text-emerald-200"
|
|
||||||
title="Use your browser context menu on underlined words to view spelling suggestions.">
|
|
||||||
<i class="fa-solid fa-spell-check" aria-hidden="true"></i>
|
|
||||||
Suggestions available
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<textarea id="body-editor" spellcheck="true" lang="en-GB" data-helpdesk-details-editor
|
|
||||||
data-dusk="ticket-body-editor" dusk="ticket-body-editor" rows="12"
|
|
||||||
class="block min-h-[18rem] w-full resize-y rounded-b-xl border-0 bg-zinc-950 px-4 py-3 text-sm leading-6 text-zinc-100 shadow-none outline-none placeholder:text-zinc-500 focus:ring-0"
|
|
||||||
placeholder="Describe the issue, expected outcome, steps to reproduce and any useful context...">{{ $body ?? '' }}</textarea>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<textarea id="body" spellcheck="true" lang="en-GB" wire:model="body" class="sr-only" tabindex="-1" aria-hidden="true"></textarea>
|
|
||||||
|
|
||||||
<p class="mt-2 flex items-center gap-2 text-xs font-medium text-zinc-400">
|
<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>
|
<i class="fa-solid fa-circle-info text-blue-400" aria-hidden="true"></i>
|
||||||
Use right-click or Ctrl-click on a red-underlined word to see browser spelling suggestions.
|
Rich formatting is available. Browser spelling suggestions appear by right-clicking or Ctrl-clicking red-underlined words.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
@error('body')
|
|
||||||
<p class="mt-2 text-sm text-red-500">{{ $message }}</p>
|
|
||||||
@enderror
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="lg:col-span-3 xl:col-span-6">
|
<div class="lg:col-span-3 xl:col-span-6">
|
||||||
@@ -323,97 +299,17 @@
|
|||||||
</form>
|
</form>
|
||||||
<script>
|
<script>
|
||||||
(() => {
|
(() => {
|
||||||
const initialisedEditors = window.helpdeskTicketCreateEditors ??= new WeakSet();
|
const resetTicketCreateFiles = () => {
|
||||||
|
document.querySelectorAll('.helpdesk-ticket-form #attachments').forEach((input) => {
|
||||||
const syncEditorToLivewire = (form, editor, bodyField) => {
|
input.value = '';
|
||||||
const value = (editor.value ?? editor.textContent ?? '').trim();
|
|
||||||
|
|
||||||
bodyField.value = value;
|
|
||||||
bodyField.dispatchEvent(new Event('input', { bubbles: true }));
|
|
||||||
bodyField.dispatchEvent(new Event('change', { bubbles: true }));
|
|
||||||
|
|
||||||
const livewireRoot = form.closest('[wire\:id]');
|
|
||||||
const livewireId = livewireRoot?.getAttribute('wire:id');
|
|
||||||
|
|
||||||
if (livewireId && window.Livewire?.find(livewireId)) {
|
|
||||||
window.Livewire.find(livewireId).set('body', value, false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const resetTicketCreateFormDom = () => {
|
|
||||||
document.querySelectorAll('.helpdesk-ticket-form').forEach((form) => {
|
|
||||||
const editor = form.querySelector('[data-helpdesk-details-editor]');
|
|
||||||
const bodyField = form.querySelector('#body');
|
|
||||||
const subjectField = form.querySelector('#subject');
|
|
||||||
const attachmentField = form.querySelector('#attachments');
|
|
||||||
|
|
||||||
if (editor) {
|
|
||||||
editor.value = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bodyField) {
|
|
||||||
bodyField.value = '';
|
|
||||||
bodyField.dispatchEvent(new Event('input', { bubbles: true }));
|
|
||||||
bodyField.dispatchEvent(new Event('change', { bubbles: true }));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (subjectField) {
|
|
||||||
subjectField.value = '';
|
|
||||||
subjectField.dispatchEvent(new Event('input', { bubbles: true }));
|
|
||||||
subjectField.dispatchEvent(new Event('change', { bubbles: true }));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (attachmentField) {
|
|
||||||
attachmentField.value = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (window.clearHelpdeskFormControls) {
|
|
||||||
window.clearHelpdeskFormControls();
|
|
||||||
}
|
|
||||||
|
|
||||||
const livewireRoot = form.closest('[wire\:id]');
|
|
||||||
const livewireId = livewireRoot?.getAttribute('wire:id');
|
|
||||||
const component = livewireId && window.Livewire?.find(livewireId);
|
|
||||||
|
|
||||||
if (component) {
|
|
||||||
component.set('subject', '', false);
|
|
||||||
component.set('body', '', false);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const initialiseTicketCreateEditor = () => {
|
document.addEventListener('helpdesk-form-cleared', resetTicketCreateFiles);
|
||||||
document.querySelectorAll('.helpdesk-ticket-form').forEach((form) => {
|
|
||||||
const editor = form.querySelector('[data-helpdesk-details-editor]');
|
|
||||||
const bodyField = form.querySelector('#body');
|
|
||||||
|
|
||||||
if (!editor || !bodyField || initialisedEditors.has(editor)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
initialisedEditors.add(editor);
|
|
||||||
|
|
||||||
const syncBody = () => syncEditorToLivewire(form, editor, bodyField);
|
|
||||||
|
|
||||||
editor.addEventListener('input', syncBody);
|
|
||||||
editor.addEventListener('keyup', syncBody);
|
|
||||||
editor.addEventListener('paste', () => window.setTimeout(syncBody, 0));
|
|
||||||
editor.addEventListener('blur', syncBody);
|
|
||||||
form.addEventListener('submit', syncBody, { capture: true });
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
document.addEventListener('helpdesk-form-cleared', resetTicketCreateFormDom);
|
|
||||||
document.addEventListener('helpdesk-editor-reset', resetTicketCreateFormDom);
|
|
||||||
|
|
||||||
if (window.Livewire?.on) {
|
if (window.Livewire?.on) {
|
||||||
window.Livewire.on('helpdesk-form-cleared', resetTicketCreateFormDom);
|
window.Livewire.on('helpdesk-form-cleared', resetTicketCreateFiles);
|
||||||
window.Livewire.on('helpdesk-editor-reset', resetTicketCreateFormDom);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', initialiseTicketCreateEditor);
|
|
||||||
document.addEventListener('livewire:navigated', initialiseTicketCreateEditor);
|
|
||||||
initialiseTicketCreateEditor();
|
|
||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
</div>
|
</div>
|
||||||
@@ -403,27 +403,40 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label for="ticket-comment-body"
|
<label for="ticket-comment-body-editor"
|
||||||
class="mb-2 block text-xs font-bold text-zinc-700 dark:text-zinc-200">Comment</label>
|
class="mb-2 block text-xs font-bold text-zinc-700 dark:text-zinc-200">Comment</label>
|
||||||
|
|
||||||
<div class="rounded-xl border border-zinc-300 bg-white shadow-sm focus-within:border-blue-500 focus-within:ring-2 focus-within:ring-blue-500 dark:border-zinc-700 dark:bg-zinc-950">
|
<div class="overflow-hidden rounded-xl border border-zinc-300 bg-white shadow-sm focus-within:border-blue-500 focus-within:ring-2 focus-within:ring-blue-500 dark:border-zinc-700 dark:bg-zinc-950">
|
||||||
<div class="flex flex-col gap-1 border-b border-zinc-200 px-4 py-3 dark:border-zinc-700 sm:flex-row sm:items-center sm:justify-between">
|
<div class="flex flex-wrap items-center gap-1 border-b border-zinc-200 bg-zinc-50 p-2 dark:border-zinc-700 dark:bg-zinc-900"
|
||||||
<p class="text-xs font-bold uppercase tracking-[0.16em] text-zinc-500 dark:text-zinc-400">Spellcheck reply</p>
|
data-helpdesk-html-toolbar="ticket-comment-body-editor">
|
||||||
<span class="inline-flex items-center gap-2 rounded-full border border-emerald-300 bg-emerald-50 px-3 py-1 text-xs font-bold text-emerald-800 dark:border-emerald-900 dark:bg-emerald-950/60 dark:text-emerald-100">
|
<button type="button" data-helpdesk-command="bold"
|
||||||
<i class="fa-solid fa-spell-check" aria-hidden="true"></i>
|
class="rounded-lg px-2 py-1 text-sm font-bold hover:bg-zinc-200 dark:hover:bg-zinc-800">B</button>
|
||||||
Right-click suggestions
|
<button type="button" data-helpdesk-command="italic"
|
||||||
</span>
|
class="rounded-lg px-2 py-1 text-sm italic hover:bg-zinc-200 dark:hover:bg-zinc-800">I</button>
|
||||||
|
<button type="button" data-helpdesk-command="underline"
|
||||||
|
class="rounded-lg px-2 py-1 text-sm underline hover:bg-zinc-200 dark:hover:bg-zinc-800">U</button>
|
||||||
|
<button type="button" data-helpdesk-command="insertUnorderedList"
|
||||||
|
class="rounded-lg px-2 py-1 text-sm hover:bg-zinc-200 dark:hover:bg-zinc-800">• List</button>
|
||||||
|
<button type="button" data-helpdesk-command="insertOrderedList"
|
||||||
|
class="rounded-lg px-2 py-1 text-sm hover:bg-zinc-200 dark:hover:bg-zinc-800">1. List</button>
|
||||||
|
<button type="button" data-helpdesk-block="blockquote"
|
||||||
|
class="rounded-lg px-2 py-1 text-sm hover:bg-zinc-200 dark:hover:bg-zinc-800">Quote</button>
|
||||||
|
<button type="button" data-helpdesk-block="code"
|
||||||
|
class="rounded-lg px-2 py-1 text-sm hover:bg-zinc-200 dark:hover:bg-zinc-800">Code</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<textarea dusk="comment-body" spellcheck="true" lang="en-GB" data-dusk="comment-body" id="ticket-comment-body"
|
<div id="ticket-comment-body-editor" dusk="comment-body" data-dusk="comment-body"
|
||||||
name="commentBody" required rows="8"
|
data-helpdesk-rich-editor data-helpdesk-sync-target="ticket-comment-body"
|
||||||
class="block min-h-[12rem] w-full resize-y rounded-b-xl border-0 bg-white p-4 text-sm leading-6 text-zinc-900 shadow-none focus:outline-none focus:ring-0 dark:bg-zinc-950 dark:text-zinc-100"
|
contenteditable="true" spellcheck="true" lang="en-GB" autocorrect="on" autocomplete="on"
|
||||||
placeholder="Write a public reply or internal note. Right-click or Ctrl-click underlined words for spelling suggestions.">{{ strip_tags($oldCommentBody) }}</textarea>
|
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>
|
||||||
|
|
||||||
|
<textarea id="ticket-comment-body" name="commentBody" required class="sr-only" tabindex="-1" aria-hidden="true">{{ $oldCommentBody }}</textarea>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p class="mt-2 flex items-center gap-2 text-xs font-medium text-zinc-500 dark:text-zinc-400">
|
<p class="mt-2 flex items-center gap-2 text-xs font-medium text-zinc-500 dark:text-zinc-400">
|
||||||
<i class="fa-solid fa-circle-info text-blue-500" aria-hidden="true"></i>
|
<i class="fa-solid fa-circle-info text-blue-500" aria-hidden="true"></i>
|
||||||
Browser suggestions appear from the context menu on underlined words.
|
Rich formatting is available. Browser suggestions appear from the context menu on underlined words.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -211,34 +211,65 @@
|
|||||||
</details>
|
</details>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
document.addEventListener('DOMContentLoaded', function () {
|
(() => {
|
||||||
document.querySelectorAll('[data-helpdesk-status-form]').forEach(function (form) {
|
const initialiseCloseTicketDialogs = () => {
|
||||||
const statusSelect = form.querySelector('[data-dusk="ticket-show-status"]');
|
document.querySelectorAll('[data-helpdesk-status-form]').forEach((form) => {
|
||||||
const dialog = form.querySelector('[data-helpdesk-close-ticket-dialog]');
|
if (form.dataset.helpdeskCloseDialogInitialised === '1') {
|
||||||
const comment = form.querySelector('[data-helpdesk-closure-comment]');
|
|
||||||
const cancel = form.querySelector('[data-helpdesk-close-dialog-cancel]');
|
|
||||||
|
|
||||||
if (!statusSelect || !dialog || !comment) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
form.addEventListener('submit', function (event) {
|
|
||||||
const selectedOption = statusSelect.options[statusSelect.selectedIndex];
|
|
||||||
const isClosing = selectedOption?.dataset?.isClosed === '1';
|
|
||||||
|
|
||||||
if (!isClosing || comment.value.trim().length >= 10) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
event.preventDefault();
|
form.dataset.helpdeskCloseDialogInitialised = '1';
|
||||||
dialog.showModal();
|
|
||||||
comment.focus();
|
|
||||||
});
|
|
||||||
|
|
||||||
cancel?.addEventListener('click', function () {
|
const statusSelect = form.querySelector('[data-dusk="ticket-show-status"]');
|
||||||
dialog.close();
|
const dialog = form.querySelector('[data-helpdesk-close-ticket-dialog]');
|
||||||
|
const comment = form.querySelector('[data-helpdesk-closure-comment]');
|
||||||
|
const cancel = form.querySelector('[data-helpdesk-close-dialog-cancel]');
|
||||||
|
const originalStatus = statusSelect?.value || '';
|
||||||
|
|
||||||
|
if (!statusSelect || !dialog || !comment) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const selectedStatusIsClosed = () => {
|
||||||
|
const selectedOption = statusSelect.options[statusSelect.selectedIndex];
|
||||||
|
|
||||||
|
return selectedOption?.dataset?.isClosed === '1';
|
||||||
|
};
|
||||||
|
|
||||||
|
const openDialog = () => {
|
||||||
|
if (!dialog.open) {
|
||||||
|
dialog.showModal();
|
||||||
|
}
|
||||||
|
|
||||||
|
window.setTimeout(() => comment.focus(), 50);
|
||||||
|
};
|
||||||
|
|
||||||
|
statusSelect.addEventListener('change', () => {
|
||||||
|
if (selectedStatusIsClosed()) {
|
||||||
|
openDialog();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
form.addEventListener('submit', (event) => {
|
||||||
|
if (!selectedStatusIsClosed() || comment.value.trim().length >= 10) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
event.preventDefault();
|
||||||
|
openDialog();
|
||||||
|
});
|
||||||
|
|
||||||
|
cancel?.addEventListener('click', () => {
|
||||||
|
dialog.close();
|
||||||
|
statusSelect.value = originalStatus;
|
||||||
|
statusSelect.dispatchEvent(new Event('change', { bubbles: true }));
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
};
|
||||||
});
|
|
||||||
|
document.addEventListener('DOMContentLoaded', initialiseCloseTicketDialogs);
|
||||||
|
document.addEventListener('livewire:navigated', initialiseCloseTicketDialogs);
|
||||||
|
initialiseCloseTicketDialogs();
|
||||||
|
})();
|
||||||
</script>
|
</script>
|
||||||
@endcan
|
@endcan
|
||||||
|
|||||||
@@ -174,3 +174,13 @@
|
|||||||
- Updated README guidance to explain how browser spellcheck suggestions are accessed.
|
- Updated README guidance to explain how browser spellcheck suggestions are accessed.
|
||||||
- Updated regression coverage for visible spellcheck suggestion guidance.
|
- Updated regression coverage for visible spellcheck suggestion guidance.
|
||||||
- Preserved append-only changelog history.
|
- Preserved append-only changelog history.
|
||||||
|
|
||||||
|
- version: 1.9.46
|
||||||
|
date: 2026-06-23
|
||||||
|
changes:
|
||||||
|
- Restored rich text HTML controls for ticket details and main ticket replies.
|
||||||
|
- Enabled inline browser spellcheck on contenteditable rich editor areas without replacing the editor with plain textareas.
|
||||||
|
- Fixed ticket create clear action so configured defaults are preserved while subject, details, tags and attachments are cleared.
|
||||||
|
- Fixed close-ticket modal so selecting a closed status opens the professional closure prompt on the first interaction.
|
||||||
|
- Preserved the mandatory closure comment workflow and public/internal closure visibility behaviour.
|
||||||
|
- Added regression coverage notes for rich editor, clear defaults and close-modal workflow.
|
||||||
|
|||||||
@@ -22,5 +22,5 @@
|
|||||||
"Modules\\Helpdesk\\Providers\\HelpdeskServiceProvider"
|
"Modules\\Helpdesk\\Providers\\HelpdeskServiceProvider"
|
||||||
],
|
],
|
||||||
"files": [],
|
"files": [],
|
||||||
"version": "1.9.45"
|
"version": "1.9.46"
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user