changes, global search (clients, cleintCases)
This commit is contained in:
parent
c45751c1e2
commit
3ae70bf340
25
app/Console/Commands/ImportPosts.php
Normal file
25
app/Console/Commands/ImportPosts.php
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
use App\Models\Post;
|
||||||
|
|
||||||
|
class ImportPosts extends Command
|
||||||
|
{
|
||||||
|
protected $signature = 'import:posts';
|
||||||
|
protected $description = 'Import posts into Algolia without clearing the index';
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
parent::__construct();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
$posts = Post::all();
|
||||||
|
$posts->searchable();
|
||||||
|
$this->info('Posts have been imported into Algolia.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -24,7 +24,7 @@ public function index(ClientCase $clientCase, Request $request)
|
||||||
)
|
)
|
||||||
->where('active', 1)
|
->where('active', 1)
|
||||||
->orderByDesc('created_at')
|
->orderByDesc('created_at')
|
||||||
->paginate(15)
|
->paginate(15, ['*'], 'client-cases-page')
|
||||||
->withQueryString(),
|
->withQueryString(),
|
||||||
'filters' => $request->only(['search'])
|
'filters' => $request->only(['search'])
|
||||||
]);
|
]);
|
||||||
|
|
@ -164,7 +164,7 @@ public function show(ClientCase $clientCase)
|
||||||
->orderByDesc('created_at')->get(),
|
->orderByDesc('created_at')->get(),
|
||||||
'activities' => $case->activities()->with(['action', 'decision'])
|
'activities' => $case->activities()->with(['action', 'decision'])
|
||||||
->orderByDesc('created_at')
|
->orderByDesc('created_at')
|
||||||
->paginate(15),
|
->paginate(20, ['*'], 'activities'),
|
||||||
'contract_types' => \App\Models\ContractType::whereNull('deleted_at')->get(),
|
'contract_types' => \App\Models\ContractType::whereNull('deleted_at')->get(),
|
||||||
'actions' => \App\Models\Action::with('decisions')->get()
|
'actions' => \App\Models\Action::with('decisions')->get()
|
||||||
]);
|
]);
|
||||||
|
|
|
||||||
66
app/Http/Controllers/PostController.php
Normal file
66
app/Http/Controllers/PostController.php
Normal file
|
|
@ -0,0 +1,66 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Models\Post;
|
||||||
|
use App\Http\Requests\StorePostRequest;
|
||||||
|
use App\Http\Requests\UpdatePostRequest;
|
||||||
|
|
||||||
|
class PostController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Display a listing of the resource.
|
||||||
|
*/
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the form for creating a new resource.
|
||||||
|
*/
|
||||||
|
public function create()
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store a newly created resource in storage.
|
||||||
|
*/
|
||||||
|
public function store(StorePostRequest $request)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the specified resource.
|
||||||
|
*/
|
||||||
|
public function show(Post $post)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the form for editing the specified resource.
|
||||||
|
*/
|
||||||
|
public function edit(Post $post)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the specified resource in storage.
|
||||||
|
*/
|
||||||
|
public function update(UpdatePostRequest $request, Post $post)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the specified resource from storage.
|
||||||
|
*/
|
||||||
|
public function destroy(Post $post)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
||||||
28
app/Http/Requests/StorePostRequest.php
Normal file
28
app/Http/Requests/StorePostRequest.php
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Requests;
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
|
class StorePostRequest extends FormRequest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*/
|
||||||
|
public function authorize(): bool
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the validation rules that apply to the request.
|
||||||
|
*
|
||||||
|
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
|
||||||
|
*/
|
||||||
|
public function rules(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
//
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
28
app/Http/Requests/UpdatePostRequest.php
Normal file
28
app/Http/Requests/UpdatePostRequest.php
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Requests;
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
|
class UpdatePostRequest extends FormRequest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*/
|
||||||
|
public function authorize(): bool
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the validation rules that apply to the request.
|
||||||
|
*
|
||||||
|
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
|
||||||
|
*/
|
||||||
|
public function rules(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
//
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -6,11 +6,13 @@
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||||
|
use Laravel\Scout\Searchable;
|
||||||
|
|
||||||
class Action extends Model
|
class Action extends Model
|
||||||
{
|
{
|
||||||
/** @use HasFactory<\Database\Factories\ActionFactory> */
|
/** @use HasFactory<\Database\Factories\ActionFactory> */
|
||||||
use HasFactory;
|
use HasFactory;
|
||||||
|
use Searchable;
|
||||||
|
|
||||||
public function decisions(): BelongsToMany
|
public function decisions(): BelongsToMany
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -7,12 +7,15 @@
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||||
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
use Laravel\Scout\Searchable;
|
||||||
|
|
||||||
class Client extends Model
|
class Client extends Model
|
||||||
{
|
{
|
||||||
/** @use HasFactory<\Database\Factories\ClientFactory> */
|
/** @use HasFactory<\Database\Factories\ClientFactory> */
|
||||||
use HasFactory;
|
use HasFactory;
|
||||||
use Uuid;
|
use Uuid;
|
||||||
|
use Searchable;
|
||||||
|
|
||||||
protected $fillable = [
|
protected $fillable = [
|
||||||
'person_id'
|
'person_id'
|
||||||
|
|
@ -23,6 +26,26 @@ class Client extends Model
|
||||||
'person_id',
|
'person_id',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
|
protected function makeAllSearchableUsing(Builder $query): Builder
|
||||||
|
{
|
||||||
|
return $query->with('person');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toSearchableArray(): array
|
||||||
|
{
|
||||||
|
$person = [
|
||||||
|
'full_name' => $this->person->full_name,
|
||||||
|
'addresses' => $this->person->addresses,
|
||||||
|
'phones' => $this->person->phones
|
||||||
|
];
|
||||||
|
|
||||||
|
return [
|
||||||
|
'person' => $person
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public function person(): BelongsTo
|
public function person(): BelongsTo
|
||||||
{
|
{
|
||||||
return $this->belongsTo(\App\Models\Person\Person::class);
|
return $this->belongsTo(\App\Models\Person\Person::class);
|
||||||
|
|
|
||||||
|
|
@ -7,12 +7,15 @@
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||||
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
use Laravel\Scout\Searchable;
|
||||||
|
|
||||||
class ClientCase extends Model
|
class ClientCase extends Model
|
||||||
{
|
{
|
||||||
/** @use HasFactory<\Database\Factories\ClientCaseFactory> */
|
/** @use HasFactory<\Database\Factories\ClientCaseFactory> */
|
||||||
use HasFactory;
|
use HasFactory;
|
||||||
use Uuid;
|
use Uuid;
|
||||||
|
use Searchable;
|
||||||
|
|
||||||
protected $fillable = [
|
protected $fillable = [
|
||||||
'client_id'
|
'client_id'
|
||||||
|
|
@ -24,6 +27,20 @@ class ClientCase extends Model
|
||||||
'person_id'
|
'person_id'
|
||||||
];
|
];
|
||||||
|
|
||||||
|
protected function makeAllSearchableUsing(Builder $query): Builder
|
||||||
|
{
|
||||||
|
return $query->with('person');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toSearchableArray(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'person' => $this->person,
|
||||||
|
'addresses' => $this->person->addresses,
|
||||||
|
'phones' => $this->person->phones
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
public function client(): BelongsTo
|
public function client(): BelongsTo
|
||||||
{
|
{
|
||||||
return $this->belongsTo(\App\Models\Client::class);
|
return $this->belongsTo(\App\Models\Client::class);
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,9 @@
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||||
use Illuminate\Database\Eloquent\Relations\HasOne;
|
use Illuminate\Database\Eloquent\Relations\HasOne;
|
||||||
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
use Laravel\Sanctum\HasApiTokens;
|
use Laravel\Sanctum\HasApiTokens;
|
||||||
|
use Laravel\Scout\Searchable;
|
||||||
|
|
||||||
class Person extends Model
|
class Person extends Model
|
||||||
{
|
{
|
||||||
|
|
@ -16,6 +18,7 @@ class Person extends Model
|
||||||
/** @use HasFactory<\Database\Factories\Person/PersonFactory> */
|
/** @use HasFactory<\Database\Factories\Person/PersonFactory> */
|
||||||
use HasFactory;
|
use HasFactory;
|
||||||
use Uuid;
|
use Uuid;
|
||||||
|
use Searchable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The attributes that are mass assignable.
|
* The attributes that are mass assignable.
|
||||||
|
|
@ -52,6 +55,22 @@ protected static function booted(){
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function makeAllSearchableUsing(Builder $query): Builder
|
||||||
|
{
|
||||||
|
return $query->with(['addresses', 'phones']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toSearchableArray(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'first_name' => $this->first_name,
|
||||||
|
'last_name' => $this->last_name,
|
||||||
|
'full_name' => $this->full_name,
|
||||||
|
'addresses' => $this->addresses,
|
||||||
|
'phones' => $this->phones
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public function phones(): HasMany
|
public function phones(): HasMany
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -5,11 +5,13 @@
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
|
use Laravel\Scout\Searchable;
|
||||||
|
|
||||||
class PersonAddress extends Model
|
class PersonAddress extends Model
|
||||||
{
|
{
|
||||||
/** @use HasFactory<\Database\Factories\Person/PersonAddressFactory> */
|
/** @use HasFactory<\Database\Factories\Person/PersonAddressFactory> */
|
||||||
use HasFactory;
|
use HasFactory;
|
||||||
|
use Searchable;
|
||||||
|
|
||||||
protected $fillable = [
|
protected $fillable = [
|
||||||
'address',
|
'address',
|
||||||
|
|
@ -26,6 +28,14 @@ class PersonAddress extends Model
|
||||||
'deleted'
|
'deleted'
|
||||||
];
|
];
|
||||||
|
|
||||||
|
public function toSearchableArray(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'address' => $this->address,
|
||||||
|
'country' => $this->country
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
protected static function booted(){
|
protected static function booted(){
|
||||||
static::creating(function (PersonAddress $address) {
|
static::creating(function (PersonAddress $address) {
|
||||||
$address->user_id = auth()->id();
|
$address->user_id = auth()->id();
|
||||||
|
|
|
||||||
|
|
@ -6,11 +6,13 @@
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
|
use Laravel\Scout\Searchable;
|
||||||
|
|
||||||
class PersonPhone extends Model
|
class PersonPhone extends Model
|
||||||
{
|
{
|
||||||
/** @use HasFactory<\Database\Factories\Person/PersonPhoneFactory> */
|
/** @use HasFactory<\Database\Factories\Person/PersonPhoneFactory> */
|
||||||
use HasFactory;
|
use HasFactory;
|
||||||
|
use Searchable;
|
||||||
|
|
||||||
protected $fillable = [
|
protected $fillable = [
|
||||||
'nu',
|
'nu',
|
||||||
|
|
@ -27,6 +29,13 @@ class PersonPhone extends Model
|
||||||
'deleted'
|
'deleted'
|
||||||
];
|
];
|
||||||
|
|
||||||
|
public function toSearchableArray(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'nu' => $this->nu
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
protected static function booted(){
|
protected static function booted(){
|
||||||
static::creating(function (PersonPhone $personPhone) {
|
static::creating(function (PersonPhone $personPhone) {
|
||||||
if(!isset($personPhone->user_id)){
|
if(!isset($personPhone->user_id)){
|
||||||
|
|
|
||||||
18
app/Models/Post.php
Normal file
18
app/Models/Post.php
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Laravel\Scout\Searchable;
|
||||||
|
|
||||||
|
class Post extends Model
|
||||||
|
{
|
||||||
|
use HasFactory, Searchable;
|
||||||
|
|
||||||
|
public function toSearchableArray()
|
||||||
|
{
|
||||||
|
$array = $this->toArray();
|
||||||
|
return $array;
|
||||||
|
}
|
||||||
|
}
|
||||||
66
app/Policies/PostPolicy.php
Normal file
66
app/Policies/PostPolicy.php
Normal file
|
|
@ -0,0 +1,66 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Policies;
|
||||||
|
|
||||||
|
use App\Models\Post;
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Auth\Access\Response;
|
||||||
|
|
||||||
|
class PostPolicy
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine whether the user can view any models.
|
||||||
|
*/
|
||||||
|
public function viewAny(User $user): bool
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether the user can view the model.
|
||||||
|
*/
|
||||||
|
public function view(User $user, Post $post): bool
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether the user can create models.
|
||||||
|
*/
|
||||||
|
public function create(User $user): bool
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether the user can update the model.
|
||||||
|
*/
|
||||||
|
public function update(User $user, Post $post): bool
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether the user can delete the model.
|
||||||
|
*/
|
||||||
|
public function delete(User $user, Post $post): bool
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether the user can restore the model.
|
||||||
|
*/
|
||||||
|
public function restore(User $user, Post $post): bool
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether the user can permanently delete the model.
|
||||||
|
*/
|
||||||
|
public function forceDelete(User $user, Post $post): bool
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -6,13 +6,17 @@
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"require": {
|
"require": {
|
||||||
"php": "^8.2",
|
"php": "^8.2",
|
||||||
|
"algolia/scout-extended": "3.1",
|
||||||
"arielmejiadev/larapex-charts": "^2.1",
|
"arielmejiadev/larapex-charts": "^2.1",
|
||||||
"diglactic/laravel-breadcrumbs": "^9.0",
|
"diglactic/laravel-breadcrumbs": "^9.0",
|
||||||
|
"http-interop/http-factory-guzzle": "^1.2",
|
||||||
"inertiajs/inertia-laravel": "^1.0",
|
"inertiajs/inertia-laravel": "^1.0",
|
||||||
"laravel/framework": "^11.9",
|
"laravel/framework": "^11.9",
|
||||||
"laravel/jetstream": "^5.2",
|
"laravel/jetstream": "^5.2",
|
||||||
"laravel/sanctum": "^4.0",
|
"laravel/sanctum": "^4.0",
|
||||||
|
"laravel/scout": "^10.11",
|
||||||
"laravel/tinker": "^2.9",
|
"laravel/tinker": "^2.9",
|
||||||
|
"meilisearch/meilisearch-php": "^1.11",
|
||||||
"robertboes/inertia-breadcrumbs": "^0.6.0",
|
"robertboes/inertia-breadcrumbs": "^0.6.0",
|
||||||
"tightenco/ziggy": "^2.0"
|
"tightenco/ziggy": "^2.0"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
871
composer.lock
generated
871
composer.lock
generated
File diff suppressed because it is too large
Load Diff
|
|
@ -95,6 +95,10 @@
|
||||||
'prefix_indexes' => true,
|
'prefix_indexes' => true,
|
||||||
'search_path' => 'public',
|
'search_path' => 'public',
|
||||||
'sslmode' => 'prefer',
|
'sslmode' => 'prefer',
|
||||||
|
'options' => [
|
||||||
|
'LC_COLLATE' => env('PGSQL_LC_COLLATE', 'en_US.UTF-8'),
|
||||||
|
'LC_CTYPE' => env('PGSQL_LC_CTYPE', 'en_US.UTF-8'),
|
||||||
|
]
|
||||||
],
|
],
|
||||||
|
|
||||||
'sqlsrv' => [
|
'sqlsrv' => [
|
||||||
|
|
|
||||||
203
config/scout.php
Normal file
203
config/scout.php
Normal file
|
|
@ -0,0 +1,203 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Default Search Engine
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This option controls the default search connection that gets used while
|
||||||
|
| using Laravel Scout. This connection is used when syncing all models
|
||||||
|
| to the search service. You should adjust this based on your needs.
|
||||||
|
|
|
||||||
|
| Supported: "algolia", "meilisearch", "typesense",
|
||||||
|
| "database", "collection", "null"
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'driver' => env('SCOUT_DRIVER', 'database'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Index Prefix
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Here you may specify a prefix that will be applied to all search index
|
||||||
|
| names used by Scout. This prefix may be useful if you have multiple
|
||||||
|
| "tenants" or applications sharing the same search infrastructure.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'prefix' => env('SCOUT_PREFIX', ''),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Queue Data Syncing
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This option allows you to control if the operations that sync your data
|
||||||
|
| with your search engines are queued. When this is set to "true" then
|
||||||
|
| all automatic data syncing will get queued for better performance.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'queue' => env('SCOUT_QUEUE', true),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Database Transactions
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This configuration option determines if your data will only be synced
|
||||||
|
| with your search indexes after every open database transaction has
|
||||||
|
| been committed, thus preventing any discarded data from syncing.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'after_commit' => false,
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Chunk Sizes
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| These options allow you to control the maximum chunk size when you are
|
||||||
|
| mass importing data into the search engine. This allows you to fine
|
||||||
|
| tune each of these chunk sizes based on the power of the servers.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'chunk' => [
|
||||||
|
'searchable' => 500,
|
||||||
|
'unsearchable' => 500,
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Soft Deletes
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This option allows to control whether to keep soft deleted records in
|
||||||
|
| the search indexes. Maintaining soft deleted records can be useful
|
||||||
|
| if your application still needs to search for the records later.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'soft_delete' => true,
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Identify User
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This option allows you to control whether to notify the search engine
|
||||||
|
| of the user performing the search. This is sometimes useful if the
|
||||||
|
| engine supports any analytics based on this application's users.
|
||||||
|
|
|
||||||
|
| Supported engines: "algolia"
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'identify' => env('SCOUT_IDENTIFY', false),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Algolia Configuration
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Here you may configure your Algolia settings. Algolia is a cloud hosted
|
||||||
|
| search engine which works great with Scout out of the box. Just plug
|
||||||
|
| in your application ID and admin API key to get started searching.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'algolia' => [
|
||||||
|
'id' => env('ALGOLIA_APP_ID', 'ZDAXR87LZV'),
|
||||||
|
'secret' => env('ALGOLIA_SECRET', '8797318d18e10541ad15d49ae1e64db2'),
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Meilisearch Configuration
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Here you may configure your Meilisearch settings. Meilisearch is an open
|
||||||
|
| source search engine with minimal configuration. Below, you can state
|
||||||
|
| the host and key information for your own Meilisearch installation.
|
||||||
|
|
|
||||||
|
| See: https://www.meilisearch.com/docs/learn/configuration/instance_options#all-instance-options
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'meilisearch' => [
|
||||||
|
'host' => env('MEILISEARCH_HOST', 'http://localhost:7700'),
|
||||||
|
'key' => env('MEILISEARCH_KEY'),
|
||||||
|
'index-settings' => [
|
||||||
|
// 'users' => [
|
||||||
|
// 'filterableAttributes'=> ['id', 'name', 'email'],
|
||||||
|
// ],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Typesense Configuration
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Here you may configure your Typesense settings. Typesense is an open
|
||||||
|
| source search engine using minimal configuration. Below, you will
|
||||||
|
| state the host, key, and schema configuration for the instance.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'typesense' => [
|
||||||
|
'client-settings' => [
|
||||||
|
'api_key' => env('TYPESENSE_API_KEY', 'xyz'),
|
||||||
|
'nodes' => [
|
||||||
|
[
|
||||||
|
'host' => env('TYPESENSE_HOST', 'localhost'),
|
||||||
|
'port' => env('TYPESENSE_PORT', '8108'),
|
||||||
|
'path' => env('TYPESENSE_PATH', ''),
|
||||||
|
'protocol' => env('TYPESENSE_PROTOCOL', 'http'),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'nearest_node' => [
|
||||||
|
'host' => env('TYPESENSE_HOST', 'localhost'),
|
||||||
|
'port' => env('TYPESENSE_PORT', '8108'),
|
||||||
|
'path' => env('TYPESENSE_PATH', ''),
|
||||||
|
'protocol' => env('TYPESENSE_PROTOCOL', 'http'),
|
||||||
|
],
|
||||||
|
'connection_timeout_seconds' => env('TYPESENSE_CONNECTION_TIMEOUT_SECONDS', 2),
|
||||||
|
'healthcheck_interval_seconds' => env('TYPESENSE_HEALTHCHECK_INTERVAL_SECONDS', 30),
|
||||||
|
'num_retries' => env('TYPESENSE_NUM_RETRIES', 3),
|
||||||
|
'retry_interval_seconds' => env('TYPESENSE_RETRY_INTERVAL_SECONDS', 1),
|
||||||
|
],
|
||||||
|
// 'max_total_results' => env('TYPESENSE_MAX_TOTAL_RESULTS', 1000),
|
||||||
|
'model-settings' => [
|
||||||
|
// User::class => [
|
||||||
|
// 'collection-schema' => [
|
||||||
|
// 'fields' => [
|
||||||
|
// [
|
||||||
|
// 'name' => 'id',
|
||||||
|
// 'type' => 'string',
|
||||||
|
// ],
|
||||||
|
// [
|
||||||
|
// 'name' => 'name',
|
||||||
|
// 'type' => 'string',
|
||||||
|
// ],
|
||||||
|
// [
|
||||||
|
// 'name' => 'created_at',
|
||||||
|
// 'type' => 'int64',
|
||||||
|
// ],
|
||||||
|
// ],
|
||||||
|
// 'default_sorting_field' => 'created_at',
|
||||||
|
// ],
|
||||||
|
// 'search-parameters' => [
|
||||||
|
// 'query_by' => 'name'
|
||||||
|
// ],
|
||||||
|
// ],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
];
|
||||||
25
database/factories/PostFactory.php
Normal file
25
database/factories/PostFactory.php
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Database\Factories;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Post>
|
||||||
|
*/
|
||||||
|
class PostFactory extends Factory
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Define the model's default state.
|
||||||
|
*
|
||||||
|
* @return array<string, mixed>
|
||||||
|
*/
|
||||||
|
public function definition(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'title' => fake()->sentence(),
|
||||||
|
'body' => fake()->paragraph(),
|
||||||
|
'slug' => fake()->slug(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
30
database/migrations/2024_11_17_123507_create_posts_table.php
Normal file
30
database/migrations/2024_11_17_123507_create_posts_table.php
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('posts', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->string('title');
|
||||||
|
$table->text('body');
|
||||||
|
$table->string('slug');
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('posts');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -69,7 +69,7 @@ public function run(): void
|
||||||
'nu' => rand(100000,200000),
|
'nu' => rand(100000,200000),
|
||||||
'first_name' => '',
|
'first_name' => '',
|
||||||
'last_name' => '',
|
'last_name' => '',
|
||||||
'full_name' => 'test d.o.o.',
|
'full_name' => 'Naročnik d.o.o.',
|
||||||
'gender' => 'm',
|
'gender' => 'm',
|
||||||
'birthday' => '2000-01-01',
|
'birthday' => '2000-01-01',
|
||||||
'tax_number' => '22424345',
|
'tax_number' => '22424345',
|
||||||
|
|
|
||||||
17
database/seeders/PostSeeder.php
Normal file
17
database/seeders/PostSeeder.php
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Database\Seeders;
|
||||||
|
|
||||||
|
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||||
|
use Illuminate\Database\Seeder;
|
||||||
|
|
||||||
|
class PostSeeder extends Seeder
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the database seeds.
|
||||||
|
*/
|
||||||
|
public function run(): void
|
||||||
|
{
|
||||||
|
\App\Models\Post::factory(500)->create();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
|
"module": "CommonJS",
|
||||||
|
"target": "ES6",
|
||||||
"baseUrl": ".",
|
"baseUrl": ".",
|
||||||
"paths": {
|
"paths": {
|
||||||
"@/*": ["resources/js/*"]
|
"@/*": ["resources/js/*"]
|
||||||
|
|
|
||||||
115
package-lock.json
generated
115
package-lock.json
generated
|
|
@ -5,6 +5,11 @@
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@fortawesome/fontawesome-svg-core": "^6.6.0",
|
||||||
|
"@fortawesome/free-brands-svg-icons": "^6.6.0",
|
||||||
|
"@fortawesome/free-regular-svg-icons": "^6.6.0",
|
||||||
|
"@fortawesome/free-solid-svg-icons": "^6.6.0",
|
||||||
|
"@fortawesome/vue-fontawesome": "^3.0.8",
|
||||||
"@headlessui/vue": "^1.7.23",
|
"@headlessui/vue": "^1.7.23",
|
||||||
"@heroicons/vue": "^2.1.5",
|
"@heroicons/vue": "^2.1.5",
|
||||||
"@vuepic/vue-datepicker": "^9.0.3",
|
"@vuepic/vue-datepicker": "^9.0.3",
|
||||||
|
|
@ -12,11 +17,15 @@
|
||||||
"flowbite": "^2.5.2",
|
"flowbite": "^2.5.2",
|
||||||
"flowbite-vue": "^0.1.6",
|
"flowbite-vue": "^0.1.6",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
|
"material-design-icons-iconfont": "^6.7.0",
|
||||||
"tailwindcss-inner-border": "^0.2.0",
|
"tailwindcss-inner-border": "^0.2.0",
|
||||||
"vue3-apexcharts": "^1.7.0"
|
"vue-search-input": "^1.1.16",
|
||||||
|
"vue3-apexcharts": "^1.7.0",
|
||||||
|
"vuedraggable": "^4.1.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@inertiajs/vue3": "^1.0.14",
|
"@inertiajs/vue3": "^1.0.14",
|
||||||
|
"@mdi/js": "^7.4.47",
|
||||||
"@tailwindcss/forms": "^0.5.7",
|
"@tailwindcss/forms": "^0.5.7",
|
||||||
"@tailwindcss/typography": "^0.5.10",
|
"@tailwindcss/typography": "^0.5.10",
|
||||||
"@vitejs/plugin-vue": "^5.0.0",
|
"@vitejs/plugin-vue": "^5.0.0",
|
||||||
|
|
@ -515,6 +524,73 @@
|
||||||
"integrity": "sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig==",
|
"integrity": "sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/@fortawesome/fontawesome-common-types": {
|
||||||
|
"version": "6.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.6.0.tgz",
|
||||||
|
"integrity": "sha512-xyX0X9mc0kyz9plIyryrRbl7ngsA9jz77mCZJsUkLl+ZKs0KWObgaEBoSgQiYWAsSmjz/yjl0F++Got0Mdp4Rw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@fortawesome/fontawesome-svg-core": {
|
||||||
|
"version": "6.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.6.0.tgz",
|
||||||
|
"integrity": "sha512-KHwPkCk6oRT4HADE7smhfsKudt9N/9lm6EJ5BVg0tD1yPA5hht837fB87F8pn15D8JfTqQOjhKTktwmLMiD7Kg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@fortawesome/fontawesome-common-types": "6.6.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@fortawesome/free-brands-svg-icons": {
|
||||||
|
"version": "6.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-6.6.0.tgz",
|
||||||
|
"integrity": "sha512-1MPD8lMNW/earme4OQi1IFHtmHUwAKgghXlNwWi9GO7QkTfD+IIaYpIai4m2YJEzqfEji3jFHX1DZI5pbY/biQ==",
|
||||||
|
"license": "(CC-BY-4.0 AND MIT)",
|
||||||
|
"dependencies": {
|
||||||
|
"@fortawesome/fontawesome-common-types": "6.6.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@fortawesome/free-regular-svg-icons": {
|
||||||
|
"version": "6.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-6.6.0.tgz",
|
||||||
|
"integrity": "sha512-Yv9hDzL4aI73BEwSEh20clrY8q/uLxawaQ98lekBx6t9dQKDHcDzzV1p2YtBGTtolYtNqcWdniOnhzB+JPnQEQ==",
|
||||||
|
"license": "(CC-BY-4.0 AND MIT)",
|
||||||
|
"dependencies": {
|
||||||
|
"@fortawesome/fontawesome-common-types": "6.6.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@fortawesome/free-solid-svg-icons": {
|
||||||
|
"version": "6.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.6.0.tgz",
|
||||||
|
"integrity": "sha512-IYv/2skhEDFc2WGUcqvFJkeK39Q+HyPf5GHUrT/l2pKbtgEIv1al1TKd6qStR5OIwQdN1GZP54ci3y4mroJWjA==",
|
||||||
|
"license": "(CC-BY-4.0 AND MIT)",
|
||||||
|
"dependencies": {
|
||||||
|
"@fortawesome/fontawesome-common-types": "6.6.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@fortawesome/vue-fontawesome": {
|
||||||
|
"version": "3.0.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/@fortawesome/vue-fontawesome/-/vue-fontawesome-3.0.8.tgz",
|
||||||
|
"integrity": "sha512-yyHHAj4G8pQIDfaIsMvQpwKMboIZtcHTUvPqXjOHyldh1O1vZfH4W03VDPv5RvI9P6DLTzJQlmVgj9wCf7c2Fw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"@fortawesome/fontawesome-svg-core": "~1 || ~6",
|
||||||
|
"vue": ">= 3.0.0 < 4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@headlessui/vue": {
|
"node_modules/@headlessui/vue": {
|
||||||
"version": "1.7.23",
|
"version": "1.7.23",
|
||||||
"resolved": "https://registry.npmjs.org/@headlessui/vue/-/vue-1.7.23.tgz",
|
"resolved": "https://registry.npmjs.org/@headlessui/vue/-/vue-1.7.23.tgz",
|
||||||
|
|
@ -632,6 +708,13 @@
|
||||||
"@jridgewell/sourcemap-codec": "^1.4.14"
|
"@jridgewell/sourcemap-codec": "^1.4.14"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@mdi/js": {
|
||||||
|
"version": "7.4.47",
|
||||||
|
"resolved": "https://registry.npmjs.org/@mdi/js/-/js-7.4.47.tgz",
|
||||||
|
"integrity": "sha512-KPnNOtm5i2pMabqZxpUz7iQf+mfrYZyKCZ8QNz85czgEt7cuHcGorWfdzUMWYA0SD+a6Hn4FmJ+YhzzzjkTZrQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "Apache-2.0"
|
||||||
|
},
|
||||||
"node_modules/@nodelib/fs.scandir": {
|
"node_modules/@nodelib/fs.scandir": {
|
||||||
"version": "2.1.5",
|
"version": "2.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
|
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
|
||||||
|
|
@ -2335,6 +2418,12 @@
|
||||||
"@jridgewell/sourcemap-codec": "^1.5.0"
|
"@jridgewell/sourcemap-codec": "^1.5.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/material-design-icons-iconfont": {
|
||||||
|
"version": "6.7.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/material-design-icons-iconfont/-/material-design-icons-iconfont-6.7.0.tgz",
|
||||||
|
"integrity": "sha512-lSj71DgVv20kO0kGbs42icDzbRot61gEDBLQACzkUuznRQBUYmbxzEkGU6dNBb5fRWHMaScYlAXX96HQ4/cJWA==",
|
||||||
|
"license": "Apache-2.0"
|
||||||
|
},
|
||||||
"node_modules/merge2": {
|
"node_modules/merge2": {
|
||||||
"version": "1.4.1",
|
"version": "1.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
|
||||||
|
|
@ -2974,6 +3063,12 @@
|
||||||
"url": "https://github.com/sponsors/isaacs"
|
"url": "https://github.com/sponsors/isaacs"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/sortablejs": {
|
||||||
|
"version": "1.14.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.14.0.tgz",
|
||||||
|
"integrity": "sha512-pBXvQCs5/33fdN1/39pPL0NZF20LeRbLQ5jtnheIPN9JQAaufGjKdWduZn4U7wCtVuzKhmRkI0DFYHYRbB2H1w==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/source-map-js": {
|
"node_modules/source-map-js": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
|
||||||
|
|
@ -3466,6 +3561,12 @@
|
||||||
"vue": "^3.0.0"
|
"vue": "^3.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/vue-search-input": {
|
||||||
|
"version": "1.1.16",
|
||||||
|
"resolved": "https://registry.npmjs.org/vue-search-input/-/vue-search-input-1.1.16.tgz",
|
||||||
|
"integrity": "sha512-hMZJHN/HppamwF24vPVhWVy4334WEmChkuAEnmDuiR3SeKrAPjK5mYb0vKBiAWP4QL1p2d+JhvbUe444uDTEMw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/vue3-apexcharts": {
|
"node_modules/vue3-apexcharts": {
|
||||||
"version": "1.7.0",
|
"version": "1.7.0",
|
||||||
"resolved": "https://registry.npmjs.org/vue3-apexcharts/-/vue3-apexcharts-1.7.0.tgz",
|
"resolved": "https://registry.npmjs.org/vue3-apexcharts/-/vue3-apexcharts-1.7.0.tgz",
|
||||||
|
|
@ -3476,6 +3577,18 @@
|
||||||
"vue": "> 3.0.0"
|
"vue": "> 3.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/vuedraggable": {
|
||||||
|
"version": "4.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/vuedraggable/-/vuedraggable-4.1.0.tgz",
|
||||||
|
"integrity": "sha512-FU5HCWBmsf20GpP3eudURW3WdWTKIbEIQxh9/8GE806hydR9qZqRRxRE3RjqX7PkuLuMQG/A7n3cfj9rCEchww==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"sortablejs": "1.14.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"vue": "^3.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/which": {
|
"node_modules/which": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||||
|
|
|
||||||
11
package.json
11
package.json
|
|
@ -7,6 +7,7 @@
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@inertiajs/vue3": "^1.0.14",
|
"@inertiajs/vue3": "^1.0.14",
|
||||||
|
"@mdi/js": "^7.4.47",
|
||||||
"@tailwindcss/forms": "^0.5.7",
|
"@tailwindcss/forms": "^0.5.7",
|
||||||
"@tailwindcss/typography": "^0.5.10",
|
"@tailwindcss/typography": "^0.5.10",
|
||||||
"@vitejs/plugin-vue": "^5.0.0",
|
"@vitejs/plugin-vue": "^5.0.0",
|
||||||
|
|
@ -19,6 +20,11 @@
|
||||||
"vue": "^3.3.13"
|
"vue": "^3.3.13"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@fortawesome/fontawesome-svg-core": "^6.6.0",
|
||||||
|
"@fortawesome/free-brands-svg-icons": "^6.6.0",
|
||||||
|
"@fortawesome/free-regular-svg-icons": "^6.6.0",
|
||||||
|
"@fortawesome/free-solid-svg-icons": "^6.6.0",
|
||||||
|
"@fortawesome/vue-fontawesome": "^3.0.8",
|
||||||
"@headlessui/vue": "^1.7.23",
|
"@headlessui/vue": "^1.7.23",
|
||||||
"@heroicons/vue": "^2.1.5",
|
"@heroicons/vue": "^2.1.5",
|
||||||
"@vuepic/vue-datepicker": "^9.0.3",
|
"@vuepic/vue-datepicker": "^9.0.3",
|
||||||
|
|
@ -26,7 +32,10 @@
|
||||||
"flowbite": "^2.5.2",
|
"flowbite": "^2.5.2",
|
||||||
"flowbite-vue": "^0.1.6",
|
"flowbite-vue": "^0.1.6",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
|
"material-design-icons-iconfont": "^6.7.0",
|
||||||
"tailwindcss-inner-border": "^0.2.0",
|
"tailwindcss-inner-border": "^0.2.0",
|
||||||
"vue3-apexcharts": "^1.7.0"
|
"vue-search-input": "^1.1.16",
|
||||||
|
"vue3-apexcharts": "^1.7.0",
|
||||||
|
"vuedraggable": "^4.1.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
@import '/node_modules/floating-vue/dist/style.css';
|
@import '/node_modules/floating-vue/dist/style.css';
|
||||||
|
@import '/node_modules/vue-search-input/dist/styles.css';
|
||||||
@tailwind base;
|
@tailwind base;
|
||||||
@tailwind components;
|
@tailwind components;
|
||||||
@tailwind utilities;
|
@tailwind utilities;
|
||||||
|
|
|
||||||
135
resources/js/Components/DragDropList.vue
Normal file
135
resources/js/Components/DragDropList.vue
Normal file
|
|
@ -0,0 +1,135 @@
|
||||||
|
<script setup>
|
||||||
|
import { FwbListGroup, FwbListGroupItem } from 'flowbite-vue';
|
||||||
|
import { computed, onMounted, ref, useTemplateRef, watch } from 'vue';
|
||||||
|
import draggable from 'vuedraggable';
|
||||||
|
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
list1: Array,
|
||||||
|
list2: Array
|
||||||
|
});
|
||||||
|
|
||||||
|
const item1 = {
|
||||||
|
id: 1,
|
||||||
|
name: 'Item 1'
|
||||||
|
}
|
||||||
|
|
||||||
|
const item2 = {
|
||||||
|
id: 2,
|
||||||
|
name: 'Item 2'
|
||||||
|
}
|
||||||
|
|
||||||
|
const item3 = {
|
||||||
|
id: 3,
|
||||||
|
name: 'Item 3'
|
||||||
|
}
|
||||||
|
|
||||||
|
const isDragging = ref(false);
|
||||||
|
|
||||||
|
let containerOne = ref([item1, item2])
|
||||||
|
let containerTwo = ref([item3])
|
||||||
|
|
||||||
|
const dragOptions = computed(() => {
|
||||||
|
return {
|
||||||
|
animation: 200,
|
||||||
|
group: "actions",
|
||||||
|
disabled: false,
|
||||||
|
ghostClass: "ghost"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const removeAt = (idx, targeContainer) => {
|
||||||
|
targeContainer.splice(idx, 1);
|
||||||
|
};
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => containerOne.value,
|
||||||
|
(value) => {
|
||||||
|
console.log(value)
|
||||||
|
},
|
||||||
|
{ deep: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<div class="grid grid-cols-4 gap-4">
|
||||||
|
<draggable
|
||||||
|
class="list-group"
|
||||||
|
:list="containerOne"
|
||||||
|
item-key="id"
|
||||||
|
:component-data="{
|
||||||
|
tag: 'ul',
|
||||||
|
type: 'transition-group',
|
||||||
|
name: !isDragging ? 'flip-list' : null
|
||||||
|
}"
|
||||||
|
v-bind="dragOptions"
|
||||||
|
@start="isDragging = true"
|
||||||
|
@end="isDragging = false"
|
||||||
|
group="actions"
|
||||||
|
>
|
||||||
|
<template #item="{element, index}">
|
||||||
|
<fwb-list-group-item class="flex justify-between">
|
||||||
|
<span class="text">{{ element.name }} </span>
|
||||||
|
|
||||||
|
<i class=" cursor-pointer" @click="removeAt(index, containerOne)"><svg class="w-6 h-6 text-gray-800 dark:text-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
|
||||||
|
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18 17.94 6M18 18 6.06 6"/>
|
||||||
|
</svg></i>
|
||||||
|
</fwb-list-group-item>
|
||||||
|
</template>
|
||||||
|
</draggable>
|
||||||
|
<draggable
|
||||||
|
class="list-group"
|
||||||
|
:list="containerTwo"
|
||||||
|
:component-data="{
|
||||||
|
tag: 'ul',
|
||||||
|
type: 'transition-group',
|
||||||
|
name: !isDragging ? 'flip-list' : null
|
||||||
|
}"
|
||||||
|
item-key="id"
|
||||||
|
v-bind="dragOptions"
|
||||||
|
@start="isDragging = true"
|
||||||
|
@end="isDragging = false"
|
||||||
|
group="actions"
|
||||||
|
>
|
||||||
|
<template #item="{element, index}">
|
||||||
|
<fwb-list-group-item class="flex justify-between">
|
||||||
|
<span class="text">{{ element.name }} </span>
|
||||||
|
|
||||||
|
<i class="cursor-pointer" @click="removeAt(index, containerOne)"><svg class="w-6 h-6 text-gray-800 dark:text-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
|
||||||
|
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18 17.94 6M18 18 6.06 6"/>
|
||||||
|
</svg></i>
|
||||||
|
</fwb-list-group-item>
|
||||||
|
</template>
|
||||||
|
</draggable>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<style lang="css">
|
||||||
|
.button {
|
||||||
|
margin-top: 35px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flip-list-move {
|
||||||
|
transition: transform 0.5s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-move {
|
||||||
|
transition: transform 0s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ghost {
|
||||||
|
opacity: 0.5;
|
||||||
|
background: #c8ebfb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-group {
|
||||||
|
min-height: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-group-item {
|
||||||
|
cursor: move;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-group-item i {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
79
resources/js/Components/DragDropListEx.vue
Normal file
79
resources/js/Components/DragDropListEx.vue
Normal file
|
|
@ -0,0 +1,79 @@
|
||||||
|
<script setup>
|
||||||
|
import { ref } from 'vue';
|
||||||
|
|
||||||
|
const item1 = {
|
||||||
|
id: 1,
|
||||||
|
text: 'Item 1'
|
||||||
|
};
|
||||||
|
const item2 = {
|
||||||
|
id: 2,
|
||||||
|
text: 'Item 2'
|
||||||
|
};
|
||||||
|
|
||||||
|
let containerOne = ref([item1, item2])
|
||||||
|
let containerTwo = ref([])
|
||||||
|
|
||||||
|
const handleDragStart = (event, container, itemData) => {
|
||||||
|
event.dataTransfer.setData('application/json', JSON.stringify(itemData));
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDrop = (event, targetContainer) => {
|
||||||
|
const itemData = JSON.parse(event.dataTransfer.getData('application/json'));
|
||||||
|
if (targetContainer === containerOne.value) {
|
||||||
|
containerTwo.value = containerTwo.value.filter(i => i.id !== itemData.id);
|
||||||
|
} else if (targetContainer === containerTwo.value) {
|
||||||
|
containerOne.value = containerOne.value.filter(i => i.id !== itemData.id);
|
||||||
|
}
|
||||||
|
targetContainer.push(itemData);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="drag-drop-container">
|
||||||
|
<div class="container-one"
|
||||||
|
v-on:dragover.prevent
|
||||||
|
v-on:drop="handleDrop($event, containerOne)">
|
||||||
|
<div class="item"
|
||||||
|
v-for="item in containerOne"
|
||||||
|
:key="item.id"
|
||||||
|
draggable="true"
|
||||||
|
v-on:dragstart="handleDragStart($event, containerOne, item)">
|
||||||
|
{{ item.text }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="container-two"
|
||||||
|
v-on:dragover.prevent
|
||||||
|
v-on:drop="handleDrop($event, containerTwo)">
|
||||||
|
<div class="item"
|
||||||
|
v-for="item in containerTwo"
|
||||||
|
:key="item.id"
|
||||||
|
draggable="true"
|
||||||
|
v-on:dragstart="handleDragStart($event, containerTwo, item)">
|
||||||
|
{{ item.text }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.drag-drop-container {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container-one, .container-two {
|
||||||
|
border: 1px solid #1a1a1a;
|
||||||
|
width: 600px;
|
||||||
|
height: 800px;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item {
|
||||||
|
padding: 10px;
|
||||||
|
background-color: black;
|
||||||
|
color: white;
|
||||||
|
cursor: pointer;
|
||||||
|
width: 90%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { computed, ref } from 'vue';
|
import { computed, onMounted, ref, watch } from 'vue';
|
||||||
import { Head, Link, router, usePage } from '@inertiajs/vue3';
|
import { Head, Link, router, usePage } from '@inertiajs/vue3';
|
||||||
import ApplicationMark from '@/Components/ApplicationMark.vue';
|
import ApplicationMark from '@/Components/ApplicationMark.vue';
|
||||||
import Banner from '@/Components/Banner.vue';
|
import Banner from '@/Components/Banner.vue';
|
||||||
|
|
@ -8,16 +8,66 @@ import DropdownLink from '@/Components/DropdownLink.vue';
|
||||||
import NavLink from '@/Components/NavLink.vue';
|
import NavLink from '@/Components/NavLink.vue';
|
||||||
import ResponsiveNavLink from '@/Components/ResponsiveNavLink.vue';
|
import ResponsiveNavLink from '@/Components/ResponsiveNavLink.vue';
|
||||||
import Breadcrumbs from '@/Components/Breadcrumbs.vue';
|
import Breadcrumbs from '@/Components/Breadcrumbs.vue';
|
||||||
|
import axios from 'axios';
|
||||||
|
import { debounce } from 'lodash';
|
||||||
|
import { FwbButton, FwbInput, FwbListGroup, FwbListGroupItem } from 'flowbite-vue';
|
||||||
|
import { AdjustmentIcon, SearchIcon } from '@/Utilities/Icons';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
title: String,
|
title: String,
|
||||||
});
|
});
|
||||||
|
|
||||||
const showingNavigationDropdown = ref(false);
|
const showingNavigationDropdown = ref(false);
|
||||||
|
const querySearchDiv = ref(null);
|
||||||
|
|
||||||
|
const querySearch = ref('');
|
||||||
|
|
||||||
|
const querySearchList = ref(true);
|
||||||
|
const querySearchResult = ref([]);
|
||||||
|
|
||||||
const logout = () => {
|
const logout = () => {
|
||||||
router.post(route('logout'));
|
router.post(route('logout'));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const setRoute = (index) => {
|
||||||
|
return route('client.show', index);
|
||||||
|
}
|
||||||
|
|
||||||
|
const onSearchFocus = () => {
|
||||||
|
if(querySearch.value.length > 0) {
|
||||||
|
querySearchList.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const onSearchBlue = () => {
|
||||||
|
setTimeout(() => querySearchList.value = true, 100)
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(querySearch, debounce((value) => {
|
||||||
|
axios.get(
|
||||||
|
route('search'),
|
||||||
|
{
|
||||||
|
params: {
|
||||||
|
query: value,
|
||||||
|
limit: 5,
|
||||||
|
tag: ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.then(function(res) {
|
||||||
|
querySearchResult.value = res.data
|
||||||
|
querySearchList.value = false;
|
||||||
|
console.log(res);
|
||||||
|
})
|
||||||
|
.catch(function(error){
|
||||||
|
console.log(error)
|
||||||
|
})
|
||||||
|
.finally(function(){
|
||||||
|
|
||||||
|
});
|
||||||
|
}, 300));
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
@ -65,6 +115,42 @@ const logout = () => {
|
||||||
|
|
||||||
<div class="hidden sm:flex sm:items-center sm:ms-6">
|
<div class="hidden sm:flex sm:items-center sm:ms-6">
|
||||||
<!-- Settings Dropdown -->
|
<!-- Settings Dropdown -->
|
||||||
|
<div>
|
||||||
|
<fwb-input
|
||||||
|
v-model="querySearch"
|
||||||
|
placeholder="Iskalnik..."
|
||||||
|
size="md"
|
||||||
|
@focus="onSearchFocus"
|
||||||
|
@blur="onSearchBlue"
|
||||||
|
>
|
||||||
|
<template #prefix>
|
||||||
|
<SearchIcon />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
</fwb-input>
|
||||||
|
<fwb-list-group ref="querySearchDiv" class="absolute" :hidden="querySearchList">
|
||||||
|
<fwb-list-group-item>
|
||||||
|
<div>
|
||||||
|
<p>Naročniki:</p>
|
||||||
|
<fwb-list-group>
|
||||||
|
<fwb-list-group-item hover v-for="client in querySearchResult.clients">
|
||||||
|
<a :href="route('client.show', {uuid: client.uuid})">{{ client.person.full_name }}</a>
|
||||||
|
</fwb-list-group-item>
|
||||||
|
</fwb-list-group>
|
||||||
|
</div>
|
||||||
|
</fwb-list-group-item>
|
||||||
|
<fwb-list-group-item>
|
||||||
|
<div>
|
||||||
|
<p>Primeri:</p>
|
||||||
|
<fwb-list-group>
|
||||||
|
<fwb-list-group-item hover v-for="clientCase in querySearchResult.client_cases">
|
||||||
|
<a :href="route('clientCase.show', {uuid: clientCase.uuid})">{{ clientCase.person.full_name }}</a>
|
||||||
|
</fwb-list-group-item>
|
||||||
|
</fwb-list-group>
|
||||||
|
</div>
|
||||||
|
</fwb-list-group-item>
|
||||||
|
</fwb-list-group>
|
||||||
|
</div>
|
||||||
<div class="ms-3 relative">
|
<div class="ms-3 relative">
|
||||||
<Dropdown align="right" width="48">
|
<Dropdown align="right" width="48">
|
||||||
<template #trigger>
|
<template #trigger>
|
||||||
|
|
@ -154,7 +240,6 @@ const logout = () => {
|
||||||
Nastavitve
|
Nastavitve
|
||||||
</ResponsiveNavLink>
|
</ResponsiveNavLink>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Responsive Settings Options -->
|
<!-- Responsive Settings Options -->
|
||||||
<div class="pt-4 pb-1 border-t border-gray-200">
|
<div class="pt-4 pb-1 border-t border-gray-200">
|
||||||
<div class="flex items-center px-4">
|
<div class="flex items-center px-4">
|
||||||
|
|
@ -233,11 +318,12 @@ const logout = () => {
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<!-- Page Heading -->
|
<!-- Page Heading -->
|
||||||
<header v-if="$slots.header" class="bg-white shadow">
|
<header v-if="$slots.header" class="bg-white shadow ">
|
||||||
<div class="max-w-7xl mx-auto py-6 px-4 sm:px-6 lg:px-8">
|
<div class="max-w-7xl mx-auto py-6 px-4 sm:px-6 lg:px-8">
|
||||||
<Breadcrumbs :breadcrumbs="$page.props.breadcrumbs"></Breadcrumbs>
|
<Breadcrumbs :breadcrumbs="$page.props.breadcrumbs"></Breadcrumbs>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<!-- Page Content -->
|
<!-- Page Content -->
|
||||||
|
|
|
||||||
|
|
@ -96,7 +96,7 @@ const closeDrawer = () => {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="pt-1">
|
<!--div class="pt-1">
|
||||||
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
|
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
|
||||||
<div class="bg-white overflow-hidden shadow-xl sm:rounded-lg border-l-4 border-blue-400">
|
<div class="bg-white overflow-hidden shadow-xl sm:rounded-lg border-l-4 border-blue-400">
|
||||||
<div class="mx-auto max-w-4x1 p-3">
|
<div class="mx-auto max-w-4x1 p-3">
|
||||||
|
|
@ -104,8 +104,8 @@ const closeDrawer = () => {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div-->
|
||||||
<div class="pt-12">
|
<div class="pt-6">
|
||||||
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
|
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
|
||||||
<div class="bg-white overflow-hidden shadow-xl sm:rounded-lg border-l-4 border-red-400">
|
<div class="bg-white overflow-hidden shadow-xl sm:rounded-lg border-l-4 border-red-400">
|
||||||
<div class="mx-auto max-w-4x1 p-3">
|
<div class="mx-auto max-w-4x1 p-3">
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,6 @@ const activeTab = ref('actions')
|
||||||
<div class="pt-12">
|
<div class="pt-12">
|
||||||
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
|
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
|
||||||
<div class="bg-white overflow-hidden shadow-xl sm:rounded-lg">
|
<div class="bg-white overflow-hidden shadow-xl sm:rounded-lg">
|
||||||
|
|
||||||
<fwb-tabs v-model="activeTab" variant="underline" >
|
<fwb-tabs v-model="activeTab" variant="underline" >
|
||||||
<fwb-tab name="actions" title="Actions">
|
<fwb-tab name="actions" title="Actions">
|
||||||
<ActionTable :actions="actions" />
|
<ActionTable :actions="actions" />
|
||||||
|
|
@ -28,7 +27,6 @@ const activeTab = ref('actions')
|
||||||
<DecisionTable :decisions="decisions" />
|
<DecisionTable :decisions="decisions" />
|
||||||
</fwb-tab>
|
</fwb-tab>
|
||||||
</fwb-tabs>
|
</fwb-tabs>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,36 +1,36 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import BasicTable from '@/Components/BasicTable.vue';
|
import { FwbTable, FwbTableBody, FwbTableHead, FwbTableHeadCell, FwbTableCell, FwbTableRow } from 'flowbite-vue';
|
||||||
import { LinkOptions as C_LINK, TableColumn as C_TD, TableRow as C_TR} from '@/Shared/AppObjects';
|
import { EditIcon, TrashBinIcon } from '@/Utilities/Icons';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
actions: Array
|
actions: Array
|
||||||
});
|
});
|
||||||
|
|
||||||
const header = [
|
|
||||||
C_TD.make('#', 'header'),
|
|
||||||
C_TD.make('Name', 'header'),
|
|
||||||
C_TD.make('Color tag', 'header'),
|
|
||||||
C_TD.make('Decisions', 'header')
|
|
||||||
];
|
|
||||||
|
|
||||||
const createBody = (data) => {
|
|
||||||
let content = [];
|
|
||||||
|
|
||||||
data.forEach((a) => {
|
|
||||||
const cols = [
|
|
||||||
C_TD.make(a.id, 'body'),
|
|
||||||
C_TD.make(a.name, 'body'),
|
|
||||||
C_TD.make(a.color_tag, 'body'),
|
|
||||||
C_TD.make(a.decisions.length, 'body')
|
|
||||||
];
|
|
||||||
|
|
||||||
content.push(C_TR.make(cols));
|
|
||||||
});
|
|
||||||
|
|
||||||
return content;
|
|
||||||
}
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<BasicTable :header="header" :body="createBody(actions)" />
|
<fwb-table>
|
||||||
|
<fwb-table-head>
|
||||||
|
<fwb-table-head-cell>#</fwb-table-head-cell>
|
||||||
|
<fwb-table-head-cell>Name</fwb-table-head-cell>
|
||||||
|
<fwb-table-head-cell>Color tag</fwb-table-head-cell>
|
||||||
|
<fwb-table-head-cell>Decisions</fwb-table-head-cell>
|
||||||
|
<fwb-table-head-cell>
|
||||||
|
<span class="sr-only">Edit</span>
|
||||||
|
</fwb-table-head-cell>
|
||||||
|
</fwb-table-head>
|
||||||
|
<fwb-table-body>
|
||||||
|
<fwb-table-row v-for="act in actions" :key="act.id">
|
||||||
|
<fwb-table-cell>{{ act.id }}</fwb-table-cell>
|
||||||
|
<fwb-table-cell>{{ act.name }}</fwb-table-cell>
|
||||||
|
<fwb-table-cell>{{ act.color_tag }}</fwb-table-cell>
|
||||||
|
<fwb-table-cell>{{ act.decisions.length }}</fwb-table-cell>
|
||||||
|
<fwb-table-cell>
|
||||||
|
<button><EditIcon /></button>
|
||||||
|
<button><TrashBinIcon /></button>
|
||||||
|
</fwb-table-cell>
|
||||||
|
</fwb-table-row>
|
||||||
|
</fwb-table-body>
|
||||||
|
</fwb-table>
|
||||||
</template>
|
</template>
|
||||||
19
resources/js/Pages/Testing.vue
Normal file
19
resources/js/Pages/Testing.vue
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
<script setup>
|
||||||
|
import DragDropListEx from '@/Components/DragDropListEx.vue';
|
||||||
|
import AppLayout from '@/Layouts/AppLayout.vue';
|
||||||
|
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<AppLayout title="Testing">
|
||||||
|
<div class="pt-12">
|
||||||
|
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
|
||||||
|
<div class="bg-white overflow-hidden shadow-xl sm:rounded-lg">
|
||||||
|
<div class="grid grid-flow-col">
|
||||||
|
<DragDropListEx />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</AppLayout>
|
||||||
|
</template>
|
||||||
66
resources/js/Utilities/Icons.js
Normal file
66
resources/js/Utilities/Icons.js
Normal file
|
|
@ -0,0 +1,66 @@
|
||||||
|
|
||||||
|
import { ref } from "vue";
|
||||||
|
|
||||||
|
const Icon = {
|
||||||
|
props: {
|
||||||
|
css: {
|
||||||
|
type: String,
|
||||||
|
default: 'text-gray-800'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const AddressBookIcon = {
|
||||||
|
__proto__: Icon,
|
||||||
|
setup: () => {
|
||||||
|
console.log(this.props)
|
||||||
|
},
|
||||||
|
template: `<svg class="w-6 h-6 dark:text-white" :class="css" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
|
||||||
|
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 6H5m2 3H5m2 3H5m2 3H5m2 3H5m11-1a2 2 0 0 0-2-2h-2a2 2 0 0 0-2 2M7 3h11a1 1 0 0 1 1 1v16a1 1 0 0 1-1 1H7a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1Zm8 7a2 2 0 1 1-4 0 2 2 0 0 1 4 0Z"/>
|
||||||
|
</svg>`
|
||||||
|
};
|
||||||
|
|
||||||
|
const AlignCenterIcon = {
|
||||||
|
__proto__: Icon,
|
||||||
|
template: `<svg class="w-6 h-6 dark:text-white" :class="css" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
|
||||||
|
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 6h8M6 10h12M8 14h8M6 18h12"/>
|
||||||
|
</svg>`
|
||||||
|
}
|
||||||
|
|
||||||
|
const EditIcon = {
|
||||||
|
__proto__: Icon,
|
||||||
|
template: `<svg class="w-6 h-6 dark:text-white" :class="css" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
|
||||||
|
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m14.304 4.844 2.852 2.852M7 7H4a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h11a1 1 0 0 0 1-1v-4.5m2.409-9.91a2.017 2.017 0 0 1 0 2.853l-6.844 6.844L8 14l.713-3.565 6.844-6.844a2.015 2.015 0 0 1 2.852 0Z"/>
|
||||||
|
</svg>`
|
||||||
|
}
|
||||||
|
|
||||||
|
const TrashBinIcon = {
|
||||||
|
__proto__: Icon,
|
||||||
|
template: `<svg class="w-6 h-6 dark:text-white" :class="css" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path fill-rule="evenodd" d="M8.586 2.586A2 2 0 0 1 10 2h4a2 2 0 0 1 2 2v2h3a1 1 0 1 1 0 2v12a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V8a1 1 0 0 1 0-2h3V4a2 2 0 0 1 .586-1.414ZM10 6h4V4h-4v2Zm1 4a1 1 0 1 0-2 0v8a1 1 0 1 0 2 0v-8Zm4 0a1 1 0 1 0-2 0v8a1 1 0 1 0 2 0v-8Z" clip-rule="evenodd"/>
|
||||||
|
</svg>`
|
||||||
|
}
|
||||||
|
|
||||||
|
const SearchIcon = {
|
||||||
|
__proto__: Icon,
|
||||||
|
template: `<svg aria-hidden="true" class="w-5 h-5 text-gray-500 dark:text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" />
|
||||||
|
</svg>`
|
||||||
|
}
|
||||||
|
|
||||||
|
const AdjustmentIcon = {
|
||||||
|
__proto__: Icon,
|
||||||
|
template: `<svg class="w-6 h-6 text-gray-800 dark:text-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
|
||||||
|
<path stroke="currentColor" stroke-linecap="round" stroke-width="2" d="M20 6H10m0 0a2 2 0 1 0-4 0m4 0a2 2 0 1 1-4 0m0 0H4m16 6h-2m0 0a2 2 0 1 0-4 0m4 0a2 2 0 1 1-4 0m0 0H4m16 6H10m0 0a2 2 0 1 0-4 0m4 0a2 2 0 1 1-4 0m0 0H4"/>
|
||||||
|
</svg>
|
||||||
|
`
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
AddressBookIcon,
|
||||||
|
AlignCenterIcon,
|
||||||
|
EditIcon,
|
||||||
|
TrashBinIcon,
|
||||||
|
SearchIcon,
|
||||||
|
AdjustmentIcon
|
||||||
|
};
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import './bootstrap';
|
import './bootstrap';
|
||||||
import '../css/app.css';
|
import '../css/app.css';
|
||||||
|
|
||||||
import { createApp, h } from 'vue';
|
import { createApp, h } from 'vue/dist/vue.esm-bundler.js';
|
||||||
import { createInertiaApp } from '@inertiajs/vue3';
|
import { createInertiaApp } from '@inertiajs/vue3';
|
||||||
import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers';
|
import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers';
|
||||||
import { ZiggyVue } from '../../vendor/tightenco/ziggy';
|
import { ZiggyVue } from '../../vendor/tightenco/ziggy';
|
||||||
|
|
|
||||||
|
|
@ -11,4 +11,12 @@
|
||||||
|
|
||||||
Route::get('/person', function(){
|
Route::get('/person', function(){
|
||||||
return new PersonCollection(Person::all());
|
return new PersonCollection(Person::all());
|
||||||
|
})->middleware('auth:sanctum');
|
||||||
|
|
||||||
|
Route::get('/search', function(Request $request){
|
||||||
|
$query = '41242523';
|
||||||
|
|
||||||
|
$persons = App\Models\Person\Person::search($query)->get();
|
||||||
|
|
||||||
|
return $persons;
|
||||||
})->middleware('auth:sanctum');
|
})->middleware('auth:sanctum');
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
use App\Http\Controllers\ContractController;
|
use App\Http\Controllers\ContractController;
|
||||||
use App\Http\Controllers\SettingController;
|
use App\Http\Controllers\SettingController;
|
||||||
use App\Models\Person\Person;
|
use App\Models\Person\Person;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
use ArielMejiaDev\LarapexCharts\LarapexChart;
|
use ArielMejiaDev\LarapexCharts\LarapexChart;
|
||||||
use Illuminate\Support\Facades\Route;
|
use Illuminate\Support\Facades\Route;
|
||||||
use Inertia\Inertia;
|
use Inertia\Inertia;
|
||||||
|
|
@ -36,6 +37,35 @@
|
||||||
);
|
);
|
||||||
})->name('dashboard');
|
})->name('dashboard');
|
||||||
|
|
||||||
|
Route::get('testing', function() {
|
||||||
|
return Inertia::render('Testing', []);
|
||||||
|
});
|
||||||
|
|
||||||
|
Route::get('search', function(Request $request) {
|
||||||
|
|
||||||
|
if( !empty($request->input('query')) ) {
|
||||||
|
$clients = App\Models\Client::search($request->input('query'))
|
||||||
|
->query(function($q) use($request) {
|
||||||
|
$q->with('person')->limit($request->input('limit'));
|
||||||
|
})
|
||||||
|
->get();
|
||||||
|
|
||||||
|
$clientCases = App\Models\ClientCase::search($request->input('query'))
|
||||||
|
->query(function($q) use($request) {
|
||||||
|
$q->with('person')->limit($request->input('limit'));
|
||||||
|
})
|
||||||
|
->get();
|
||||||
|
|
||||||
|
return [
|
||||||
|
'clients' => $clients,
|
||||||
|
'client_cases' => $clientCases
|
||||||
|
];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
})->name('search');
|
||||||
|
|
||||||
//client
|
//client
|
||||||
Route::get('clients', [ClientController::class, 'index'])->name('client');
|
Route::get('clients', [ClientController::class, 'index'])->name('client');
|
||||||
Route::get('clients/{client:uuid}', [ClientController::class, 'show'])->name('client.show');
|
Route::get('clients/{client:uuid}', [ClientController::class, 'show'])->name('client.show');
|
||||||
|
|
|
||||||
28
tests/Feature/AlgoliaSearchTest.php
Normal file
28
tests/Feature/AlgoliaSearchTest.php
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tests\Feature;
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||||
|
use Illuminate\Foundation\Testing\WithFaker;
|
||||||
|
use Tests\TestCase;
|
||||||
|
|
||||||
|
class AlgoliaSearchTest extends TestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* A basic feature test example.
|
||||||
|
*/
|
||||||
|
public function test_example(): void
|
||||||
|
{
|
||||||
|
|
||||||
|
$client = \Algolia\AlgoliaSearch\SearchClient::create('ZDAXR87LZV','8797318d18e10541ad15d49ae1e64db2');
|
||||||
|
|
||||||
|
$index = $client->initIndex('myposts_index');
|
||||||
|
|
||||||
|
$index->saveObject([
|
||||||
|
'objectID' => 1,
|
||||||
|
'name' => 'Test record'
|
||||||
|
]);
|
||||||
|
|
||||||
|
//$response->assertStatus(200);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user