188 lines
8.6 KiB
PHP
188 lines
8.6 KiB
PHP
<x-filament-panels::page>
|
|
|
|
<div class="grid grid-cols-1 gap-4 sm:grid-cols-3 mb-6">
|
|
<x-filament::card>
|
|
<div class="flex items-center gap-3">
|
|
<x-heroicon-o-clock class="w-8 h-8 text-gray-400" />
|
|
<div>
|
|
<p class="text-sm text-gray-500">{{ __('navigation.sync.last_sync') }}</p>
|
|
<p class="text-lg font-bold">{{ $this->getLastSyncTime() }}</p>
|
|
</div>
|
|
</div>
|
|
</x-filament::card>
|
|
|
|
<x-filament::card>
|
|
<div class="flex items-center gap-3">
|
|
<x-heroicon-o-queue-list class="w-8 h-8 text-amber-400" />
|
|
<div>
|
|
<p class="text-sm text-gray-500">{{ __('navigation.sync.pending_changes') }}</p>
|
|
<p class="text-2xl font-bold text-amber-500">{{ $this->getPendingCount() }}</p>
|
|
</div>
|
|
</div>
|
|
</x-filament::card>
|
|
|
|
<x-filament::card>
|
|
<div class="flex items-center gap-3">
|
|
<x-heroicon-o-server class="w-8 h-8 text-blue-400" />
|
|
<div>
|
|
<p class="text-sm text-gray-500">{{ __('navigation.sync.peer_address') }}</p>
|
|
<p class="text-lg font-bold font-mono">
|
|
{{ \App\Models\OsurgInitial::val('sync_peer_ip', config('sync.peer_ip')) ?: '—' }}
|
|
@php($port = \App\Models\OsurgInitial::val('sync_peer_port', config('sync.peer_port')))
|
|
@if($port && $port != 80)
|
|
:{{ $port }}
|
|
@endif
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</x-filament::card>
|
|
</div>
|
|
|
|
<x-filament::card>
|
|
<div class="space-y-2 text-sm text-gray-600 dark:text-gray-400">
|
|
<h3 class="font-semibold text-base text-gray-800 dark:text-gray-200">{{ __('navigation.sync.setup_guide') }}</h3>
|
|
<p>{{ __('navigation.sync.setup_description_dynamic') }}</p>
|
|
<ul class="list-disc list-inside space-y-1 text-xs">
|
|
<li><code class="bg-gray-100 dark:bg-gray-800 px-1 rounded">sync_peer_ip</code> — {{ __('navigation.sync.field_peer_ip') }}</li>
|
|
<li><code class="bg-gray-100 dark:bg-gray-800 px-1 rounded">sync_peer_port</code> — {{ __('navigation.sync.field_peer_port') }}</li>
|
|
<li><code class="bg-gray-100 dark:bg-gray-800 px-1 rounded">sync_token</code> — {{ __('navigation.sync.field_sync_token') }}</li>
|
|
</ul>
|
|
<p class="text-amber-600 dark:text-amber-400">⚠ {{ __('navigation.sync.setup_warning') }}</p>
|
|
</div>
|
|
</x-filament::card>
|
|
|
|
<x-filament::card>
|
|
<div
|
|
x-data="{
|
|
dragging: false,
|
|
fileName: '',
|
|
fileSize: '',
|
|
uploading: false,
|
|
uploaded: false,
|
|
uploadProgress: 0,
|
|
setFile(file) {
|
|
this.fileName = file.name;
|
|
this.fileSize = (file.size / 1024 / 1024).toFixed(2) + ' MB';
|
|
this.uploading = true;
|
|
this.uploaded = false;
|
|
this.uploadProgress = 0;
|
|
$wire.upload(
|
|
'sqlFile',
|
|
file,
|
|
() => { this.uploading = false; this.uploaded = true; this.uploadProgress = 100; },
|
|
() => { this.uploading = false; this.uploaded = false; this.fileName = ''; this.uploadProgress = 0; },
|
|
(event) => { if (event && event.detail) this.uploadProgress = event.detail.progress; }
|
|
);
|
|
}
|
|
}"
|
|
class="space-y-4"
|
|
>
|
|
<div class="flex items-center gap-2">
|
|
<x-heroicon-o-arrow-up-tray class="w-5 h-5 text-amber-500" />
|
|
<h3 class="font-semibold text-base text-gray-800 dark:text-gray-200">
|
|
{{ __('navigation.import.label') }}
|
|
</h3>
|
|
</div>
|
|
|
|
<p class="text-sm text-gray-500 dark:text-gray-400">
|
|
{{ __('navigation.import.confirm_description') }}
|
|
</p>
|
|
|
|
{{-- File drop zone --}}
|
|
<div
|
|
@dragover.prevent="dragging = true"
|
|
@dragleave.prevent="dragging = false"
|
|
@drop.prevent="
|
|
dragging = false;
|
|
const file = $event.dataTransfer.files[0];
|
|
if (file) setFile(file);
|
|
"
|
|
class="relative border-2 border-dashed rounded-xl p-6 text-center transition-colors"
|
|
:class="dragging
|
|
? 'border-amber-400 bg-amber-50 dark:bg-amber-900/20'
|
|
: 'border-gray-300 dark:border-gray-600 hover:border-amber-400 dark:hover:border-amber-500'"
|
|
>
|
|
<input
|
|
x-ref="fileInput"
|
|
type="file"
|
|
accept=".sql,.txt"
|
|
class="absolute inset-0 opacity-0 cursor-pointer w-full h-full"
|
|
x-on:change="
|
|
const file = $event.target.files[0];
|
|
if (file) setFile(file);
|
|
"
|
|
/>
|
|
|
|
{{-- Idle state --}}
|
|
<div x-show="!fileName" class="space-y-2">
|
|
<x-heroicon-o-document-arrow-up class="w-10 h-10 text-gray-400 mx-auto" />
|
|
<p class="text-sm font-medium text-gray-600 dark:text-gray-300">
|
|
{{ __('navigation.import.drop_or_click') }}
|
|
</p>
|
|
<p class="text-xs text-gray-400">{{ __('navigation.import.file_hint') }}</p>
|
|
</div>
|
|
|
|
{{-- File selected state --}}
|
|
<div x-show="fileName" class="space-y-1">
|
|
<x-heroicon-o-document-check class="w-10 h-10 text-amber-500 mx-auto" />
|
|
<p class="text-sm font-semibold text-gray-700 dark:text-gray-200" x-text="fileName"></p>
|
|
<p class="text-xs text-gray-400" x-text="fileSize"></p>
|
|
<p class="text-xs" :class="uploading ? 'text-blue-500' : 'text-amber-600 dark:text-amber-400'">
|
|
<span x-show="uploading">{{ __('navigation.import.uploading') }}</span>
|
|
<span x-show="!uploading && uploaded">{{ __('navigation.import.file_ready') }}</span>
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
@error('sqlFile')
|
|
<p class="text-sm text-red-600 dark:text-red-400">{{ $message }}</p>
|
|
@enderror
|
|
|
|
{{-- Upload progress bar --}}
|
|
<div x-show="uploading" class="space-y-1">
|
|
<div class="w-full bg-gray-200 dark:bg-gray-700 rounded-full h-2">
|
|
<div
|
|
class="bg-amber-500 h-2 rounded-full transition-all"
|
|
:style="'width: ' + uploadProgress + '%'"
|
|
></div>
|
|
</div>
|
|
</div>
|
|
|
|
{{-- Submit button --}}
|
|
<div class="flex justify-end">
|
|
<x-filament::button
|
|
wire:click="startImport"
|
|
wire:loading.attr="disabled"
|
|
wire:target="startImport"
|
|
color="warning"
|
|
icon="heroicon-o-arrow-up-tray"
|
|
:disabled="$this->importing"
|
|
x-bind:disabled="!uploaded || uploading"
|
|
>
|
|
<span wire:loading.remove wire:target="startImport">
|
|
{{ __('navigation.import.confirm_button') }}
|
|
</span>
|
|
<span wire:loading wire:target="startImport">
|
|
{{ __('navigation.import.processing') }}
|
|
</span>
|
|
</x-filament::button>
|
|
</div>
|
|
</div>
|
|
</x-filament::card>
|
|
|
|
@if($report)
|
|
<x-filament::card>
|
|
<h3 class="font-semibold text-base mb-2">{{ __('navigation.sync.last_report') }}</h3>
|
|
<pre class="bg-gray-50 dark:bg-gray-900 border rounded p-3 text-xs leading-loose max-h-64 overflow-y-auto whitespace-pre-wrap">{{ $report }}</pre>
|
|
</x-filament::card>
|
|
@endif
|
|
|
|
@if($importReport)
|
|
<x-filament::card>
|
|
<h3 class="font-semibold text-base mb-2">{{ __('navigation.import.last_report') }}</h3>
|
|
<pre class="bg-gray-50 dark:bg-gray-900 border rounded p-3 text-xs leading-loose max-h-64 overflow-y-auto whitespace-pre-wrap">{{ $importReport }}</pre>
|
|
</x-filament::card>
|
|
@endif
|
|
|
|
</x-filament-panels::page>
|