log ui
This commit is contained in:
@@ -3,13 +3,20 @@
|
|||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
use App\Jobs\Services\RunStep;
|
use App\Jobs\Services\RunStep;
|
||||||
|
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
class Step extends Model
|
class Step extends Model
|
||||||
{
|
{
|
||||||
protected $guarded = [];
|
protected $guarded = [];
|
||||||
|
|
||||||
|
protected $appends = [
|
||||||
|
'logs_excerpt',
|
||||||
|
'error_logs_excerpt',
|
||||||
|
];
|
||||||
|
|
||||||
protected function casts(): array
|
protected function casts(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
@@ -24,6 +31,20 @@ class Step extends Model
|
|||||||
return $this->belongsTo(Deployment::class);
|
return $this->belongsTo(Deployment::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function logsExcerpt(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => $this->logs ? Str::afterLast($this->logs, "\n"): null,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function errorLogsExcerpt(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => $this->error_logs ? Str::afterLast($this->error_logs, "\n"): null,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public function dispatchJob(): void
|
public function dispatchJob(): void
|
||||||
{
|
{
|
||||||
dispatch(new RunStep($this));
|
dispatch(new RunStep($this));
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { Badge } from '@/components/ui/badge';
|
import { Badge } from '@/components/ui/badge';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { Card, CardDescription, CardHeader, CardTitle, CardContent } from '@/components/ui/card';
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
||||||
|
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
|
||||||
import AppLayout from '@/layouts/AppLayout.vue';
|
import AppLayout from '@/layouts/AppLayout.vue';
|
||||||
import { Head, Link } from '@inertiajs/vue3';
|
import { Head, Link } from '@inertiajs/vue3';
|
||||||
import { useCycleList, useInterval } from '@vueuse/core';
|
import { useCycleList, useInterval } from '@vueuse/core';
|
||||||
import { DatabaseIcon, Layers2Icon, LoaderCircleIcon, PlusIcon } from 'lucide-vue-next';
|
import { DatabaseIcon, Layers2Icon, LoaderCircleIcon, PlusIcon } from 'lucide-vue-next';
|
||||||
import { watch } from 'vue';
|
import { ref, watch } from 'vue';
|
||||||
|
|
||||||
defineProps({
|
defineProps({
|
||||||
server: {
|
server: {
|
||||||
@@ -15,6 +16,8 @@ defineProps({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const selectedStep = ref(null);
|
||||||
|
|
||||||
const { state: provisionMessage, next } = useCycleList([
|
const { state: provisionMessage, next } = useCycleList([
|
||||||
'Provisioning your server...',
|
'Provisioning your server...',
|
||||||
'Updating dependencies...',
|
'Updating dependencies...',
|
||||||
@@ -102,17 +105,37 @@ watch(counter, () => {
|
|||||||
<Card>
|
<Card>
|
||||||
<CardContent class="py-4">
|
<CardContent class="py-4">
|
||||||
<div v-for="deployment in server.service_deployments" class="flex gap-4">
|
<div v-for="deployment in server.service_deployments" class="flex gap-4">
|
||||||
<div class="w-48">{{ deployment.target.name }}</div>
|
<div class="w-48 leading-none">{{ deployment.target.name }}</div>
|
||||||
<div class="space-y-4">
|
<div class="w-full space-y-4">
|
||||||
<div v-for="step in deployment.steps">
|
<div v-for="step in deployment.steps" class="flex items-center space-y-1">
|
||||||
<div class="font-semibold">
|
<div class="flex-1">
|
||||||
{{ step.name ?? 'Unnamed Step' }}
|
<div class="text-sm font-semibold leading-none">
|
||||||
|
{{ step.name ?? 'Unnamed Step' }}
|
||||||
|
</div>
|
||||||
|
<div v-if="step.error_logs">
|
||||||
|
<pre class="text-xs text-muted-foreground"
|
||||||
|
>{{ step.error_logs_excerpt.length !== step.error_logs ? '... ' : ''
|
||||||
|
}}{{ step.error_logs_excerpt }}</pre
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div v-else-if="step.logs">
|
||||||
|
<pre class="text-xs text-muted-foreground"
|
||||||
|
>{{ step.logs_excerpt.length !== step.logs ? '... ' : '' }}{{ step.logs_excerpt }}</pre
|
||||||
|
>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="step.error_logs">
|
<div>
|
||||||
<pre class="text-xs">{{ step.error_logs }}</pre>
|
<Button
|
||||||
</div>
|
size="xs"
|
||||||
<div v-else>
|
variant="link"
|
||||||
<pre class="text-xs">{{ step.logs }}</pre>
|
@click="
|
||||||
|
() => {
|
||||||
|
selectedStep = step;
|
||||||
|
}
|
||||||
|
"
|
||||||
|
>
|
||||||
|
View
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -149,6 +172,22 @@ watch(counter, () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<Dialog :open="!!selectedStep" @update:open="($event) => (!$event ? (selectedStep = null) : null)">
|
||||||
|
<DialogContent class="md:max-w-2xl">
|
||||||
|
<DialogHeader>
|
||||||
|
<DialogTitle>Logs for {{ selectedStep?.name }}</DialogTitle>
|
||||||
|
</DialogHeader>
|
||||||
|
<section v-if="selectedStep?.logs">
|
||||||
|
<h3 class="text-sm font-medium">Logs</h3>
|
||||||
|
<pre class="text-xs text-muted-foreground">{{ selectedStep?.logs }}</pre>
|
||||||
|
</section>
|
||||||
|
<section v-if="selectedStep?.error_logs">
|
||||||
|
<h3 class="text-sm font-medium">Error Logs</h3>
|
||||||
|
<pre class="max-w-full overflow-x-scroll text-xs text-muted-foreground">{{ selectedStep?.error_logs }}</pre>
|
||||||
|
</section>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
|
||||||
<!-- {{ server }} -->
|
<!-- {{ server }} -->
|
||||||
</div>
|
</div>
|
||||||
</AppLayout>
|
</AppLayout>
|
||||||
|
|||||||
Reference in New Issue
Block a user