Skip to content

Commit

Permalink
Add Nova Artisan Card for horizon:clear
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisbjr committed Sep 17, 2024
1 parent a659a5e commit 802d1ad
Show file tree
Hide file tree
Showing 8 changed files with 281 additions and 1 deletion.
2 changes: 1 addition & 1 deletion dist/js/card.js

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions resources/js/card.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ import MigrateFreshCard from "./components/MigrateFresh/MigrateFreshCard.vue";
import MaintenanceModeCard from "./components/MaintenanceMode/MaintenanceModeCard.vue";
import MaintenanceModeWarningCard from "./components/MaintenanceMode/MaintenanceModeWarningCard.vue";
import DatabaseBackupCard from "./components/DatabaseBackup/DatabaseBackupCard.vue";
import HorizonClearCard from "./components/HorizonClear/HorizonClearCard.vue";

Nova.booting((app, store) => {
app.component('nova-artisan-migrate-fresh-card', MigrateFreshCard)
app.component('nova-artisan-maintenance-mode-card', MaintenanceModeCard)
app.component('nova-artisan-maintenance-mode-warning-card', MaintenanceModeWarningCard)
app.component('nova-artisan-database-backup-card', DatabaseBackupCard)
app.component('nova-artisan-horizon-clear-card', HorizonClearCard)
})
78 changes: 78 additions & 0 deletions resources/js/components/HorizonClear/HorizonClearCard.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<template>
<Card class="flex flex-col justify-center min-h-8">
<div class="px-4 py-4 flex justify-between items-center">
<div class="flex-grow pr-2">
<h3 class="text-lg font-bold">
Horizon Clear
</h3>
<p>This will delete all jobs from a specified queue.</p>
</div>
<div class="shrink-0 ml-4">
<Button
@click="showModal = true"
state="default"
>
Clear Queue
</Button>
</div>
</div>
<HorizonClearModal
:show="showModal"
title="Horizon Clear"
message="This will clear all jobs from Horizon queue."
@confirm="handleConfirm"
confirmButtonState="danger"
confirmButtonText="Clear Queue"
@close="handleClose"
/>
</Card>
</template>

<script>
import HorizonClearModal from "./Modals/HorizonClearModal.vue";
import {Button} from "laravel-nova-ui";
export default {
components: {
Button,
HorizonClearModal,
},
props: [
'card',
// The following props are only available on resource detail cards...
// 'resource',
// 'resourceId',
// 'resourceName',
],
data() {
return {
loading: false,
showModal: false,
};
},
methods: {
async handleConfirm(queue) {
this.loading = true;
try {
const response = await Nova.request()
.post('/nova-vendor/nova-artisan-cards/artisan/horizon-clear', {
'queue': queue,
});
// Redirect user back to /
alert(response.data.output);
} catch (error) {
console.error('Error clearing horizon queue:', error);
// Handle error here
alert('Horizon clear experienced an error');
} finally {
this.showModal = false;
this.loading = false;
}
},
handleClose() {
this.showModal = false;
},
},
};
</script>
110 changes: 110 additions & 0 deletions resources/js/components/HorizonClear/Modals/HorizonClearModal.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
<template>
<Modal :show="show" size="sm">
<form
@submit.prevent="handleConfirm"
class="bg-white dark:bg-gray-800 rounded-lg shadow-lg overflow-hidden"
style="width: 460px"
>
<slot>
<ModalHeader v-text="title"/>
<ModalContent>
<p class="leading-normal">
{{ message }}
</p>

<div class="action">
<div
class="space-y-2 md:flex @md/modal:flex md:flex-row @md/modal:flex-row md:space-y-0 @md/modal:space-y-0 py-5"
>
<div class="w-full px-6 md:mt-2 @md/modal:mt-2 md:px-8 @md/modal:px-8 md:w-1/5 @md/modal:w-1/5">
<label for="test-default-text-field" class="inline-block leading-tight space-x-1">
<span>Queue</span>
</label>
</div>
<div class="w-full space-y-2 md:w-3/5 @md/modal:w-3/5">
<div class="space-y-1">
<input type="text" placeholder="default"
v-model="queue"
class="w-full form-control form-input form-control-bordered"
id="test-default-text-field" maxlength="-1">
</div>
</div>
</div>
</div>
</ModalContent>
</slot>

<ModalFooter>
<div class="ml-auto">
<LinkButton
type="button"
dusk="cancel-restore-button"
@click.prevent="handleClose"
class="mr-3"
>
{{ __('Cancel') }}
</LinkButton>

<Button
type="submit"
ref="confirmButton"
:loading="working"
:state="confirmButtonState"
>
{{ confirmButtonText }}
</Button>
</div>
</ModalFooter>
</form>
</Modal>
</template>

<script>
import {Button} from 'laravel-nova-ui'
export default {
components: {
Button,
},
emits: ['confirm', 'close'],
props: {
show: {type: Boolean, default: false},
message: {type: String, default: 'Are you sure you want to do this action?'},
title: {type: String, default: 'Confirm Action'},
confirmButtonText: {type: String, default: 'Confirm'},
confirmButtonState: {type: Button.ButtonState, default: 'default'},
},
data: () => ({
working: false,
queue: "default",
}),
watch: {
show(showing) {
if (showing === false) {
this.working = false
}
},
},
methods: {
handleClose() {
this.$emit('close')
this.working = false
},
handleConfirm() {
// If the secret is blank, show an alert
if (this.queue === '') {
alert('Queue cannot be blank')
return
}
this.$emit('confirm', this.queue)
this.working = true
},
},
}
</script>
3 changes: 3 additions & 0 deletions routes/api.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<?php

use Coreproc\NovaArtisanCards\DatabaseBackup\DatabaseBackupController;
use Coreproc\NovaArtisanCards\HorizonClear\HorizonClearController;
use Coreproc\NovaArtisanCards\MaintenanceMode\MaintenanceModeController;
use Coreproc\NovaArtisanCards\MigrateFresh\MigrateFreshController;
use Illuminate\Support\Facades\Route;
Expand All @@ -23,3 +24,5 @@
Route::post('/artisan/up', [MaintenanceModeController::class, 'up']);

Route::post('/artisan/database-backup', DatabaseBackupController::class);

Route::post('/artisan/horizon-clear', [HorizonClearController::class, 'clear']);
26 changes: 26 additions & 0 deletions src/HorizonClear/HorizonClearCard.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

namespace Coreproc\NovaArtisanCards\HorizonClear;

use Illuminate\Support\Facades\Cache;
use Laravel\Nova\Card;

class HorizonClearCard extends Card
{
/**
* The width of the card (1/3, 1/2, or full).
*
* @var string
*/
public $width = 'full';

/**
* Get the component name for the element.
*
* @return string
*/
public function component()
{
return 'nova-artisan-horizon-clear-card';
}
}
41 changes: 41 additions & 0 deletions src/HorizonClear/HorizonClearController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php

namespace Coreproc\NovaArtisanCards\HorizonClear;

use Coreproc\NovaArtisanCards\HorizonClear\Requests\HorizonClearRequest;
use Illuminate\Http\JsonResponse;
use Illuminate\Routing\Controller;
use Symfony\Component\Process\Exception\ProcessFailedException;
use Symfony\Component\Process\Process;

class HorizonClearController extends Controller
{
public function clear(HorizonClearRequest $horizonClearRequest): JsonResponse
{
$queue = $horizonClearRequest->get('queue', 'default');

$command = ['php', base_path('artisan'), 'horizon:clear'];
if ($queue !== 'default') {
$command[] = '--queue=' . escapeshellarg($queue);
}

$process = new Process($command);

try {
$process->mustRun();

return response()->json([
'success' => true,
'message' => 'Horizon queue cleared successfully.',
'output' => $process->getOutput()
]);
} catch (ProcessFailedException $exception) {
return response()->json([
'success' => false,
'message' => 'Failed to clear Horizon queue.',
'error' => $exception->getMessage(),
'output' => $process->getOutput()
], 500);
}
}
}
20 changes: 20 additions & 0 deletions src/HorizonClear/Requests/HorizonClearRequest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

namespace Coreproc\NovaArtisanCards\HorizonClear\Requests;

use Illuminate\Foundation\Http\FormRequest;

class HorizonClearRequest extends FormRequest
{
public function rules(): array
{
return [
'queue' => ['required', 'string', 'max:255']
];
}

public function authorize(): bool
{
return true;
}
}

0 comments on commit 802d1ad

Please sign in to comment.