mirror of
https://github.com/vitodeploy/vito.git
synced 2025-04-19 18:01:37 +00:00
add log viewer for queues
This commit is contained in:
parent
fd93f3dd47
commit
7a6dcb5654
13
app/Actions/Queue/GetQueueLogs.php
Normal file
13
app/Actions/Queue/GetQueueLogs.php
Normal file
@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace App\Actions\Queue;
|
||||
|
||||
use App\Models\Queue;
|
||||
|
||||
class GetQueueLogs
|
||||
{
|
||||
public function getLogs(Queue $queue): string
|
||||
{
|
||||
return $queue->server->processManager()->handler()->getLogs($queue->getLogFile());
|
||||
}
|
||||
}
|
@ -4,6 +4,7 @@
|
||||
|
||||
use App\Actions\Queue\CreateQueue;
|
||||
use App\Actions\Queue\DeleteQueue;
|
||||
use App\Actions\Queue\GetQueueLogs;
|
||||
use App\Actions\Queue\ManageQueue;
|
||||
use App\Facades\Toast;
|
||||
use App\Helpers\HtmxResponse;
|
||||
@ -51,4 +52,9 @@ public function destroy(Server $server, Site $site, Queue $queue): RedirectRespo
|
||||
|
||||
return back();
|
||||
}
|
||||
|
||||
public function logs(Server $server, Site $site, Queue $queue): RedirectResponse
|
||||
{
|
||||
return back()->with('content', app(GetQueueLogs::class)->getLogs($queue));
|
||||
}
|
||||
}
|
||||
|
35
package-lock.json
generated
35
package-lock.json
generated
@ -20,6 +20,7 @@
|
||||
"prettier-plugin-tailwindcss": "^0.5.11",
|
||||
"pusher-js": "^4.3.1",
|
||||
"tailwindcss": "^3.1.0",
|
||||
"tippy.js": "^6.3.7",
|
||||
"toastr": "^2.1.4",
|
||||
"vite": "^4.5.2"
|
||||
}
|
||||
@ -465,6 +466,16 @@
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/@popperjs/core": {
|
||||
"version": "2.11.8",
|
||||
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
|
||||
"integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==",
|
||||
"dev": true,
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/popperjs"
|
||||
}
|
||||
},
|
||||
"node_modules/@ryangjchandler/alpine-clipboard": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@ryangjchandler/alpine-clipboard/-/alpine-clipboard-2.2.0.tgz",
|
||||
@ -1879,6 +1890,15 @@
|
||||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/tippy.js": {
|
||||
"version": "6.3.7",
|
||||
"resolved": "https://registry.npmjs.org/tippy.js/-/tippy.js-6.3.7.tgz",
|
||||
"integrity": "sha512-E1d3oP2emgJ9dRQZdf3Kkn0qJgI6ZLpyS5z6ZkY1DF3kaQaBsGZsndEpHwx+eC+tYM41HaSNvNtLx8tU57FzTQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@popperjs/core": "^2.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/to-regex-range": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
||||
@ -2294,6 +2314,12 @@
|
||||
"fastq": "^1.6.0"
|
||||
}
|
||||
},
|
||||
"@popperjs/core": {
|
||||
"version": "2.11.8",
|
||||
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
|
||||
"integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==",
|
||||
"dev": true
|
||||
},
|
||||
"@ryangjchandler/alpine-clipboard": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@ryangjchandler/alpine-clipboard/-/alpine-clipboard-2.2.0.tgz",
|
||||
@ -3225,6 +3251,15 @@
|
||||
"thenify": ">= 3.1.0 < 4"
|
||||
}
|
||||
},
|
||||
"tippy.js": {
|
||||
"version": "6.3.7",
|
||||
"resolved": "https://registry.npmjs.org/tippy.js/-/tippy.js-6.3.7.tgz",
|
||||
"integrity": "sha512-E1d3oP2emgJ9dRQZdf3Kkn0qJgI6ZLpyS5z6ZkY1DF3kaQaBsGZsndEpHwx+eC+tYM41HaSNvNtLx8tU57FzTQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@popperjs/core": "^2.9.0"
|
||||
}
|
||||
},
|
||||
"to-regex-range": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
||||
|
@ -22,6 +22,7 @@
|
||||
"prettier-plugin-tailwindcss": "^0.5.11",
|
||||
"pusher-js": "^4.3.1",
|
||||
"tailwindcss": "^3.1.0",
|
||||
"tippy.js": "^6.3.7",
|
||||
"toastr": "^2.1.4",
|
||||
"vite": "^4.5.2"
|
||||
}
|
||||
|
21
public/build/assets/app-44a1ce19.js
Normal file
21
public/build/assets/app-44a1ce19.js
Normal file
File diff suppressed because one or more lines are too long
1
public/build/assets/app-a1ae07b3.css
Normal file
1
public/build/assets/app-a1ae07b3.css
Normal file
@ -0,0 +1 @@
|
||||
.tippy-box[data-animation=fade][data-state=hidden]{opacity:0}[data-tippy-root]{max-width:calc(100vw - 10px)}.tippy-box{position:relative;background-color:#333;color:#fff;border-radius:4px;font-size:14px;line-height:1.4;white-space:normal;outline:0;transition-property:transform,visibility,opacity}.tippy-box[data-placement^=top]>.tippy-arrow{bottom:0}.tippy-box[data-placement^=top]>.tippy-arrow:before{bottom:-7px;left:0;border-width:8px 8px 0;border-top-color:initial;transform-origin:center top}.tippy-box[data-placement^=bottom]>.tippy-arrow{top:0}.tippy-box[data-placement^=bottom]>.tippy-arrow:before{top:-7px;left:0;border-width:0 8px 8px;border-bottom-color:initial;transform-origin:center bottom}.tippy-box[data-placement^=left]>.tippy-arrow{right:0}.tippy-box[data-placement^=left]>.tippy-arrow:before{border-width:8px 0 8px 8px;border-left-color:initial;right:-7px;transform-origin:center left}.tippy-box[data-placement^=right]>.tippy-arrow{left:0}.tippy-box[data-placement^=right]>.tippy-arrow:before{left:-7px;border-width:8px 8px 8px 0;border-right-color:initial;transform-origin:center right}.tippy-box[data-inertia][data-state=visible]{transition-timing-function:cubic-bezier(.54,1.5,.38,1.11)}.tippy-arrow{width:16px;height:16px;color:#333}.tippy-arrow:before{content:"";position:absolute;border-color:transparent;border-style:solid}.tippy-content{position:relative;padding:5px 9px;z-index:1}
|
File diff suppressed because one or more lines are too long
@ -4,8 +4,15 @@
|
||||
"isEntry": true,
|
||||
"src": "resources/css/app.css"
|
||||
},
|
||||
"resources/js/app.css": {
|
||||
"file": "assets/app-a1ae07b3.css",
|
||||
"src": "resources/js/app.css"
|
||||
},
|
||||
"resources/js/app.js": {
|
||||
"file": "assets/app-c41c626e.js",
|
||||
"css": [
|
||||
"assets/app-a1ae07b3.css"
|
||||
],
|
||||
"file": "assets/app-44a1ce19.js",
|
||||
"isEntry": true,
|
||||
"src": "resources/js/app.js"
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
@import "toastr.css";
|
||||
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
@ -1,4 +1,4 @@
|
||||
import Alpine from 'alpinejs';
|
||||
import tippy from 'tippy.js';
|
||||
|
||||
Alpine.directive('clipboard', (el) => {
|
||||
let text = el.textContent
|
||||
@ -54,3 +54,18 @@ window.toastr.options = {
|
||||
"positionClass": "toast-bottom-right",
|
||||
"preventDuplicates": true,
|
||||
}
|
||||
|
||||
import 'tippy.js/dist/tippy.css';
|
||||
import Alpine from 'alpinejs';
|
||||
document.body.addEventListener('htmx:afterSettle', (event) => {
|
||||
tippy('[data-tooltip]', {
|
||||
content(reference) {
|
||||
return reference.getAttribute('data-tooltip');
|
||||
},
|
||||
});
|
||||
});
|
||||
tippy('[data-tooltip]', {
|
||||
content(reference) {
|
||||
return reference.getAttribute('data-tooltip');
|
||||
},
|
||||
});
|
||||
|
@ -27,27 +27,41 @@
|
||||
hx-post="{{ route('servers.sites.queues.action', ['server' => $server, 'site' => $site, 'queue' => $queue, 'action' => 'stop']) }}"
|
||||
hx-swap="outerHTML"
|
||||
hx-select="#queue-actions-{{ $queue->id }}"
|
||||
data-tooltip="Stop"
|
||||
>
|
||||
Stop
|
||||
<x-heroicon-o-stop class="h-5 w-5" />
|
||||
</x-icon-button>
|
||||
<x-icon-button
|
||||
id="resume-{{ $queue->id }}"
|
||||
hx-post="{{ route('servers.sites.queues.action', ['server' => $server, 'site' => $site, 'queue' => $queue, 'action' => 'start']) }}"
|
||||
hx-swap="outerHTML"
|
||||
hx-select="#queue-actions-{{ $queue->id }}"
|
||||
data-tooltip="Start"
|
||||
>
|
||||
Start
|
||||
<x-heroicon-o-play class="h-5 w-5" />
|
||||
</x-icon-button>
|
||||
<x-icon-button
|
||||
id="restart-{{ $queue->id }}"
|
||||
hx-post="{{ route('servers.sites.queues.action', ['server' => $server, 'site' => $site, 'queue' => $queue, 'action' => 'restart']) }}"
|
||||
hx-swap="outerHTML"
|
||||
hx-select="#queue-actions-{{ $queue->id }}"
|
||||
data-tooltip="Restart"
|
||||
>
|
||||
Restart
|
||||
<x-heroicon-o-arrow-path class="h-5 w-5" />
|
||||
</x-icon-button>
|
||||
<x-icon-button
|
||||
id="logs-{{ $queue->id }}"
|
||||
x-on:click="$dispatch('open-modal', 'show-log'); document.getElementById('log-content').firstChild.innerHTML = '';"
|
||||
hx-get="{{ route('servers.sites.queues.logs', ['server' => $server, 'site' => $site, 'queue' => $queue]) }}"
|
||||
hx-target="#log-content"
|
||||
hx-select="#log-content"
|
||||
data-tooltip="Logs"
|
||||
>
|
||||
<x-heroicon-o-square-3-stack-3d class="h-5 w-5" />
|
||||
</x-icon-button>
|
||||
<x-icon-button
|
||||
x-on:click="deleteAction = '{{ route('servers.sites.queues.destroy', ['server' => $server, 'site' => $site, 'queue' => $queue]) }}'; $dispatch('open-modal', 'delete-queue')"
|
||||
data-tooltip="Delete"
|
||||
>
|
||||
<x-heroicon-o-trash class="h-5 w-5" />
|
||||
</x-icon-button>
|
||||
@ -71,4 +85,25 @@
|
||||
method="delete"
|
||||
x-bind:action="deleteAction"
|
||||
/>
|
||||
<x-modal name="show-log" max-width="4xl">
|
||||
<div class="p-6">
|
||||
<h2 class="mb-5 text-lg font-medium text-gray-900 dark:text-gray-100">
|
||||
{{ __("View Log") }}
|
||||
</h2>
|
||||
<div id="log-content">
|
||||
<x-console-view>
|
||||
@if (session()->has("content"))
|
||||
{{ session("content") }}
|
||||
@else
|
||||
Loading...
|
||||
@endif
|
||||
</x-console-view>
|
||||
</div>
|
||||
<div class="mt-6 flex justify-end">
|
||||
<x-secondary-button type="button" x-on:click="$dispatch('close')">
|
||||
{{ __("Close") }}
|
||||
</x-secondary-button>
|
||||
</div>
|
||||
</div>
|
||||
</x-modal>
|
||||
</div>
|
||||
|
@ -54,6 +54,7 @@
|
||||
Route::post('/{site}/queues', [QueueController::class, 'store'])->name('servers.sites.queues.store');
|
||||
Route::post('/{site}/queues/{queue}/action/{action}', [QueueController::class, 'action'])->name('servers.sites.queues.action');
|
||||
Route::delete('/{site}/queues/{queue}', [QueueController::class, 'destroy'])->name('servers.sites.queues.destroy');
|
||||
Route::get('/{site}/queues/{queue}/logs', [QueueController::class, 'logs'])->name('servers.sites.queues.logs');
|
||||
|
||||
// site settings
|
||||
Route::get('/{site}/settings', [SiteSettingController::class, 'index'])->name('servers.sites.settings');
|
||||
|
@ -167,4 +167,27 @@ public function test_restart_queue(): void
|
||||
'status' => QueueStatus::RUNNING,
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_show_logs(): void
|
||||
{
|
||||
SSH::fake('logs');
|
||||
|
||||
$this->actingAs($this->user);
|
||||
|
||||
$queue = Queue::factory()->create([
|
||||
'server_id' => $this->server->id,
|
||||
'site_id' => $this->site->id,
|
||||
'status' => QueueStatus::RUNNING,
|
||||
]);
|
||||
|
||||
$this->get(
|
||||
route('servers.sites.queues.logs', [
|
||||
'server' => $this->server,
|
||||
'site' => $this->site,
|
||||
'queue' => $queue,
|
||||
])
|
||||
)
|
||||
->assertSessionDoesntHaveErrors()
|
||||
->assertSessionHas('content', 'logs');
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user