[done] front end drag and drop for pivot, span, and harvest data.

This commit is contained in:
guillaume91 2024-05-21 16:21:31 +02:00
parent 54367dc8d4
commit bace7a47c0
9 changed files with 214 additions and 117 deletions

View file

@ -5,7 +5,7 @@
use App\Models\Project;
use App\Models\ProjectBoundingBox;
use App\Models\ProjectEmailRecipient;
use Illuminate\Support\Arr;
use App\Rules\HarvestFile;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;
use Livewire\Component;
@ -28,6 +28,11 @@ class ProjectManager extends Component
public $projectIdBeingDeleted;
public $span_json_path;
public $pivot_json_path;
public $harvest_json_path;
public array $pivotFiles;
public array $spanFiles;
public array $harvestDataFiles;
/**
* Mount the component.
@ -58,6 +63,7 @@ private function loadFormData(Project $project)
$this->pivot_json_path = $this->formData['pivot_json_path'];
$this->formData['pivot_json_path'] = null;
$this->span_json_path = $this->formData['span_json_path'];
$this->harvest_json_path = $this->formData['harvest_json_path'];
$this->formData['span_json_path'] = null;
$this->formData['boundingBoxes'] = $project->boundingBoxes->toArray();
$this->formData['mail_recipients'] = $project->emailRecipients->toArray() ?: [
@ -77,7 +83,7 @@ public function openCreateProjectModal()
public function saveProject()
{
$this->resetErrorBag();
$this->validateForm();
dd($this->validateForm());
Project::saveWithFormData($this->formData);
$this->resetFormData();
$this->showProjectModal = false;
@ -184,6 +190,7 @@ private function resetFormData()
'name' => '',
'pivot_json_path' => '',
'span_json_path' => '',
'harvest_json_path' => '',
'boundingBoxes' => [],
'mail_subject' => '',
'mail_template' => '',
@ -191,6 +198,9 @@ private function resetFormData()
'mail_day' => '',
'mail_recipients' => [],
];
$this->pivotFiles = [];
$this->spanFiles = [];
$this->harvestDataFiles = [];
$this->addBoundingBox();
$this->addEmailRecipient();
}
@ -199,10 +209,11 @@ private function validateForm()
{
$projectIdentifier = $this->formData['id'] ?? null;
Validator::make([
return Validator::make([
'name' => $this->formData['name'],
'pivot_json_path' => $this->formData['pivot_json_path'], // TODO: 'required|file|mimes:csv,txt|max:2048
'span_json_path' => $this->formData['span_json_path'],
'pivot_file' => $this->pivotFiles[0] ?? null,
'span_file' => $this->spanFiles[0] ?? null,
'harvest_data_file' => $this->harvestDataFiles[0] ?? null,
'boundingBoxes' => $this->formData['boundingBoxes'],
], [
'name' => [
@ -211,31 +222,16 @@ private function validateForm()
'string',
'max:255'
],
'pivot_json_path' => [
function ($attribute, $value, $fail) {
if ($value && !is_file($value->getRealPath())) {
$fail($attribute.' is geen geldig bestand.');
} elseif ($value && !in_array(mime_content_type($value->getRealPath()), ['application/json'])) {
// $fail($attribute.' moet een JSON-bestand zijn.');
}
},
],
'span_json_path' => [
function ($attribute, $value, $fail) {
if ($value && !is_file($value->getRealPath())) {
$fail($attribute.' is geen geldig bestand.');
} elseif ($value && !in_array(mime_content_type($value->getRealPath()), ['application/json'])) {
// $fail($attribute.' moet een JSON-bestand zijn.');
}
},
],
'pivot_file' => ['sometimes'],
'span_file' => ['sometimes'],
'harvestDataFile' => ['sometimes',new HarvestFile],
'boundingBoxes' => ['required', 'array', 'min:1'],
'boundingBoxes.*.name' => ['required', 'string', 'max:255'],
'boundingBoxes.*.top_left_latitude' => ['required', 'string'],
'boundingBoxes.*.top_left_longitude' => ['required', 'string'],
'boundingBoxes.*.bottom_right_latitude' => ['required', 'string'],
'boundingBoxes.*.bottom_right_longitude' => ['required', 'string'],
])->validateWithBag('saveProject');
])->validate();
}
private function validateEmailSettingsForm()

View file

@ -26,6 +26,9 @@ class Project extends Model
'mail_frequency',
'mail_day',
'download_path',
'pivot_json_path',
'span_json_path',
'harvest_json_data'
];
public static function saveWithFormData(mixed $formData)
@ -34,13 +37,15 @@ public static function saveWithFormData(mixed $formData)
$project = Project::updateOrCreate($uniqueIdentifier, $formData);
if ($formData['pivot_json_path']) {
$path = $formData['pivot_json_path']->storeAs($project->download_path .'/Data', 'pivot.geojson');
$project->pivot_json_path = $path;
$project->save();
$project->update(['pivot_json_path' => $path]);
}
if ($formData['span_json_path']) {
$path = $formData['span_json_path']->storeAs($project->download_path .'/Data', 'span.geojson');
$project->pivot_json_path = $path;
$project->save();
$project->update(['span_json_path' => $path]);
}
if ($formData['harvest_json_data']) {
$path = $formData['harvest_json_path']->storeAs($project->download_path .'/Data', 'harvest.xlsx');
$project->update(['harvest_json_path' => $path]);
}
$project->upsertBoundingBox($formData);
$project->upsertMailRecipients($formData);

View file

@ -6,6 +6,7 @@
"license": "MIT",
"require": {
"php": "^8.2",
"dasundev/livewire-dropzone": "^1.0",
"guzzlehttp/guzzle": "^7.2",
"laravel/framework": "^v11.0.7",
"laravel/jetstream": "^5.0",

View file

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "6c255cb424db38d53bf1b26ce0e9ec53",
"content-hash": "fb3d9bb02b87b8873aec06181a9061d5",
"packages": [
{
"name": "bacon/bacon-qr-code",
@ -239,6 +239,75 @@
},
"time": "2023-08-25T16:18:39+00:00"
},
{
"name": "dasundev/livewire-dropzone",
"version": "v1.0.10",
"source": {
"type": "git",
"url": "https://github.com/dasundev/livewire-dropzone.git",
"reference": "fddfc9acbd43b6b29be1692b605d911d4e6d5359"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/dasundev/livewire-dropzone/zipball/fddfc9acbd43b6b29be1692b605d911d4e6d5359",
"reference": "fddfc9acbd43b6b29be1692b605d911d4e6d5359",
"shasum": ""
},
"require": {
"livewire/livewire": "^3.0",
"php": "^8.1",
"spatie/laravel-package-tools": "^1.16"
},
"require-dev": {
"larastan/larastan": "^2.0",
"laravel/pint": "^1.13",
"orchestra/testbench": "^8.0",
"pestphp/pest": "^1.23"
},
"type": "library",
"extra": {
"laravel": {
"providers": [
"Dasundev\\LivewireDropzone\\LivewireDropzoneServiceProvider"
],
"aliases": {
"LivewireDropzone": "Dasundev\\LivewireDropzone\\LivewireDropzoneFacade"
}
}
},
"autoload": {
"psr-4": {
"Dasundev\\LivewireDropzone\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Dasun Tharanga",
"email": "hello@dasun.dev",
"role": "Developer"
}
],
"description": "A Livewire Dropzone component for simple drag-and-drop file uploads.",
"keywords": [
"dropzone",
"livewire"
],
"support": {
"issues": "https://github.com/dasundev/livewire-dropzone/issues",
"source": "https://github.com/dasundev/livewire-dropzone/tree/v1.0.10"
},
"funding": [
{
"url": "https://github.com/dasundev",
"type": "github"
}
],
"time": "2024-04-30T01:58:11+00:00"
},
{
"name": "dflydev/dot-access-data",
"version": "v3.0.2",
@ -3799,6 +3868,66 @@
],
"time": "2024-04-27T21:32:50+00:00"
},
{
"name": "spatie/laravel-package-tools",
"version": "1.16.4",
"source": {
"type": "git",
"url": "https://github.com/spatie/laravel-package-tools.git",
"reference": "ddf678e78d7f8b17e5cdd99c0c3413a4a6592e53"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/spatie/laravel-package-tools/zipball/ddf678e78d7f8b17e5cdd99c0c3413a4a6592e53",
"reference": "ddf678e78d7f8b17e5cdd99c0c3413a4a6592e53",
"shasum": ""
},
"require": {
"illuminate/contracts": "^9.28|^10.0|^11.0",
"php": "^8.0"
},
"require-dev": {
"mockery/mockery": "^1.5",
"orchestra/testbench": "^7.7|^8.0",
"pestphp/pest": "^1.22",
"phpunit/phpunit": "^9.5.24",
"spatie/pest-plugin-test-time": "^1.1"
},
"type": "library",
"autoload": {
"psr-4": {
"Spatie\\LaravelPackageTools\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Freek Van der Herten",
"email": "freek@spatie.be",
"role": "Developer"
}
],
"description": "Tools for creating Laravel packages",
"homepage": "https://github.com/spatie/laravel-package-tools",
"keywords": [
"laravel-package-tools",
"spatie"
],
"support": {
"issues": "https://github.com/spatie/laravel-package-tools/issues",
"source": "https://github.com/spatie/laravel-package-tools/tree/1.16.4"
},
"funding": [
{
"url": "https://github.com/spatie",
"type": "github"
}
],
"time": "2024-03-20T07:29:11+00:00"
},
{
"name": "symfony/clock",
"version": "v7.0.7",
@ -8816,5 +8945,5 @@
"php": "^8.2"
},
"platform-dev": [],
"plugin-api-version": "2.3.0"
"plugin-api-version": "2.6.0"
}

View file

@ -9,6 +9,7 @@
"@alpinejs/focus": "^3.13.3",
"@alpinejs/intersect": "^3.13.3",
"@alpinejs/ui": "^3.13.3-beta.4",
"@dasundev/livewire-dropzone-styles": "^1.0.7",
"@fortawesome/fontawesome-free": "^6.5.2",
"@ryangjchandler/alpine-clipboard": "^2.3.0",
"@tailwindcss/aspect-ratio": "^0.4.2",
@ -62,6 +63,11 @@
"resolved": "https://registry.npmjs.org/@alpinejs/ui/-/ui-3.13.3-beta.4.tgz",
"integrity": "sha512-Dc6j40tELUqSAIg93Dgi+Carkw8MB+YXm0sILD41vkxw0ByHf5pICCBvhxkcVRg2I/2/6YM/W7i1ZUORNEqrgw=="
},
"node_modules/@dasundev/livewire-dropzone-styles": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/@dasundev/livewire-dropzone-styles/-/livewire-dropzone-styles-1.0.7.tgz",
"integrity": "sha512-Kd9lGe7qAAm2vc0DsiuzELBnqyNnlNlf9I8Zrdqm0HeD6cvJW1F16Mpl6EEJtR2ZgshTfX/mMvTjgJ5g48jMpg=="
},
"node_modules/@esbuild/android-arm": {
"version": "0.18.20",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz",

View file

@ -20,6 +20,7 @@
"@alpinejs/focus": "^3.13.3",
"@alpinejs/intersect": "^3.13.3",
"@alpinejs/ui": "^3.13.3-beta.4",
"@dasundev/livewire-dropzone-styles": "^1.0.7",
"@fortawesome/fontawesome-free": "^6.5.2",
"@ryangjchandler/alpine-clipboard": "^2.3.0",
"@tailwindcss/aspect-ratio": "^0.4.2",

View file

@ -1,6 +1,7 @@
@import 'flatpickr/dist/flatpickr.css';
@import url('https://rsms.me/inter/inter.css');
@import '@fortawesome/fontawesome-free/css/all.css';
@import "@dasundev/livewire-dropzone-styles";
@tailwind base;
@tailwind components;
@tailwind utilities;

View file

@ -22,93 +22,51 @@
<x-input-error for="name" class="mt-2"/>
</div>
<div class="flex flex-col mb-2">
<label for="pivot_json_path"
class="flex flex-col items-center justify-center border-2 border-dashed border-gray-300 w-full bg-gray-50 hover:bg-gray-100 hover:border-gray-300 hover:cursor-pointer p-4 rounded"
x-data="{pivot_file:null}">
<div class="flex flex-col items-center justify-center text-gray-500 text-sm">
<span>
<i class="fa-solid fa-file-arrow-up fa-lg"></i>
</span>
<div class="flex flex-col items-center" id="geo_label">
<span x-text="pivot_file?.name ?? 'Click to upload a Span GeoJSON File.'"></span>
<span x-text="pivot_file?.name ? '': 'JSON.' " class="text-gray-400 text-xs"></span>
</div>
</div>
<input type="file" id="pivot_json_path" wire:model="formData.pivot_json_path" accept=".json"
class="hidden" @change="pivot_file = $event.target.files[0]"/>
<x-input-error for="pivot_json_path" class="mt-2"/>
</label>
</div>
<div class="flex flex-col mb-2">
<label for="span_json_path"
class="flex flex-col items-center justify-center border-2 border-dashed border-gray-300 w-full bg-gray-50 hover:bg-gray-100 hover:border-gray-300 hover:cursor-pointer p-4 rounded"
x-data="{span_file:null}" x-init="span_file=null">
<div class="flex flex-col items-center justify-center text-gray-500 text-sm">
<span><i class="fa-solid fa-file-arrow-up fa-lg"></i></span>
<div class="flex flex-col items-center">
<span x-text="span_file?.name ?? 'Click to upload a Span GeoJSON File.'"></span>
<span x-text="span_file?.name ? '': 'JSON.' " class="text-gray-400 text-xs"></span>
</div>
</div>
<input type="file" id="span_json_path" wire:model="formData.span_json_path" accept=".json"
class="hidden" @change="span_file = $event.target.files[0]"/>
<x-input-error for="span_json_path" class="mt-2"/>
</label>
</div>
{{-- <div class="">--}}
{{-- <label for="harvest_data"--}}
{{-- class="flex flex-col items-center justify-center border-2 border-dashed border-gray-300 w-full bg-gray-50 hover:bg-gray-100 hover:border-gray-300 hover:cursor-pointer p-4 rounded"--}}
{{-- x-data="{excel_file:null}"--}}
{{-- >--}}
{{-- <div class="flex flex-col items-center justify-center text-gray-500 text-sm">--}}
{{-- <span><i class=" fa-solid fa-file-excel fa-lg"></i></span>--}}
{{-- <div class="flex flex-col items-center">--}}
{{-- <span x-text="excel_file?.name ?? 'Click to upload a SpreadSheet File.'"></span>--}}
{{-- <span x-text="excel_file?.name ? '': 'XLS, XLSX or ODS.' "--}}
{{-- class="text-gray-400 text-xs"></span>--}}
{{-- </div>--}}
{{-- </div>--}}
{{-- <input type="file" id="harvest_data" wire:model="formData.harvest_data" accept=".xlsx,.xls,.ods"--}}
{{-- class="hidden" @change="excel_file = $event.target.files[0]" @drop="excel_file = $event.dataTransfer.files[0];console.log(excel_file);"/>--}}
{{-- <x-input-error for="harvest_data" class="mt-2"/>--}}
{{-- </label>--}}
{{-- </div>--}}
<div x-data="{ fileName: '',
isAccepted(file){
acceptedFormats = [
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
];
return acceptedFormats.includes(file.type);
},
handleFile(file){
if(!this.isAccepted(file)){
console.log('Wrong file.');
$dispatch('notify',{message:'Wrong File',type:'error'});
$refs.harvest_data.files=[];
return;
}
console.log(file.type,file.name);
this.fileName = file.name;
$wire.set('formData.harvest_data',file);
console.log(this.fileName);
},
}" class=" bg-gray-50 hover:bg-gray-100 w-full relative rounded-md shadow-sm">
<div x-ref="dnd" class="relative text-gray-500 text-sm border-2 border-gray-300 border-dashed rounded cursor-pointer">
<input accept=".xlsx,.xls,.ods" type="file" x-ref="harvest_data" name="file" title="" @change="if($el.files) handleFile($el.files[0])" wire:model="formData.harvest_data"
class="absolute inset-0 z-50 w-full h-full p-0 m-0 outline-none opacity-0 cursor-pointer"
@dragover="$refs.dnd.classList.add('bg-indigo-50')"
@dragleave="$refs.dnd.classList.remove('bg-indigo-50')"
@drop="$refs.dnd.classList.remove('bg-indigo-50')"
<p>{{__('Pivot GeoJSON file.')}}</p>
<div id="pivot_file">
<livewire:dropzone
wire:model="pivotFiles"
:rules="['extensions:json,geojson','mimes:json,geojson']"
:key="'pivotFiles'"
/>
<div class="flex flex-col items-center justify-center py-10 text-center">
<span><i class=" fa-solid fa-file-excel fa-lg"></i></span>
<p class="mt-1">Drag or Click to upload a SpreadSheet File.</p>
<p class="text-gray-400 text-xs"> .xlsx, .xsl or .ods</p>
<p class="mt-2 text-gray-800" x-text="fileName"></p>
@error('pivotFiles')
{{ $message }}
@enderror
</div>
@dump($this->pivot_json_path)
</div>
<div class="flex flex-col mb-2">
<p>{{__('Span GeoJSON file.')}}</p>
<div id="span_file">
<livewire:dropzone
wire:model="spanFiles"
:rules="['extensions:json,geojson','mimes:json,geojson']"
:key="'spanFiles'"
/>
@error('spanFiles')
{{ $message }}
@enderror
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@dump($this->span_json_path)
</div>
<div class="flex flex-col mb-2">
<p>{{__('Harvested Data file.')}}</p>
<div id="harvest_file">
<livewire:dropzone
wire:model="harvestDataFiles"
:rules="['extensions:xls,xlsx,ods','mimes:xls,xlsx,ods','required']"
:key="'harvestDataFiles'"
/>
@error('harvestDataFiles')
{{ $message }}
@enderror
</div>
@dump($this->harvest_json_path)
</div>
@foreach($projectManager->formData['boundingBoxes'] as $key => $boundingBox)
{{-- <div wire:key="bounding_box_{{ $key }}">--}}