refactor.

main
Giò 2024-07-01 20:55:25 +02:00
parent 944c993739
commit b7661d8e01
33 changed files with 213 additions and 655 deletions

View File

@ -8,52 +8,21 @@ LOG_CHANNEL=stack
LOG_DEPRECATIONS_CHANNEL=null
LOG_LEVEL=debug
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=root
DB_PASSWORD=
# mysql or mariadb connection
# DB_CONNECTION=mysql
# DB_HOST=127.0.0.1
# DB_PORT=3306
# DB_DATABASE=laravel
# DB_USERNAME=root
# DB_PASSWORD=
# sqlite database
DB_CONNECTION=sqlite
DB_DATABASE=/absolute/path/to/database.sqlite
BROADCAST_DRIVER=log
CACHE_DRIVER=file
FILESYSTEM_DISK=local
QUEUE_CONNECTION=sync
QUEUE_CONNECTION=database
SESSION_DRIVER=file
SESSION_LIFETIME=120
MEMCACHED_HOST=127.0.0.1
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
MAIL_MAILER=smtp
MAIL_HOST=mailpit
MAIL_PORT=1025
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS="hello@example.com"
MAIL_FROM_NAME="${APP_NAME}"
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET=
AWS_USE_PATH_STYLE_ENDPOINT=false
PUSHER_APP_ID=
PUSHER_APP_KEY=
PUSHER_APP_SECRET=
PUSHER_HOST=
PUSHER_PORT=443
PUSHER_SCHEME=https
PUSHER_APP_CLUSTER=mt1
VITE_APP_NAME="${APP_NAME}"
VITE_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
VITE_PUSHER_HOST="${PUSHER_HOST}"
VITE_PUSHER_PORT="${PUSHER_PORT}"
VITE_PUSHER_SCHEME="${PUSHER_SCHEME}"
VITE_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"

View File

@ -5,21 +5,21 @@ namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Models\Regions;
class scrapeAddRegion extends Command
class scraperAddRegion extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'scrape:add-region {name}';
protected $signature = 'scraper:add-region {name}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Scrapes for properties from seeds.';
protected $description = 'Add new region to database.';
/**
* Execute the console command.

View File

@ -5,21 +5,21 @@ namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Models\Seed;
class scrapeAddSeed extends Command
class scraperAddSeed extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'scrape:add-seed {regionId} {uri}';
protected $signature = 'scraper:add-seed {regionId} {uri}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Scrapes for properties from seeds.';
protected $description = 'Add new seed to database.';
/**
* Execute the console command.

View File

@ -6,14 +6,14 @@ use App\Scraper\Edomizil;
use App\Models\Property;
use Illuminate\Console\Command;
class scrapeCreateJobs extends Command
class scraperCreateJobs extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'scrape:jobs';
protected $signature = 'scraper:jobs';
/**
* The console command description.

View File

@ -5,21 +5,21 @@ namespace App\Console\Commands;
use App\Scraper\Edomizil;
use Illuminate\Console\Command;
class scrapeProperty extends Command
class scraperProperty extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'scrape:property';
protected $signature = 'scraper:scrape-properties';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Scrapes for properties from seeds.';
protected $description = 'Scrape for properties.';
/**
* Execute the console command.

View File

@ -6,14 +6,14 @@ use App\Scraper\Edomizil;
use App\Models\Property;
use Illuminate\Console\Command;
class scrapePropertyDate extends Command
class scraperPropertyDate extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'scrape:propertydata {propertyId?} {--seed=}';
protected $signature = 'scraper:scrape-propertydata {propertyId?} {--seed=}';
/**
* The console command description.

View File

@ -7,6 +7,14 @@ use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
class Kernel extends ConsoleKernel
{
/**
* Define the application's command schedule.
*/
protected function schedule(Schedule $schedule): void
{
// $schedule->command('inspire')->hourly();
}
/**
* Register the commands for the application.
*/

View File

@ -28,6 +28,6 @@ class ScrapePropertyData implements ShouldQueue
public function handle(): void
{
Edomizil::scrapePropertyData($this->property);
sleep(random_int(1,20));
sleep(random_int(1,10));
}
}

View File

@ -9,20 +9,9 @@ use App\Jobs\ScrapeProperty;
use App\Jobs\ScrapePropertyData;
use Illuminate\Support\Facades\Http;
/**
* This Class contains methods for scraping offers from the
* website e-domizil.ch.
**/
class Edomizil{
/**
* Save an exception.
* @param string $response The respsonse form an exception e.g. 404
* @param enum $type Is either 'offer', 'price', 'calendar' or 'property'
* @param integer $entityId Has to be the id of the corresponding entity.
**/
public static function saveHttpException($response, $type, $entityId)
{
public static function saveHttpException($response, $type, $entityId){
$exception = [];
@ -40,71 +29,52 @@ class Edomizil{
}
/**
* Get seed urls.
* Get all seed urls (seeds.uris) in random order.
* @return Collection with seed urls.
**/
public static function getAllSeeds()
{
// get all seeds from model in random order.
return Seed::select('id','uri')->inRandomOrder()->get();
}
/**
* Get property ids.
* Get all ids (properties.property_platform_id) in random order.
* @return Collection with property id
**/
public static function getAllProperties()
{
// get all properties from model in random order.
return Property::select('id','property_platform_id')->inRandomOrder()->get();
}
/**
* Scrape for properties.
* Scrapes for properties form seed url and save them to the database.
* @param $seed Seed
**/
public static function dispatchPropertyJobs()
{
$seeds = self::getAllSeeds();
foreach($seeds as $seed){
ScrapeProperty::dispatch($seed);
}
}
public static function dispatchPropertyDataJobs()
{
$properties = self::getAllProperties();
foreach($properties as $property){
ScrapePropertyData::dispatch($property);
}
}
public static function scrapeProperty($seed)
{
$response = Http::get($seed->uri);
if($response->successful()){
$json = $response->json();
/** Check if offers are findable in response */
if(!$json['offers']){
Exception::create([
'exception' => 'No offers found for'.$seed->uri,
'entity_type' => 'property',
'entity_id' => $property->id
]);
return;
}
/** Iterate offers */
foreach($json['offers'] as $offer){
/**
* Check if property with same id is already present in database.
* If already present check if the geoLocation was the same as the first time when found.
* Otherwise add property to database.
**/
$property = Property::firstWhere('property_platform_id', $offer['id']);
$geoLocation = implode(',', $offer['geoLocation']);
if($property){
/** Update last found attribute */
$property->last_found = now();
$property->save();
/** check if geoLocation is the same as at creation time and save exception if not */
// check if geoLocation is the same as last crawl
if($property->check_data !== $geoLocation){
Exception::create([
'exception' => 'geoLocation was different: '.$geoLocation,
@ -112,7 +82,6 @@ class Edomizil{
'entity_id' => $property->id
]);
}
}else{
Property::create([
'property_platform_id' => $offer['id'],
@ -127,32 +96,26 @@ class Edomizil{
}else{
/** Save Exception if document could not be found */
self::saveHttpException($response,'property', $seed->id);
return 0;
}
}
/**
* Extract details from property.
* Scrapes for offer, price and calendar details from property and save the to extractions table (or exceptions when not found).
* @param $property Id of property (properties.property_platform_id)
**/
public static function scrapePropertyData($property){
$result = [];
/** scrape offer details such as name, ammeneties, etc. */
// scrape offer details such as name etc.
$offer = Http::get('https://www.e-domizil.ch/rental/offer/'.$property->property_platform_id);
if($offer->successful()){
if($offer->successful()){
Extraction::create([
'property_id' => $property->id,
'type' => 'offer',
'body' => $offer->body(),
'header' => json_encode($offer->headers())
]);
]);
}else{
self::saveHttpException($offer,'offer',$property->id);
@ -160,7 +123,7 @@ class Edomizil{
$result['offer'] = $offer->body();
/** scrape for price details */
// scrape price of property
$price = Http::get('https://www.e-domizil.ch/booking/checkout/priceDetails/'.$property->property_platform_id);
if($price->successful()){
@ -178,7 +141,7 @@ class Edomizil{
$result['price'] = $price->body();
/** scrape for calendar details */
// scrape calendar which contains occupancies
$calendar = Http::get('https://www.e-domizil.ch/api/v2/calendar/'.$property->property_platform_id, [
'year' => date("Y"),
'month' => date("m")
@ -203,28 +166,5 @@ class Edomizil{
}
/**
* Dispatch property jobs.
* Creates jobs for scraping new for properties
**/
public static function dispatchPropertyJobs()
{
$seeds = self::getAllSeeds();
foreach($seeds as $seed){
ScrapeProperty::dispatch($seed);
}
}
}
/**
* Dispatch property data jobs.
* Creates jobs for scraping new for property detail data.
**/
public static function dispatchPropertyDataJobs()
{
$properties = self::getAllProperties();
foreach($properties as $property){
ScrapePropertyData::dispatch($property);
}
}
}

View File

@ -1,4 +1,3 @@
{
"name": "laravel/laravel",
"type": "project",
@ -9,6 +8,7 @@
"php": "^8.1",
"guzzlehttp/guzzle": "^7.2",
"laravel/framework": "^10.10",
"laravel/sanctum": "^3.3",
"laravel/tinker": "^2.8"
},
"require-dev": {
@ -35,8 +35,7 @@
"scripts": {
"post-autoload-dump": [
"Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
"@php artisan package:discover --ansi",
"@php artisan filament:upgrade"
"@php artisan package:discover --ansi"
],
"post-update-cmd": [
"@php artisan vendor:publish --tag=laravel-assets --ansi --force"

68
scraper/composer.lock generated
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": "2db4f4f45d5f19c3d1d1d0592de24b8a",
"content-hash": "9c491b8531eec05ba41a11d9276a5749",
"packages": [
{
"name": "brick/math",
@ -1315,6 +1315,72 @@
},
"time": "2024-06-17T13:58:22+00:00"
},
{
"name": "laravel/sanctum",
"version": "v3.3.3",
"source": {
"type": "git",
"url": "https://github.com/laravel/sanctum.git",
"reference": "8c104366459739f3ada0e994bcd3e6fd681ce3d5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/sanctum/zipball/8c104366459739f3ada0e994bcd3e6fd681ce3d5",
"reference": "8c104366459739f3ada0e994bcd3e6fd681ce3d5",
"shasum": ""
},
"require": {
"ext-json": "*",
"illuminate/console": "^9.21|^10.0",
"illuminate/contracts": "^9.21|^10.0",
"illuminate/database": "^9.21|^10.0",
"illuminate/support": "^9.21|^10.0",
"php": "^8.0.2"
},
"require-dev": {
"mockery/mockery": "^1.0",
"orchestra/testbench": "^7.28.2|^8.8.3",
"phpstan/phpstan": "^1.10",
"phpunit/phpunit": "^9.6"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.x-dev"
},
"laravel": {
"providers": [
"Laravel\\Sanctum\\SanctumServiceProvider"
]
}
},
"autoload": {
"psr-4": {
"Laravel\\Sanctum\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Taylor Otwell",
"email": "taylor@laravel.com"
}
],
"description": "Laravel Sanctum provides a featherweight authentication system for SPAs and simple APIs.",
"keywords": [
"auth",
"laravel",
"sanctum"
],
"support": {
"issues": "https://github.com/laravel/sanctum/issues",
"source": "https://github.com/laravel/sanctum"
},
"time": "2023-12-19T18:44:48+00:00"
},
{
"name": "laravel/serializable-closure",
"version": "v1.3.3",

View File

@ -165,6 +165,7 @@ return [
*/
App\Providers\AppServiceProvider::class,
App\Providers\AuthServiceProvider::class,
// App\Providers\BroadcastServiceProvider::class,
App\Providers\EventServiceProvider::class,
App\Providers\RouteServiceProvider::class,
])->toArray(),

View File

@ -0,0 +1,83 @@
<?php
use Laravel\Sanctum\Sanctum;
return [
/*
|--------------------------------------------------------------------------
| Stateful Domains
|--------------------------------------------------------------------------
|
| Requests from the following domains / hosts will receive stateful API
| authentication cookies. Typically, these should include your local
| and production domains which access your API via a frontend SPA.
|
*/
'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf(
'%s%s',
'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1',
Sanctum::currentApplicationUrlWithPort()
))),
/*
|--------------------------------------------------------------------------
| Sanctum Guards
|--------------------------------------------------------------------------
|
| This array contains the authentication guards that will be checked when
| Sanctum is trying to authenticate a request. If none of these guards
| are able to authenticate the request, Sanctum will use the bearer
| token that's present on an incoming request for authentication.
|
*/
'guard' => ['web'],
/*
|--------------------------------------------------------------------------
| Expiration Minutes
|--------------------------------------------------------------------------
|
| This value controls the number of minutes until an issued token will be
| considered expired. This will override any values set in the token's
| "expires_at" attribute, but first-party sessions are not affected.
|
*/
'expiration' => null,
/*
|--------------------------------------------------------------------------
| Token Prefix
|--------------------------------------------------------------------------
|
| Sanctum can prefix new tokens in order to take advantage of numerous
| security scanning initiatives maintained by open source platforms
| that notify developers if they commit tokens into repositories.
|
| See: https://docs.github.com/en/code-security/secret-scanning/about-secret-scanning
|
*/
'token_prefix' => env('SANCTUM_TOKEN_PREFIX', ''),
/*
|--------------------------------------------------------------------------
| Sanctum Middleware
|--------------------------------------------------------------------------
|
| When authenticating your first-party SPA with Sanctum you may need to
| customize some of the middleware Sanctum uses while processing the
| request. You may change the middleware listed below as required.
|
*/
'middleware' => [
'authenticate_session' => Laravel\Sanctum\Http\Middleware\AuthenticateSession::class,
'encrypt_cookies' => App\Http\Middleware\EncryptCookies::class,
'verify_csrf_token' => App\Http\Middleware\VerifyCsrfToken::class,
],
];

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1 +0,0 @@
.fi-pagination-items,.fi-pagination-overview,.fi-pagination-records-per-page-select:not(.fi-compact){display:none}@supports (container-type:inline-size){.fi-pagination{container-type:inline-size}@container (min-width: 28rem){.fi-pagination-records-per-page-select.fi-compact{display:none}.fi-pagination-records-per-page-select:not(.fi-compact){display:inline}}@container (min-width: 56rem){.fi-pagination:not(.fi-simple)>.fi-pagination-previous-btn{display:none}.fi-pagination-overview{display:inline}.fi-pagination:not(.fi-simple)>.fi-pagination-next-btn{display:none}.fi-pagination-items{display:flex}}}@supports not (container-type:inline-size){@media (min-width:640px){.fi-pagination-records-per-page-select.fi-compact{display:none}.fi-pagination-records-per-page-select:not(.fi-compact){display:inline}}@media (min-width:768px){.fi-pagination:not(.fi-simple)>.fi-pagination-previous-btn{display:none}.fi-pagination-overview{display:inline}.fi-pagination:not(.fi-simple)>.fi-pagination-next-btn{display:none}.fi-pagination-items{display:flex}}}.tippy-box[data-animation=fade][data-state=hidden]{opacity:0}[data-tippy-root]{max-width:calc(100vw - 10px)}.tippy-box{background-color:#333;border-radius:4px;color:#fff;font-size:14px;line-height:1.4;outline:0;position:relative;transition-property:transform,visibility,opacity;white-space:normal}.tippy-box[data-placement^=top]>.tippy-arrow{bottom:0}.tippy-box[data-placement^=top]>.tippy-arrow:before{border-top-color:initial;border-width:8px 8px 0;bottom:-7px;left:0;transform-origin:center top}.tippy-box[data-placement^=bottom]>.tippy-arrow{top:0}.tippy-box[data-placement^=bottom]>.tippy-arrow:before{border-bottom-color:initial;border-width:0 8px 8px;left:0;top:-7px;transform-origin:center bottom}.tippy-box[data-placement^=left]>.tippy-arrow{right:0}.tippy-box[data-placement^=left]>.tippy-arrow:before{border-left-color:initial;border-width:8px 0 8px 8px;right:-7px;transform-origin:center left}.tippy-box[data-placement^=right]>.tippy-arrow{left:0}.tippy-box[data-placement^=right]>.tippy-arrow:before{border-right-color:initial;border-width:8px 8px 8px 0;left:-7px;transform-origin:center right}.tippy-box[data-inertia][data-state=visible]{transition-timing-function:cubic-bezier(.54,1.5,.38,1.11)}.tippy-arrow{color:#333;height:16px;width:16px}.tippy-arrow:before{border-color:transparent;border-style:solid;content:"";position:absolute}.tippy-content{padding:5px 9px;position:relative;z-index:1}.tippy-box[data-theme~=light]{background-color:#fff;box-shadow:0 0 20px 4px #9aa1b126,0 4px 80px -8px #24282f40,0 4px 4px -2px #5b5e6926;color:#26323d}.tippy-box[data-theme~=light][data-placement^=top]>.tippy-arrow:before{border-top-color:#fff}.tippy-box[data-theme~=light][data-placement^=bottom]>.tippy-arrow:before{border-bottom-color:#fff}.tippy-box[data-theme~=light][data-placement^=left]>.tippy-arrow:before{border-left-color:#fff}.tippy-box[data-theme~=light][data-placement^=right]>.tippy-arrow:before{border-right-color:#fff}.tippy-box[data-theme~=light]>.tippy-backdrop{background-color:#fff}.tippy-box[data-theme~=light]>.tippy-svg-arrow{fill:#fff}.fi-sortable-ghost{opacity:.3}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1 +0,0 @@
function r({state:i}){return{state:i,rows:[],shouldUpdateRows:!0,init:function(){this.updateRows(),this.rows.length<=0?this.rows.push({key:"",value:""}):this.updateState(),this.$watch("state",(t,e)=>{let s=o=>o===null?0:Array.isArray(o)?o.length:typeof o!="object"?0:Object.keys(o).length;s(t)===0&&s(e)===0||this.updateRows()})},addRow:function(){this.rows.push({key:"",value:""}),this.updateState()},deleteRow:function(t){this.rows.splice(t,1),this.rows.length<=0&&this.addRow(),this.updateState()},reorderRows:function(t){let e=Alpine.raw(this.rows),s=e.splice(t.oldIndex,1)[0];e.splice(t.newIndex,0,s),this.rows=e,this.updateState()},updateRows:function(){if(!this.shouldUpdateRows){this.shouldUpdateRows=!0;return}let t=[];for(let[e,s]of Object.entries(this.state??{}))t.push({key:e,value:s});this.rows=t},updateState:function(){let t={};this.rows.forEach(e=>{e.key===""||e.key===null||(t[e.key]=e.value)}),this.shouldUpdateRows=!1,this.state=t}}}export{r as default};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1 +0,0 @@
function i({state:a,splitKeys:n}){return{newTag:"",state:a,createTag:function(){if(this.newTag=this.newTag.trim(),this.newTag!==""){if(this.state.includes(this.newTag)){this.newTag="";return}this.state.push(this.newTag),this.newTag=""}},deleteTag:function(t){this.state=this.state.filter(e=>e!==t)},reorderTags:function(t){let e=this.state.splice(t.oldIndex,1)[0];this.state.splice(t.newIndex,0,e),this.state=[...this.state]},input:{["x-on:blur"]:"createTag()",["x-model"]:"newTag",["x-on:keydown"](t){["Enter",...n].includes(t.key)&&(t.preventDefault(),t.stopPropagation(),this.createTag())},["x-on:paste"](){this.$nextTick(()=>{if(n.length===0){this.createTag();return}let t=n.map(e=>e.replace(/[/\-\\^$*+?.()|[\]{}]/g,"\\$&")).join("|");this.newTag.split(new RegExp(t,"g")).forEach(e=>{this.newTag=e,this.createTag()})})}}}}export{i as default};

View File

@ -1 +0,0 @@
function t({initialHeight:e}){return{init:function(){this.render()},render:function(){this.$el.scrollHeight>0&&(this.$el.style.height=e+"rem",this.$el.style.height=this.$el.scrollHeight+"px")}}}export{t as default};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1 +0,0 @@
function c(){return{collapsedGroups:[],isLoading:!1,selectedRecords:[],shouldCheckUniqueSelection:!0,init:function(){this.$wire.$on("deselectAllTableRecords",()=>this.deselectAllRecords()),this.$watch("selectedRecords",()=>{if(!this.shouldCheckUniqueSelection){this.shouldCheckUniqueSelection=!0;return}this.selectedRecords=[...new Set(this.selectedRecords)],this.shouldCheckUniqueSelection=!1})},mountAction:function(e,s=null){this.$wire.set("selectedTableRecords",this.selectedRecords,!1),this.$wire.mountTableAction(e,s)},mountBulkAction:function(e){this.$wire.set("selectedTableRecords",this.selectedRecords,!1),this.$wire.mountTableBulkAction(e)},toggleSelectRecordsOnPage:function(){let e=this.getRecordsOnPage();if(this.areRecordsSelected(e)){this.deselectRecords(e);return}this.selectRecords(e)},toggleSelectRecordsInGroup:async function(e){if(this.isLoading=!0,this.areRecordsSelected(this.getRecordsInGroupOnPage(e))){this.deselectRecords(await this.$wire.getGroupedSelectableTableRecordKeys(e));return}this.selectRecords(await this.$wire.getGroupedSelectableTableRecordKeys(e)),this.isLoading=!1},getRecordsInGroupOnPage:function(e){let s=[];for(let t of this.$root?.getElementsByClassName("fi-ta-record-checkbox")??[])t.dataset.group===e&&s.push(t.value);return s},getRecordsOnPage:function(){let e=[];for(let s of this.$root?.getElementsByClassName("fi-ta-record-checkbox")??[])e.push(s.value);return e},selectRecords:function(e){for(let s of e)this.isRecordSelected(s)||this.selectedRecords.push(s)},deselectRecords:function(e){for(let s of e){let t=this.selectedRecords.indexOf(s);t!==-1&&this.selectedRecords.splice(t,1)}},selectAllRecords:async function(){this.isLoading=!0,this.selectedRecords=await this.$wire.getAllSelectableTableRecordKeys(),this.isLoading=!1},deselectAllRecords:function(){this.selectedRecords=[]},isRecordSelected:function(e){return this.selectedRecords.includes(e)},areRecordsSelected:function(e){return e.every(s=>this.isRecordSelected(s))},toggleCollapseGroup:function(e){if(this.isGroupCollapsed(e)){this.collapsedGroups.splice(this.collapsedGroups.indexOf(e),1);return}this.collapsedGroups.push(e)},isGroupCollapsed:function(e){return this.collapsedGroups.includes(e)},resetCollapsedGroups:function(){this.collapsedGroups=[]}}}export{c as default};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long