now with git support
This commit is contained in:
@@ -134,10 +134,31 @@ final class TicketCreate extends Component
|
||||
|
||||
$this->subject = '';
|
||||
$this->body = '';
|
||||
$this->due_at = null;
|
||||
$this->tag_ids = [];
|
||||
$this->attachments = [];
|
||||
|
||||
$this->dispatch('helpdesk-form-cleared');
|
||||
$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->applyDefaults();
|
||||
|
||||
$this->dispatch('helpdesk-form-cleared', values: [
|
||||
'company_id' => $this->company_id,
|
||||
'board_id' => $this->board_id,
|
||||
'priority_id' => $this->priority_id,
|
||||
'category_id' => $this->category_id,
|
||||
'project_id' => $this->project_id,
|
||||
'product_id' => $this->product_id,
|
||||
'team_id' => $this->team_id,
|
||||
'due_at' => $this->due_at,
|
||||
'tag_ids' => $this->tag_ids,
|
||||
]);
|
||||
$this->dispatch('helpdesk-editor-reset', model: 'body');
|
||||
}
|
||||
|
||||
|
||||
@@ -173,23 +173,36 @@ final class TicketEdit extends Component
|
||||
$this->resetErrorBag();
|
||||
$this->resetValidation();
|
||||
|
||||
$this->subject = '';
|
||||
$this->body = '';
|
||||
$this->company_id = null;
|
||||
$this->status_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->agent_id = null;
|
||||
$this->due_at = null;
|
||||
$this->tag_ids = [];
|
||||
$this->ticket = $this->freshTicket($this->ticket);
|
||||
$this->company_id = $this->ticket->company_id;
|
||||
$this->subject = $this->ticket->subject;
|
||||
$this->body = $this->ticket->body;
|
||||
$this->status_id = $this->ticket->status_id;
|
||||
$this->board_id = $this->ticket->board_id;
|
||||
$this->priority_id = $this->ticket->priority_id;
|
||||
$this->category_id = $this->ticket->category_id;
|
||||
$this->project_id = $this->ticket->project_id;
|
||||
$this->product_id = $this->ticket->product_id;
|
||||
$this->team_id = $this->ticket->team_id;
|
||||
$this->agent_id = $this->ticket->agent_id;
|
||||
$this->due_at = $this->ticket->due_at?->format('Y-m-d');
|
||||
$this->tag_ids = $this->ticket->tags->pluck('id')->map(fn ($id): int => (int) $id)->all();
|
||||
$this->attachments = [];
|
||||
|
||||
$this->dispatch('helpdesk-form-cleared');
|
||||
$this->dispatch('helpdesk-editor-reset', model: 'body');
|
||||
$this->dispatch('helpdesk-form-cleared', values: [
|
||||
'company_id' => $this->company_id,
|
||||
'status_id' => $this->status_id,
|
||||
'board_id' => $this->board_id,
|
||||
'priority_id' => $this->priority_id,
|
||||
'category_id' => $this->category_id,
|
||||
'project_id' => $this->project_id,
|
||||
'product_id' => $this->product_id,
|
||||
'team_id' => $this->team_id,
|
||||
'agent_id' => $this->agent_id,
|
||||
'due_at' => $this->due_at,
|
||||
'tag_ids' => $this->tag_ids,
|
||||
]);
|
||||
$this->dispatch('helpdesk-editor-reset', model: 'body', value: $this->body);
|
||||
}
|
||||
|
||||
public function render(): View
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
<div {{ $attributes->whereDoesntStartWith('wire:model')->merge(['class' => 'space-y-2']) }}
|
||||
@if ($model) data-helpdesk-editor-model="{{ $model }}" @endif
|
||||
x-on:helpdesk-editor-reset.window="if ($event.detail.model === model) clear()"
|
||||
x-on:helpdesk-editor-reset.window="if ($event.detail.model === model) clear($event.detail.value || '')"
|
||||
x-on:helpdesk-editor-sync.window="if ($event.detail.model === model) syncToLivewire()"
|
||||
x-data="{
|
||||
model: @js($model),
|
||||
@@ -54,12 +54,12 @@
|
||||
|
||||
this.$nextTick(() => this.syncToHiddenInput());
|
||||
},
|
||||
clear() {
|
||||
this.value = '';
|
||||
this.$refs.editor.innerHTML = '';
|
||||
clear(value = '') {
|
||||
this.value = value || '';
|
||||
this.$refs.editor.innerHTML = this.value;
|
||||
|
||||
if (this.model) {
|
||||
this.$wire.set(this.model, '', false);
|
||||
this.$wire.set(this.model, this.value, false);
|
||||
}
|
||||
},
|
||||
init() {
|
||||
@@ -103,7 +103,7 @@
|
||||
class="rounded-lg px-2 py-1 text-sm hover:bg-zinc-200 dark:hover:bg-zinc-800">Clear</button>
|
||||
</div>
|
||||
|
||||
<div x-ref="editor" contenteditable="true" spellcheck="true" lang="en-GB" autocapitalize="sentences" autocorrect="on" autocomplete="off" inputmode="text"
|
||||
<div x-ref="editor" contenteditable="true" spellcheck="true" lang="en-GB" autocapitalize="sentences" autocorrect="on" inputmode="text" aria-multiline="true" role="textbox"
|
||||
@if ($editorDusk) data-dusk="{{ $editorDusk }}" dusk="{{ $editorDusk }}" @endif
|
||||
x-on:paste="handlePaste($event)" x-on:blur="syncToHiddenInput()"
|
||||
class="helpdesk-rich-editor 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"
|
||||
|
||||
@@ -330,28 +330,33 @@
|
||||
@enderror
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center justify-end gap-3 border-t border-zinc-700 bg-zinc-900 px-6 py-4">
|
||||
<button type="button" wire:click="clearForm" wire:loading.attr="disabled" wire:target="clearForm"
|
||||
class="inline-flex items-center gap-2 rounded-xl bg-red-600 px-4 py-2 text-sm font-semibold text-white shadow-sm hover:bg-red-700 disabled:cursor-not-allowed disabled:opacity-50"
|
||||
data-dusk="ticket-create-clear" dusk="ticket-create-clear">
|
||||
<i class="fa-solid fa-eraser" aria-hidden="true"></i>
|
||||
<span wire:loading.remove wire:target="clearForm">Clear</span>
|
||||
<span wire:loading wire:target="clearForm">Clearing...</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<a href="{{ route('helpdesk.tickets.index') }}" wire:navigate
|
||||
class="rounded-xl bg-blue-600 px-4 py-2 text-sm font-semibold text-white shadow-sm hover:bg-blue-700">
|
||||
Cancel
|
||||
</a>
|
||||
<div class="border-t border-zinc-700 bg-zinc-900/95 px-6 py-4">
|
||||
<div class="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-end">
|
||||
<a href="{{ route('helpdesk.tickets.index') }}" wire:navigate
|
||||
class="inline-flex items-center justify-center gap-2 rounded-xl bg-blue-600 px-4 py-2.5 text-sm font-semibold text-white shadow-sm transition hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500/70 focus:ring-offset-2 focus:ring-offset-zinc-950">
|
||||
<i class="fa-solid fa-xmark" aria-hidden="true"></i>
|
||||
<span>Cancel</span>
|
||||
</a>
|
||||
|
||||
<button type="submit"
|
||||
class="inline-flex items-center gap-2 rounded-xl bg-green-600 px-5 py-2 text-sm font-semibold text-white shadow-sm hover:bg-green-700 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">
|
||||
<i class="fa-regular fa-floppy-disk" aria-hidden="true"></i>
|
||||
<span wire:loading.remove wire:target="save,attachments">Create Ticket</span>
|
||||
<span wire:loading wire:target="attachments">Uploading...</span>
|
||||
<span wire:loading wire:target="save">Creating...</span>
|
||||
</button>
|
||||
<button type="button" wire:click="clearForm" wire:loading.attr="disabled" wire:target="clearForm"
|
||||
class="inline-flex items-center justify-center gap-2 rounded-xl bg-amber-600 px-4 py-2.5 text-sm font-semibold text-white shadow-sm transition hover:bg-amber-700 disabled:cursor-not-allowed disabled:opacity-50 focus:outline-none focus:ring-2 focus:ring-amber-500/70 focus:ring-offset-2 focus:ring-offset-zinc-950"
|
||||
data-dusk="ticket-create-clear" dusk="ticket-create-clear">
|
||||
<i class="fa-solid fa-rotate-left" aria-hidden="true"></i>
|
||||
<span wire:loading.remove wire:target="clearForm">Reset form</span>
|
||||
<span wire:loading wire:target="clearForm">Resetting...</span>
|
||||
</button>
|
||||
|
||||
<button type="submit"
|
||||
class="inline-flex items-center justify-center gap-2 rounded-xl bg-green-600 px-5 py-2.5 text-sm font-semibold text-white shadow-sm transition hover:bg-green-700 disabled:cursor-not-allowed disabled:opacity-50 focus:outline-none focus:ring-2 focus:ring-green-500/70 focus:ring-offset-2 focus:ring-offset-zinc-950"
|
||||
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">
|
||||
<i class="fa-regular fa-floppy-disk" aria-hidden="true"></i>
|
||||
<span wire:loading.remove wire:target="save,attachments">Create Ticket</span>
|
||||
<span wire:loading wire:target="attachments">Uploading...</span>
|
||||
<span wire:loading wire:target="save">Creating...</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
@@ -392,11 +397,36 @@
|
||||
};
|
||||
};
|
||||
|
||||
const resetTicketCreateFiles = () => {
|
||||
const resetTicketCreateFiles = (event) => {
|
||||
document.querySelectorAll('.helpdesk-ticket-form #attachments').forEach((input) => {
|
||||
input.value = '';
|
||||
input.dispatchEvent(new Event('change', { bubbles: true }));
|
||||
});
|
||||
|
||||
const values = event?.detail?.values || event?.values || {};
|
||||
|
||||
document.querySelectorAll('.helpdesk-ticket-form [data-helpdesk-select2][data-wire-model]').forEach((select) => {
|
||||
const model = select.dataset.wireModel;
|
||||
const value = values[model] ?? '';
|
||||
|
||||
select.value = value === null ? '' : String(value);
|
||||
select.dispatchEvent(new Event('change', { bubbles: true }));
|
||||
|
||||
if (window.jQuery && window.jQuery.fn?.select2) {
|
||||
window.jQuery(select).val(select.value || null).trigger('change.select2');
|
||||
}
|
||||
});
|
||||
|
||||
document.querySelectorAll('.helpdesk-ticket-form [data-helpdesk-flatpickr]').forEach((input) => {
|
||||
const model = input.getAttribute('wire:model') || input.dataset.wireModel || input.id;
|
||||
const value = values[model] ?? '';
|
||||
input.value = value || '';
|
||||
input.dispatchEvent(new Event('change', { bubbles: true }));
|
||||
|
||||
if (input._flatpickr) {
|
||||
input._flatpickr.setDate(value || null, false);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const appendPastedFiles = (event) => {
|
||||
|
||||
@@ -400,25 +400,67 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-end gap-3 border-t border-zinc-700 bg-zinc-900 px-6 py-4">
|
||||
<button type="button" wire:click="clearForm"
|
||||
class="rounded-xl bg-red-600 px-4 py-2 text-sm font-semibold text-white shadow-sm hover:bg-red-700">
|
||||
Clear
|
||||
</button>
|
||||
<div class="border-t border-zinc-700 bg-zinc-900/95 px-6 py-4">
|
||||
<div class="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-end">
|
||||
<a href="{{ route('helpdesk.tickets.show', $ticket) }}" wire:navigate
|
||||
class="inline-flex items-center justify-center gap-2 rounded-xl bg-blue-600 px-4 py-2.5 text-sm font-semibold text-white shadow-sm transition hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500/70 focus:ring-offset-2 focus:ring-offset-zinc-950">
|
||||
<i class="fa-solid fa-xmark" aria-hidden="true"></i>
|
||||
<span>Cancel</span>
|
||||
</a>
|
||||
|
||||
<a href="{{ route('helpdesk.tickets.show', $ticket) }}" wire:navigate
|
||||
class="rounded-xl bg-blue-600 px-4 py-2 text-sm font-semibold text-white shadow-sm hover:bg-blue-700">
|
||||
Cancel
|
||||
</a>
|
||||
<button type="button" wire:click="clearForm" wire:loading.attr="disabled" wire:target="clearForm"
|
||||
class="inline-flex items-center justify-center gap-2 rounded-xl bg-amber-600 px-4 py-2.5 text-sm font-semibold text-white shadow-sm transition hover:bg-amber-700 disabled:cursor-not-allowed disabled:opacity-50 focus:outline-none focus:ring-2 focus:ring-amber-500/70 focus:ring-offset-2 focus:ring-offset-zinc-950">
|
||||
<i class="fa-solid fa-rotate-left" aria-hidden="true"></i>
|
||||
<span wire:loading.remove wire:target="clearForm">Reset changes</span>
|
||||
<span wire:loading wire:target="clearForm">Resetting...</span>
|
||||
</button>
|
||||
|
||||
<button type="submit"
|
||||
class="inline-flex items-center gap-2 rounded-xl bg-green-600 px-5 py-2 text-sm font-semibold text-white shadow-sm hover:bg-green-700 disabled:cursor-not-allowed disabled:opacity-50"
|
||||
data-dusk="ticket-edit-submit" wire:loading.attr="disabled">
|
||||
<i class="fa-regular fa-floppy-disk" aria-hidden="true"></i>
|
||||
<span wire:loading.remove>Save Ticket</span>
|
||||
<span wire:loading>Saving...</span>
|
||||
</button>
|
||||
<button type="submit"
|
||||
class="inline-flex items-center justify-center gap-2 rounded-xl bg-green-600 px-5 py-2.5 text-sm font-semibold text-white shadow-sm transition hover:bg-green-700 disabled:cursor-not-allowed disabled:opacity-50 focus:outline-none focus:ring-2 focus:ring-green-500/70 focus:ring-offset-2 focus:ring-offset-zinc-950"
|
||||
data-dusk="ticket-edit-submit" wire:loading.attr="disabled">
|
||||
<i class="fa-regular fa-floppy-disk" aria-hidden="true"></i>
|
||||
<span wire:loading.remove>Save Ticket</span>
|
||||
<span wire:loading>Saving...</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<script data-helpdesk-edit-form-cleared-reset>
|
||||
(() => {
|
||||
const resetTicketEditControls = (event) => {
|
||||
const values = event?.detail?.values || event?.values || {};
|
||||
|
||||
document.querySelectorAll('.helpdesk-ticket-form [data-helpdesk-select2][data-wire-model]').forEach((select) => {
|
||||
const model = select.dataset.wireModel;
|
||||
const value = values[model] ?? '';
|
||||
|
||||
select.value = value === null ? '' : String(value);
|
||||
select.dispatchEvent(new Event('change', { bubbles: true }));
|
||||
|
||||
if (window.jQuery && window.jQuery.fn?.select2) {
|
||||
window.jQuery(select).val(select.value || null).trigger('change.select2');
|
||||
}
|
||||
});
|
||||
|
||||
document.querySelectorAll('.helpdesk-ticket-form [data-helpdesk-flatpickr]').forEach((input) => {
|
||||
const model = input.getAttribute('wire:model') || input.dataset.wireModel || input.id;
|
||||
const value = values[model] ?? '';
|
||||
input.value = value || '';
|
||||
input.dispatchEvent(new Event('change', { bubbles: true }));
|
||||
|
||||
if (input._flatpickr) {
|
||||
input._flatpickr.setDate(value || null, false);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
document.addEventListener('helpdesk-form-cleared', resetTicketEditControls);
|
||||
|
||||
if (window.Livewire?.on) {
|
||||
window.Livewire.on('helpdesk-form-cleared', resetTicketEditControls);
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -387,3 +387,15 @@
|
||||
- Replaced the broken artwork area with inline Helpdesk workflow artwork using Blade and Tailwind only.
|
||||
- Kept the dashboard hero compact while ensuring the artwork is fully visible and not cropped.
|
||||
- Preserved append-only changelog history.
|
||||
|
||||
- version: 1.10.12
|
||||
date: 2026-06-24
|
||||
type: bugfix
|
||||
summary: Fix Helpdesk ticket create and edit form actions and reset behaviour.
|
||||
changes:
|
||||
- Restored the missing grid closing wrapper so create form actions render in the footer rather than inside the form grid.
|
||||
- Repositioned Cancel, Reset and Create/Save actions to the right-hand footer on create and edit screens.
|
||||
- Changed create reset to clear user-entered values and then reapply configured default dropdown values.
|
||||
- Changed edit reset to restore the saved ticket values rather than blanking the ticket.
|
||||
- Kept rich editor spellcheck enabled and preserved submit-time Livewire synchronisation without keypress syncing.
|
||||
- Preserved append-only changelog history.
|
||||
|
||||
@@ -22,5 +22,5 @@
|
||||
"Modules\\Helpdesk\\Providers\\HelpdeskServiceProvider"
|
||||
],
|
||||
"files": [],
|
||||
"version": "1.10.10"
|
||||
"version": "1.10.12"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Controllers\Git;
|
||||
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Routing\Controller;
|
||||
|
||||
final class GiteaWebhookController extends Controller
|
||||
{
|
||||
/**
|
||||
* Handle an incoming Gitea webhook delivery.
|
||||
*/
|
||||
public function __invoke(Request $request): JsonResponse
|
||||
{
|
||||
return response()->json([
|
||||
'message' => 'Gitea webhook received.',
|
||||
'event' => $request->header('X-Gitea-Event'),
|
||||
'delivery' => $request->header('X-Gitea-Delivery'),
|
||||
'payload' => $request->json()->all(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@ use Modules\Platform\app\Http\Middleware\EnsureLicensedTenant;
|
||||
return Application::configure(basePath: dirname(__DIR__))
|
||||
->withRouting(
|
||||
web: __DIR__ . '/../routes/web.php',
|
||||
api: __DIR__ . '/../routes/api.php',
|
||||
commands: __DIR__ . '/../routes/console.php',
|
||||
health: '/up',
|
||||
)
|
||||
|
||||
+4
-1
@@ -27,7 +27,10 @@ return [
|
||||
'secret' => env('AWS_SECRET_ACCESS_KEY'),
|
||||
'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
|
||||
],
|
||||
|
||||
'gitea' => [
|
||||
'webhook_secret' => env('GITEA_WEBHOOK_SECRET'),
|
||||
'webhook_authorization' => env('GITEA_WEBHOOK_AUTHORIZATION'),
|
||||
],
|
||||
'slack' => [
|
||||
'notifications' => [
|
||||
'bot_user_oauth_token' => env('SLACK_BOT_USER_OAUTH_TOKEN'),
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
use App\Http\Controllers\Git\GiteaWebhookController;
|
||||
|
||||
Route::post('/git/gitea/webhook', GiteaWebhookController::class)
|
||||
|
||||
->name('git.gitea.webhook');
|
||||
Reference in New Issue
Block a user