feat: Add export import
This commit is contained in:
parent
2ee5d07e48
commit
bb5a078f35
20 changed files with 505 additions and 21 deletions
31
app/Http/Controllers/ImportController.php
Normal file
31
app/Http/Controllers/ImportController.php
Normal file
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\View\View;
|
||||
|
||||
class ImportController extends Controller
|
||||
{
|
||||
/**
|
||||
* Instantiate a new controller instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->middleware('allowed');
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the incoming request.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return View
|
||||
*/
|
||||
public function __invoke(Request $request): View
|
||||
{
|
||||
return view('items.import');
|
||||
}
|
||||
}
|
|
@ -12,9 +12,9 @@ use GuzzleHttp\Exception\ConnectException;
|
|||
use GuzzleHttp\Exception\GuzzleException;
|
||||
use GuzzleHttp\Exception\ServerException;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Routing\Redirector;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Facades\URL;
|
||||
|
@ -191,10 +191,10 @@ class ItemController extends Controller
|
|||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param $id
|
||||
* @return void
|
||||
* @param null $id
|
||||
* @return Item
|
||||
*/
|
||||
public function storelogic(Request $request, $id = null)
|
||||
public static function storelogic(Request $request, $id = null): Item
|
||||
{
|
||||
$application = Application::single($request->input('appid'));
|
||||
$validatedData = $request->validate([
|
||||
|
@ -275,6 +275,7 @@ class ItemController extends Controller
|
|||
}
|
||||
|
||||
$item->parents()->sync($request->tags);
|
||||
return $item;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -285,7 +286,7 @@ class ItemController extends Controller
|
|||
*/
|
||||
public function store(Request $request): RedirectResponse
|
||||
{
|
||||
$this->storelogic($request);
|
||||
self::storelogic($request);
|
||||
|
||||
$route = route('dash', []);
|
||||
|
||||
|
@ -313,7 +314,7 @@ class ItemController extends Controller
|
|||
*/
|
||||
public function update(Request $request, int $id): RedirectResponse
|
||||
{
|
||||
$this->storelogic($request, $id);
|
||||
self::storelogic($request, $id);
|
||||
$route = route('dash', []);
|
||||
|
||||
return redirect($route)
|
||||
|
|
111
app/Http/Controllers/ItemRestController.php
Normal file
111
app/Http/Controllers/ItemRestController.php
Normal file
|
@ -0,0 +1,111 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Item;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
|
||||
class ItemRestController extends Controller
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->middleware('allowed');
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$columns = [
|
||||
'title',
|
||||
'colour',
|
||||
'url',
|
||||
'description',
|
||||
'appid',
|
||||
'appdescription',
|
||||
];
|
||||
|
||||
return Item::select($columns)
|
||||
->where('deleted_at', null)
|
||||
->where('type', '0')
|
||||
->orderBy('order', 'asc')
|
||||
->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return object
|
||||
*/
|
||||
public function store(Request $request): object
|
||||
{
|
||||
$item = ItemController::storelogic($request);
|
||||
|
||||
if ($item) {
|
||||
return (object) ['status' => 'OK'];
|
||||
}
|
||||
|
||||
return (object) ['status' => 'FAILED'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*
|
||||
* @param Item $item
|
||||
* @return Response
|
||||
*/
|
||||
public function show(Item $item)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*
|
||||
* @param Item $item
|
||||
* @return Response
|
||||
*/
|
||||
public function edit(Item $item)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Item $item
|
||||
* @return Response
|
||||
*/
|
||||
public function update(Request $request, Item $item)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param Item $item
|
||||
* @return Response
|
||||
*/
|
||||
public function destroy(Item $item)
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
|
@ -4,6 +4,7 @@ namespace App;
|
|||
|
||||
use Illuminate\Contracts\Routing\UrlGenerator;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
|
@ -15,6 +16,8 @@ class Item extends Model
|
|||
{
|
||||
use SoftDeletes;
|
||||
|
||||
use HasFactory;
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
|
|
30
database/factories/ItemFactory.php
Normal file
30
database/factories/ItemFactory.php
Normal file
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Item;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class ItemFactory extends Factory
|
||||
{
|
||||
/**
|
||||
* The name of the factory's corresponding model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $model = Item::class;
|
||||
|
||||
/**
|
||||
* Define the model's default state.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function definition()
|
||||
{
|
||||
return [
|
||||
'title' => $this->faker->unique()->text(),
|
||||
'url' => $this->faker->unique()->url(),
|
||||
];
|
||||
}
|
||||
}
|
2
public/js/app.js
vendored
2
public/js/app.js
vendored
File diff suppressed because one or more lines are too long
2
public/mix-manifest.json
generated
2
public/mix-manifest.json
generated
|
@ -1,4 +1,4 @@
|
|||
{
|
||||
"/css/app.css": "/css/app.css?id=9a25947db63214edd4e6f459200dfa62",
|
||||
"/js/app.js": "/js/app.js?id=894c631b0c521ca3e5df669b4220f77b"
|
||||
"/js/app.js": "/js/app.js?id=50647209eddf7eb990cfe03fcc6652ed"
|
||||
}
|
||||
|
|
48
resources/assets/js/itemExport.js
vendored
Normal file
48
resources/assets/js/itemExport.js
vendored
Normal file
|
@ -0,0 +1,48 @@
|
|||
const EXPORT_FILE_NAME = "HeimdallExport.json";
|
||||
const EXPORT_API_URL = "api/item";
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string} fileName
|
||||
* @param {string} data
|
||||
*/
|
||||
function triggerFileDownload(fileName, data) {
|
||||
const a = document.createElement("a");
|
||||
|
||||
const file = new Blob([data], {
|
||||
type: "text/plain",
|
||||
});
|
||||
|
||||
a.href = URL.createObjectURL(file);
|
||||
a.download = EXPORT_FILE_NAME;
|
||||
|
||||
a.click();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {Event} event
|
||||
*/
|
||||
const exportItems = (event) => {
|
||||
event.preventDefault();
|
||||
|
||||
fetch(EXPORT_API_URL)
|
||||
.then((response) => {
|
||||
if (response.status !== 200) {
|
||||
window.alert("An error occurred while exporting...");
|
||||
}
|
||||
|
||||
return response.json();
|
||||
})
|
||||
.then((data) => {
|
||||
const exportedJson = JSON.stringify(data, null, 2);
|
||||
|
||||
triggerFileDownload(EXPORT_FILE_NAME, exportedJson);
|
||||
});
|
||||
};
|
||||
|
||||
const exportButton = document.querySelector("#item-export");
|
||||
|
||||
if (exportButton) {
|
||||
exportButton.addEventListener("click", exportItems);
|
||||
}
|
128
resources/assets/js/itemImport.js
vendored
Normal file
128
resources/assets/js/itemImport.js
vendored
Normal file
|
@ -0,0 +1,128 @@
|
|||
const IMPORT_API_URL = "api/item";
|
||||
const APP_LOAD_URL = "appload";
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string|null} appId
|
||||
* @returns {Promise<{}>|Promise<any>}
|
||||
*/
|
||||
const fetchAppDetails = (appId) => {
|
||||
if (appId === null) {
|
||||
return Promise.resolve({});
|
||||
}
|
||||
|
||||
return fetch(APP_LOAD_URL, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({ app: appId }),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.catch(() => ({}));
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @returns {string}
|
||||
*/
|
||||
const getCSRFToken = () => {
|
||||
const tokenSelector = 'input[name="_token"]';
|
||||
return document.querySelector(tokenSelector).value;
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {object} data
|
||||
* @param {string} csrfToken
|
||||
*/
|
||||
const postToApi = (data, csrfToken) =>
|
||||
fetch(IMPORT_API_URL, {
|
||||
method: "POST",
|
||||
cache: "no-cache",
|
||||
redirect: "follow",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"X-CSRF-TOKEN": csrfToken,
|
||||
},
|
||||
body: JSON.stringify(data),
|
||||
});
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {object} item
|
||||
* @param {object} appDetails
|
||||
* @returns {undefined}
|
||||
*/
|
||||
const mergeItemWithAppDetails = (item, appDetails) => ({
|
||||
pinned: 1,
|
||||
tags: [0],
|
||||
|
||||
appid: item.appid,
|
||||
title: item.title,
|
||||
colour: item.colour,
|
||||
url: item.url,
|
||||
appdescription: item.appdescription
|
||||
? item.appdescription
|
||||
: appDetails.description,
|
||||
|
||||
website: appDetails.website,
|
||||
|
||||
icon: appDetails.iconview,
|
||||
config: item.description ? JSON.parse(item.description) : null,
|
||||
});
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {array} items
|
||||
*/
|
||||
const importItems = (items) => {
|
||||
items.forEach((item) => {
|
||||
fetchAppDetails(item.appid)
|
||||
.then((appDetails) => {
|
||||
const itemWithAppDetails = mergeItemWithAppDetails(item, appDetails);
|
||||
const csrfToken = getCSRFToken();
|
||||
|
||||
return postToApi(itemWithAppDetails, csrfToken);
|
||||
})
|
||||
.then((response) => {
|
||||
console.log(response);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {Blob} file
|
||||
* @returns {Promise<unknown>}
|
||||
*/
|
||||
const readJSON = (file) =>
|
||||
new Promise((resolve) => {
|
||||
const reader = new FileReader();
|
||||
|
||||
reader.onload = (e) => {
|
||||
const contents = e.target.result;
|
||||
resolve(JSON.parse(contents));
|
||||
};
|
||||
|
||||
reader.readAsText(file);
|
||||
});
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {Event} event
|
||||
*/
|
||||
const openFileForImport = (event) => {
|
||||
const file = event.target.files[0];
|
||||
if (!file) {
|
||||
return;
|
||||
}
|
||||
|
||||
readJSON(file).then(importItems);
|
||||
};
|
||||
|
||||
const fileInput = document.querySelector("input[name='import']");
|
||||
|
||||
if (fileInput) {
|
||||
fileInput.addEventListener("change", openFileForImport, false);
|
||||
}
|
|
@ -86,6 +86,8 @@ return array (
|
|||
'delete' => 'Delete',
|
||||
'optional' => 'Optional',
|
||||
'restore' => 'Restore',
|
||||
'export' => 'Export',
|
||||
'import' => 'Import',
|
||||
'alert.success.item_created' => 'Item created successfully',
|
||||
'alert.success.item_updated' => 'Item updated successfully',
|
||||
'alert.success.item_deleted' => 'Item deleted successfully',
|
||||
|
|
32
resources/views/items/import.blade.php
Normal file
32
resources/views/items/import.blade.php
Normal file
|
@ -0,0 +1,32 @@
|
|||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
|
||||
<section class="module-container">
|
||||
<header>
|
||||
<div class="section-title">{{ __('import.title') }}</div>
|
||||
<div class="module-actions">
|
||||
<button type="submit"class="button"><i class="fa fa-save"></i><span>{{ __('import.save') }}</span></button>
|
||||
<a href="{{ route('settings.index', []) }}" class="button"><i class="fa fa-ban"></i><span>{{ __('app.buttons.cancel') }}</span></a>
|
||||
</div>
|
||||
</header>
|
||||
<div class="create">
|
||||
{!! csrf_field() !!}
|
||||
|
||||
<div class="input">
|
||||
<input class="form-control" name="import" type="file">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<footer>
|
||||
<div class="section-title"> </div>
|
||||
<div class="module-actions">
|
||||
<button type="submit"class="button"><i class="fa fa-save"></i><span>{{ __('import.save') }}</span></button>
|
||||
<a href="{{ route('settings.index', []) }}" class="button"><i class="fa fa-ban"></i><span>{{ __('app.buttons.cancel') }}</span></a>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
@endsection
|
|
@ -11,6 +11,8 @@
|
|||
|
||||
</div>
|
||||
<div class="module-actions">
|
||||
{{-- <a href="import" id="item-import" class="button"><i class="fa fa-upload"></i><span>{{ __('import') }}</span></a>--}}
|
||||
<a href="#export" id="item-export" class="button"><i class="fa fa-download"></i><span>{{ __('export') }}</span></a>
|
||||
<a href="{{ route('applist', []) }}" class="button"><i class="fa fa-cloud-download"></i><span>{{ __('app.buttons.downloadapps') }}</span></a>
|
||||
<a href="{{ route('items.create', []) }}" title="" class="button"><i class="fa fa-plus"></i><span>{{ __('app.buttons.add') }}</span></a>
|
||||
<a href="{{ route('dash', []) }}" class="button"><i class="fa fa-ban"></i><span>{{ __('app.buttons.cancel') }}</span></a>
|
||||
|
|
|
@ -81,3 +81,6 @@ Route::group([
|
|||
Auth::routes();
|
||||
|
||||
Route::get('/home', 'HomeController@index')->name('home');
|
||||
|
||||
Route::resource('api/item', 'ItemRestController');
|
||||
Route::get('import', 'ImportController')->name('items.import');
|
||||
|
|
|
@ -7,12 +7,14 @@ use Tests\TestCase;
|
|||
|
||||
class ExampleTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
/**
|
||||
* A basic test example.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testBasicTest()
|
||||
public function test_app_loads()
|
||||
{
|
||||
$response = $this->get('/');
|
||||
|
||||
|
|
81
tests/Feature/ItemExportTest.php
Normal file
81
tests/Feature/ItemExportTest.php
Normal file
|
@ -0,0 +1,81 @@
|
|||
<?php
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\Item;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\Date;
|
||||
use Tests\TestCase;
|
||||
|
||||
class ItemExportTest extends TestCase
|
||||
{
|
||||
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_returns_empty_jsonarray_when_there_are_no_items_in_the_db()
|
||||
{
|
||||
$response = $this->get('api/item');
|
||||
|
||||
$response->assertJsonCount(0);
|
||||
}
|
||||
|
||||
public function test_returns_exactly_the_defined_fields()
|
||||
{
|
||||
$exampleItem = [
|
||||
"appdescription" => "Description",
|
||||
"appid" => "123",
|
||||
"colour" => "#000",
|
||||
"description" => "Description",
|
||||
"title" => "Item Title",
|
||||
"url" => "http://gorczany.com/nihil-rerum-distinctio-voluptate-assumenda-accusantium-exercitationem"
|
||||
];
|
||||
|
||||
Item::factory()
|
||||
->create($exampleItem);
|
||||
|
||||
$response = $this->get('api/item');
|
||||
|
||||
$response->assertExactJson([(object)$exampleItem]);
|
||||
}
|
||||
|
||||
public function test_returns_all_items()
|
||||
{
|
||||
Item::factory()
|
||||
->count(3)
|
||||
->create();
|
||||
|
||||
$response = $this->get('api/item');
|
||||
|
||||
$response->assertJsonCount(3);
|
||||
}
|
||||
|
||||
public function test_does_not_return_deleted_item()
|
||||
{
|
||||
Item::factory()
|
||||
->create([
|
||||
'deleted_at' => Date::create('1970')
|
||||
]);
|
||||
|
||||
Item::factory()
|
||||
->create();
|
||||
|
||||
$response = $this->get('api/item');
|
||||
|
||||
$response->assertJsonCount(1);
|
||||
}
|
||||
|
||||
public function test_does_not_return_tags()
|
||||
{
|
||||
Item::factory()
|
||||
->create([
|
||||
'type' => 1
|
||||
]);
|
||||
|
||||
Item::factory()
|
||||
->create();
|
||||
|
||||
$response = $this->get('api/item');
|
||||
|
||||
$response->assertJsonCount(1);
|
||||
}
|
||||
}
|
|
@ -12,7 +12,7 @@ class SettingsSeederTest extends TestCase
|
|||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testReturnsAJSONMapWithSameAmountOfItemsAsLanguageDirectoriesPresent()
|
||||
public function test_returns_a_jsonmap_with_same_amount_of_items_as_language_directories_present()
|
||||
{
|
||||
$languageDirectories = array_filter(glob(resource_path().'/lang/*'), 'is_dir');
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ class LangTest extends TestCase
|
|||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testAllLanguageKeysAreDefined()
|
||||
public function test_all_language_keys_are_defined()
|
||||
{
|
||||
$this->markTestSkipped('2022-11-14 Lot of keys missing. Enable this test to see them all.');
|
||||
$languageDirectories = array_filter(glob(resource_path().'/lang/*'), 'is_dir');
|
||||
|
|
1
vendor/composer/autoload_classmap.php
vendored
1
vendor/composer/autoload_classmap.php
vendored
|
@ -18,6 +18,7 @@ return array(
|
|||
'App\\Http\\Controllers\\Controller' => $baseDir . '/app/Http/Controllers/Controller.php',
|
||||
'App\\Http\\Controllers\\HomeController' => $baseDir . '/app/Http/Controllers/HomeController.php',
|
||||
'App\\Http\\Controllers\\ItemController' => $baseDir . '/app/Http/Controllers/ItemController.php',
|
||||
'App\\Http\\Controllers\\ItemRestController' => $baseDir . '/app/Http/Controllers/ItemRestController.php',
|
||||
'App\\Http\\Controllers\\SearchController' => $baseDir . '/app/Http/Controllers/SearchController.php',
|
||||
'App\\Http\\Controllers\\SettingsController' => $baseDir . '/app/Http/Controllers/SettingsController.php',
|
||||
'App\\Http\\Controllers\\TagController' => $baseDir . '/app/Http/Controllers/TagController.php',
|
||||
|
|
1
vendor/composer/autoload_static.php
vendored
1
vendor/composer/autoload_static.php
vendored
|
@ -616,6 +616,7 @@ class ComposerStaticInitb2555e5ff7197b9e020da74bbd3b7cfa
|
|||
'App\\Http\\Controllers\\Controller' => __DIR__ . '/../..' . '/app/Http/Controllers/Controller.php',
|
||||
'App\\Http\\Controllers\\HomeController' => __DIR__ . '/../..' . '/app/Http/Controllers/HomeController.php',
|
||||
'App\\Http\\Controllers\\ItemController' => __DIR__ . '/../..' . '/app/Http/Controllers/ItemController.php',
|
||||
'App\\Http\\Controllers\\ItemRestController' => __DIR__ . '/../..' . '/app/Http/Controllers/ItemRestController.php',
|
||||
'App\\Http\\Controllers\\SearchController' => __DIR__ . '/../..' . '/app/Http/Controllers/SearchController.php',
|
||||
'App\\Http\\Controllers\\SettingsController' => __DIR__ . '/../..' . '/app/Http/Controllers/SettingsController.php',
|
||||
'App\\Http\\Controllers\\TagController' => __DIR__ . '/../..' . '/app/Http/Controllers/TagController.php',
|
||||
|
|
26
webpack.mix.js
vendored
26
webpack.mix.js
vendored
|
@ -1,4 +1,4 @@
|
|||
let mix = require('laravel-mix');
|
||||
const mix = require("laravel-mix");
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
|
@ -11,12 +11,20 @@ let mix = require('laravel-mix');
|
|||
|
|
||||
*/
|
||||
|
||||
mix.babel([
|
||||
mix
|
||||
.babel(
|
||||
[
|
||||
// 'resources/assets/js/jquery-ui.min.js',
|
||||
'resources/assets/js/huebee.js',
|
||||
'resources/assets/js/app.js',
|
||||
'resources/assets/js/keyBindings.js',
|
||||
], 'public/js/app.js')
|
||||
.sass('resources/assets/sass/app.scss', 'public/css').options({
|
||||
processCssUrls: false
|
||||
}).version();
|
||||
"resources/assets/js/huebee.js",
|
||||
"resources/assets/js/app.js",
|
||||
"resources/assets/js/keyBindings.js",
|
||||
"resources/assets/js/itemExport.js",
|
||||
"resources/assets/js/itemImport.js",
|
||||
],
|
||||
"public/js/app.js"
|
||||
)
|
||||
.sass("resources/assets/sass/app.scss", "public/css")
|
||||
.options({
|
||||
processCssUrls: false,
|
||||
})
|
||||
.version();
|
||||
|
|
Loading…
Reference in a new issue