Browse Source

Minor changes to the UI

master
Radu Liviu Carjan 3 years ago
parent
commit
6e0090c144
  1. 113
      app/Http/Controllers/FileController.php
  2. 21
      app/Http/Controllers/FilterController.php
  3. 10
      app/Http/Controllers/HomeController.php
  4. 24
      app/Http/Controllers/PagesController.php
  5. 183
      package-lock.json
  6. 2
      package.json
  7. BIN
      public/fonts/vendor/primevue/resources/themes/mdc-dark-indigo/roboto-v20-latin-ext_latin-500.woff
  8. BIN
      public/fonts/vendor/primevue/resources/themes/mdc-dark-indigo/roboto-v20-latin-ext_latin-500.woff2
  9. BIN
      public/fonts/vendor/primevue/resources/themes/mdc-dark-indigo/roboto-v20-latin-ext_latin-700.woff
  10. BIN
      public/fonts/vendor/primevue/resources/themes/mdc-dark-indigo/roboto-v20-latin-ext_latin-700.woff2
  11. BIN
      public/fonts/vendor/primevue/resources/themes/mdc-dark-indigo/roboto-v20-latin-ext_latin-regular.woff
  12. BIN
      public/fonts/vendor/primevue/resources/themes/mdc-dark-indigo/roboto-v20-latin-ext_latin-regular.woff2
  13. 32992
      public/js/app.js
  14. 33
      resources/js/app.ts
  15. 100
      resources/js/components/Home.vue
  16. 42
      resources/js/components/Home/Home.ts
  17. 35
      resources/js/components/Home/Home.vue
  18. 84
      resources/js/components/ProcessFile.vue
  19. 11
      resources/js/components/ProcessFile/ProcessFile.scss
  20. 121
      resources/js/components/ProcessFile/ProcessFile.ts
  21. 111
      resources/js/components/ProcessFile/ProcessFile.vue
  22. 69
      resources/js/components/helpers/Filter.vue
  23. 7
      resources/js/interfaces/FilterInterface.ts
  24. 4
      resources/js/interfaces/FilterOptions.ts
  25. 18
      resources/js/plugins/ApiPlugin.ts
  26. 7
      resources/js/plugins/plugins.d.ts
  27. 60
      resources/js/services/ApiService.ts
  28. 1
      resources/sass/app.scss
  29. 2
      resources/views/pages/home.blade.php
  30. 2
      routes/api.php
  31. 5
      routes/web.php
  32. 7
      webpack.mix.js

113
app/Http/Controllers/FileController.php

@ -5,6 +5,8 @@ namespace App\Http\Controllers;
use Illuminate\Contracts\Container\BindingResolutionException;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Storage;
use Illuminate\Http\UploadedFile;
use GuzzleHttp\Client;
class FileController extends Controller
{
@ -17,15 +19,34 @@ class FileController extends Controller
*/
public function create(): JsonResponse
{
/** @var UploadedFile $file */
$file = request()->file('file');
$filename = time() . $file->getClientOriginalName();
$time = time();
$fileName = $time . '-' . $file->getClientOriginalName();
$fileId = $time . pathinfo($file->getClientOriginalName(), PATHINFO_FILENAME);
$path = Storage::putFileAs('files/', $file, $filename);
$path = Storage::putFileAs('files/', $file, $fileName);
$guzzle = new Client();
/** @var \Psr\Http\Message\ResponseInterface $response */
$response = $guzzle->request('POST', 'http://ingest.sandd/ingest', [
'multipart' => [
[
'name' => 'body',
'contents' => json_encode([ 'id' => $fileId ]),
'headers' => [ 'Content-Type' => 'application/json' ]
],
[
'name' => 'document',
'contents' => fopen($file->getPathname(), 'r')
]
]
]);
return response()->json([
'file' => $file->getClientOriginalName(),
'id' => $filename,
'path' => $path
'id' => $fileId,
'path' => $path,
]);
}
@ -40,6 +61,88 @@ class FileController extends Controller
*/
public function get(string $id): JsonResponse
{
return response()->json(['success']);
$success = rand(0, 1);
if ($success == 1) {
$text = <<<EOT
## About Laravel
Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable and creative experience to be truly fulfilling. Laravel takes the pain out of development by easing common tasks used in many web projects, such as:
- [Simple, fast routing engine](https://laravel.com/docs/routing).
- [Powerful dependency injection container](https://laravel.com/docs/container).
- Multiple back-ends for [session](https://laravel.com/docs/session) and [cache](https://laravel.com/docs/cache) storage.
- Expressive, intuitive [database ORM](https://laravel.com/docs/eloquent).
- Database agnostic [schema migrations](https://laravel.com/docs/migrations).
- [Robust background job processing](https://laravel.com/docs/queues).
- [Real-time event broadcasting](https://laravel.com/docs/broadcasting).
Laravel is accessible, powerful, and provides tools required for large, robust applications.
## Learning Laravel
Laravel has the most extensive and thorough [documentation](https://laravel.com/docs) and video tutorial library of all modern web application frameworks, making it a breeze to get started with the framework.
If you don't feel like reading, [Laracasts](https://laracasts.com) can help. Laracasts contains over 1500 video tutorials on a range of topics including Laravel, modern PHP, unit testing, and JavaScript. Boost your skills by digging into our comprehensive video library.
## Laravel Sponsors
We would like to extend our thanks to the following sponsors for funding Laravel development. If you are interested in becoming a sponsor, please visit the Laravel [Patreon page](https://patreon.com/taylorotwell).
- **[Vehikl](https://vehikl.com/)**
- **[Tighten Co.](https://tighten.co)**
- **[Kirschbaum Development Group](https://kirschbaumdevelopment.com)**
- **[64 Robots](https://64robots.com)**
- **[Cubet Techno Labs](https://cubettech.com)**
- **[Cyber-Duck](https://cyber-duck.co.uk)**
- **[British Software Development](https://www.britishsoftware.co)**
- **[Webdock, Fast VPS Hosting](https://www.webdock.io/en)**
- **[DevSquad](https://devsquad.com)**
- [UserInsights](https://userinsights.com)
- [Fragrantica](https://www.fragrantica.com)
- [SOFTonSOFA](https://softonsofa.com/)
- [User10](https://user10.com)
- [Soumettre.fr](https://soumettre.fr/)
- [CodeBrisk](https://codebrisk.com)
- [1Forge](https://1forge.com)
- [TECPRESSO](https://tecpresso.co.jp/)
- [Runtime Converter](http://runtimeconverter.com/)
- [WebL'Agence](https://weblagence.com/)
- [Invoice Ninja](https://www.invoiceninja.com)
- [iMi digital](https://www.imi-digital.de/)
- [Earthlink](https://www.earthlink.ro/)
- [Steadfast Collective](https://steadfastcollective.com/)
- [We Are The Robots Inc.](https://watr.mx/)
- [Understand.io](https://www.understand.io/)
- [Abdel Elrafa](https://abdelelrafa.com)
- [Hyper Host](https://hyper.host)
- [Appoly](https://www.appoly.co.uk)
- [OP.GG](https://op.gg)
## Contributing
Thank you for considering contributing to the Laravel framework! The contribution guide can be found in the [Laravel documentation](https://laravel.com/docs/contributions).
## Code of Conduct
In order to ensure that the Laravel community is welcoming to all, please review and abide by the [Code of Conduct](https://laravel.com/docs/contributions#code-of-conduct).
## Security Vulnerabilities
If you discover a security vulnerability within Laravel, please send an e-mail to Taylor Otwell via [taylor@laravel.com](mailto:taylor@laravel.com). All security vulnerabilities will be promptly addressed.
## License
The Laravel framework is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT).
EOT;
return response()->json([
'text' => $text,
'ready' => true
]);
}
return response()->json([
'ready' => false
]);
}
}

21
app/Http/Controllers/FilterController.php

@ -11,19 +11,28 @@ class FilterController extends Controller
'phone_number' => [
'display_name' => 'Phone number',
'options' => [
'replace_with' => [
'#', '*', 'x',
[
'name' => 'Replace with',
'type' => 'select',
'values' => [
'#', '*', 'x'
]
]
]
],
'email' => [
'display_name' => 'Email',
'options' => [
'replace_with' => [
'#', '*', 'x',
[
'name' => 'Replace with',
'type' => 'select',
'values' => [
'#', '*', 'x'
]
],
'include_domain' => [
true, false
[
'name' => 'Include domain',
'type' => 'switch'
]
]
]

10
app/Http/Controllers/HomeController.php

@ -3,10 +3,18 @@
namespace App\Http\Controllers;
use App\SearchDisplace\Searchers\Mapper;
use Illuminate\View\View;
use Illuminate\Contracts\View\Factory;
use Illuminate\Contracts\Container\BindingResolutionException;
class HomeController extends Controller
{
public function index()
/**
*
* @return View|Factory
* @throws BindingResolutionException
*/
public function index(): View
{
return view('pages.home', [
'searchers' => (new Mapper())->get(),

24
app/Http/Controllers/PagesController.php

@ -1,24 +0,0 @@
<?php
namespace App\Http\Controllers;
use Illuminate\View\View;
use Illuminate\Contracts\View\Factory;
use Illuminate\Contracts\Container\BindingResolutionException;
class PagesController extends Controller
{
/**
* Return the home page view
*
* @return View|Factory
*
* @throws BindingResolutionException
*/
public function home(): View
{
$filters = FilterController::$filters;
return view('pages.home')->with('filters', $filters);
}
}

183
package-lock.json

@ -11,9 +11,11 @@
"tsconfig-paths-webpack-plugin": "^3.5.1",
"vue": "^2.6.12",
"vue-class-component": "^7.2.6",
"vue-markdown-render": "^1.1.1",
"vue-property-decorator": "^8.1.0"
},
"devDependencies": {
"@types/markdown-it": "^12.0.1",
"@vue/cli-plugin-babel": "^3.8.0",
"@vue/cli-plugin-typescript": "^3.8.0",
"@vue/cli-service": "^3.8.0",
@ -2241,6 +2243,12 @@
"@types/node": "*"
}
},
"node_modules/@types/highlight.js": {
"version": "9.12.4",
"resolved": "https://registry.npmjs.org/@types/highlight.js/-/highlight.js-9.12.4.tgz",
"integrity": "sha512-t2szdkwmg2JJyuCM20e8kR2X59WCE5Zkl4bzm1u1Oukjm79zpbiAv+QjnwLnuuV0WHEcX2NgUItu0pAMKuOPww==",
"dev": true
},
"node_modules/@types/http-proxy": {
"version": "1.17.5",
"resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.5.tgz",
@ -2307,6 +2315,29 @@
"resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
"integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4="
},
"node_modules/@types/linkify-it": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-3.0.1.tgz",
"integrity": "sha512-pQv3Sygwxxh6jYQzXaiyWDAHevJqWtqDUv6t11Sa9CPGiXny66II7Pl6PR8QO5OVysD6HYOkHMeBgIjLnk9SkQ==",
"dev": true
},
"node_modules/@types/markdown-it": {
"version": "12.0.1",
"resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-12.0.1.tgz",
"integrity": "sha512-mHfT8j/XkPb1uLEfs0/C3se6nd+webC2kcqcy8tgcVr0GDEONv/xaQzAN+aQvkxQXk/jC0Q6mPS+0xhFwRF35g==",
"dev": true,
"dependencies": {
"@types/highlight.js": "^9.7.0",
"@types/linkify-it": "*",
"@types/mdurl": "*"
}
},
"node_modules/@types/mdurl": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-1.0.2.tgz",
"integrity": "sha512-eC4U9MlIcu2q0KQmXszyn5Akca/0jrQmwDRgpAMJai7qBWq4amIQhZyNau4VYGtCeALvW1/NtjzJJ567aZxfKA==",
"dev": true
},
"node_modules/@types/micromatch": {
"version": "2.3.30",
"resolved": "https://registry.npmjs.org/@types/micromatch/-/micromatch-2.3.30.tgz",
@ -14001,6 +14032,14 @@
"integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=",
"dev": true
},
"node_modules/linkify-it": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.2.tgz",
"integrity": "sha512-gDBO4aHNZS6coiZCKVhSNh43F9ioIL4JwRjLZPkoLIY4yZFwg264Y5lu2x6rb1Js42Gh6Yqm2f6L2AJcnkzinQ==",
"dependencies": {
"uc.micro": "^1.0.1"
}
},
"node_modules/loader-runner": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.2.0.tgz",
@ -14273,6 +14312,34 @@
"node": ">=0.10.0"
}
},
"node_modules/markdown-it": {
"version": "12.0.6",
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.0.6.tgz",
"integrity": "sha512-qv3sVLl4lMT96LLtR7xeRJX11OUFjsaD5oVat2/SNBIb21bJXwal2+SklcRbTwGwqWpWH/HRtYavOoJE+seL8w==",
"dependencies": {
"argparse": "^2.0.1",
"entities": "~2.1.0",
"linkify-it": "^3.0.1",
"mdurl": "^1.0.1",
"uc.micro": "^1.0.5"
},
"bin": {
"markdown-it": "bin/markdown-it.js"
}
},
"node_modules/markdown-it/node_modules/argparse": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
},
"node_modules/markdown-it/node_modules/entities": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz",
"integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==",
"funding": {
"url": "https://github.com/fb55/entities?sponsor=1"
}
},
"node_modules/md5": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz",
@ -14301,6 +14368,11 @@
"integrity": "sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA==",
"dev": true
},
"node_modules/mdurl": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz",
"integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4="
},
"node_modules/media-typer": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
@ -22476,6 +22548,11 @@
"node": ">=4.2.0"
}
},
"node_modules/uc.micro": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz",
"integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA=="
},
"node_modules/uglify-js": {
"version": "3.4.10",
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.10.tgz",
@ -22914,6 +22991,24 @@
}
}
},
"node_modules/vue-markdown-render": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/vue-markdown-render/-/vue-markdown-render-1.1.1.tgz",
"integrity": "sha512-NkkGOC4ip6C3Cp0dyFBCEPZ9dDF2yI2wrePSwoU2xamyhvcs0eJk0t9VZcUiKCz1bm5SvVeTelIU0qzVgi6jVQ==",
"dependencies": {
"markdown-it": "^12.0.4",
"punycode": "^2.1.1",
"vue": "^2.6.12"
}
},
"node_modules/vue-markdown-render/node_modules/punycode": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
"engines": {
"node": ">=6"
}
},
"node_modules/vue-property-decorator": {
"version": "8.5.1",
"resolved": "https://registry.npmjs.org/vue-property-decorator/-/vue-property-decorator-8.5.1.tgz",
@ -25941,6 +26036,12 @@
"@types/node": "*"
}
},
"@types/highlight.js": {
"version": "9.12.4",
"resolved": "https://registry.npmjs.org/@types/highlight.js/-/highlight.js-9.12.4.tgz",
"integrity": "sha512-t2szdkwmg2JJyuCM20e8kR2X59WCE5Zkl4bzm1u1Oukjm79zpbiAv+QjnwLnuuV0WHEcX2NgUItu0pAMKuOPww==",
"dev": true
},
"@types/http-proxy": {
"version": "1.17.5",
"resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.5.tgz",
@ -26007,6 +26108,29 @@
"resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
"integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4="
},
"@types/linkify-it": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-3.0.1.tgz",
"integrity": "sha512-pQv3Sygwxxh6jYQzXaiyWDAHevJqWtqDUv6t11Sa9CPGiXny66II7Pl6PR8QO5OVysD6HYOkHMeBgIjLnk9SkQ==",
"dev": true
},
"@types/markdown-it": {
"version": "12.0.1",
"resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-12.0.1.tgz",
"integrity": "sha512-mHfT8j/XkPb1uLEfs0/C3se6nd+webC2kcqcy8tgcVr0GDEONv/xaQzAN+aQvkxQXk/jC0Q6mPS+0xhFwRF35g==",
"dev": true,
"requires": {
"@types/highlight.js": "^9.7.0",
"@types/linkify-it": "*",
"@types/mdurl": "*"
}
},
"@types/mdurl": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-1.0.2.tgz",
"integrity": "sha512-eC4U9MlIcu2q0KQmXszyn5Akca/0jrQmwDRgpAMJai7qBWq4amIQhZyNau4VYGtCeALvW1/NtjzJJ567aZxfKA==",
"dev": true
},
"@types/micromatch": {
"version": "2.3.30",
"resolved": "https://registry.npmjs.org/@types/micromatch/-/micromatch-2.3.30.tgz",
@ -35470,6 +35594,14 @@
"integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=",
"dev": true
},
"linkify-it": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.2.tgz",
"integrity": "sha512-gDBO4aHNZS6coiZCKVhSNh43F9ioIL4JwRjLZPkoLIY4yZFwg264Y5lu2x6rb1Js42Gh6Yqm2f6L2AJcnkzinQ==",
"requires": {
"uc.micro": "^1.0.1"
}
},
"loader-runner": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.2.0.tgz",
@ -35690,6 +35822,30 @@
"object-visit": "^1.0.0"
}
},
"markdown-it": {
"version": "12.0.6",
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.0.6.tgz",
"integrity": "sha512-qv3sVLl4lMT96LLtR7xeRJX11OUFjsaD5oVat2/SNBIb21bJXwal2+SklcRbTwGwqWpWH/HRtYavOoJE+seL8w==",
"requires": {
"argparse": "^2.0.1",
"entities": "~2.1.0",
"linkify-it": "^3.0.1",
"mdurl": "^1.0.1",
"uc.micro": "^1.0.5"
},
"dependencies": {
"argparse": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
},
"entities": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz",
"integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w=="
}
}
},
"md5": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz",
@ -35718,6 +35874,11 @@
"integrity": "sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA==",
"dev": true
},
"mdurl": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz",
"integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4="
},
"media-typer": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
@ -42252,6 +42413,11 @@
"integrity": "sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w==",
"dev": true
},
"uc.micro": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz",
"integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA=="
},
"uglify-js": {
"version": "3.4.10",
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.10.tgz",
@ -42613,6 +42779,23 @@
"vue-style-loader": "^4.1.0"
}
},
"vue-markdown-render": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/vue-markdown-render/-/vue-markdown-render-1.1.1.tgz",
"integrity": "sha512-NkkGOC4ip6C3Cp0dyFBCEPZ9dDF2yI2wrePSwoU2xamyhvcs0eJk0t9VZcUiKCz1bm5SvVeTelIU0qzVgi6jVQ==",
"requires": {
"markdown-it": "^12.0.4",
"punycode": "^2.1.1",
"vue": "^2.6.12"
},
"dependencies": {
"punycode": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
}
}
},
"vue-property-decorator": {
"version": "8.5.1",
"resolved": "https://registry.npmjs.org/vue-property-decorator/-/vue-property-decorator-8.5.1.tgz",

2
package.json

@ -10,6 +10,7 @@
"production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --config=node_modules/laravel-mix/setup/webpack.config.js"
},
"devDependencies": {
"@types/markdown-it": "^12.0.1",
"@vue/cli-plugin-babel": "^3.8.0",
"@vue/cli-plugin-typescript": "^3.8.0",
"@vue/cli-service": "^3.8.0",
@ -32,6 +33,7 @@
"tsconfig-paths-webpack-plugin": "^3.5.1",
"vue": "^2.6.12",
"vue-class-component": "^7.2.6",
"vue-markdown-render": "^1.1.1",
"vue-property-decorator": "^8.1.0"
}
}

BIN
public/fonts/vendor/primevue/resources/themes/mdc-dark-indigo/roboto-v20-latin-ext_latin-500.woff

BIN
public/fonts/vendor/primevue/resources/themes/mdc-dark-indigo/roboto-v20-latin-ext_latin-500.woff2

BIN
public/fonts/vendor/primevue/resources/themes/mdc-dark-indigo/roboto-v20-latin-ext_latin-700.woff

BIN
public/fonts/vendor/primevue/resources/themes/mdc-dark-indigo/roboto-v20-latin-ext_latin-700.woff2

BIN
public/fonts/vendor/primevue/resources/themes/mdc-dark-indigo/roboto-v20-latin-ext_latin-regular.woff

BIN
public/fonts/vendor/primevue/resources/themes/mdc-dark-indigo/roboto-v20-latin-ext_latin-regular.woff2

32992
public/js/app.js
File diff suppressed because it is too large
View File

33
resources/js/app.ts

@ -4,6 +4,7 @@ import Vue from 'vue';
/**
* Import vendor classes
*/
import VueMarkdown from 'vue-markdown-render';
import PrimeVue from 'primevue/config';
import Button from 'primevue/button';
import Panel from 'primevue/panel';
@ -20,15 +21,21 @@ import Skeleton from 'primevue/skeleton';
import ToastService from 'primevue/toastservice';
import Toast from 'primevue/toast';
import Fieldset from 'primevue/fieldset';
import Dropdown from 'primevue/dropdown';
import InputSwitch from 'primevue/inputswitch';
import DataTable from 'primevue/datatable';
import Column from 'primevue/column';
import OverlayPanel from 'primevue/overlaypanel';
import Checkbox from 'primevue/checkbox';
import ProgressSpinner from 'primevue/progressspinner';
import InputText from 'primevue/inputtext';
// Own components
import AppHeader from './components/layout/Header.vue';
import AppFooter from './components/layout/Footer.vue';
import Home from './components/Home.vue';
import ProcessFile from './components/ProcessFile.vue';
import Filter from './components/helpers/Filter.vue';
import SelectButton from 'primevue/selectbutton';
import ApiPlugin from '@plugins/ApiPlugin';
import AppHeader from '@components/layout/Header.vue';
import AppFooter from '@components/layout/Footer.vue';
import Home from '@components/Home/Home.vue';
import ProcessFile from '@components/ProcessFile/ProcessFile.vue';
Vue.use(PrimeVue, {
@ -36,7 +43,9 @@ Vue.use(PrimeVue, {
});
Vue.use(ToastService);
Vue.use(ApiPlugin);
Vue.component('vue-markdown', VueMarkdown);
Vue.component('Button', Button);
Vue.component('Panel', Panel);
Vue.component('Card', Card);
@ -50,12 +59,18 @@ Vue.component('Listbox', Listbox);
Vue.component('Toolbar', Toolbar);
Vue.component('Skeleton', Skeleton);
Vue.component('Toast', Toast);
Vue.component('SelectButton', SelectButton);
Vue.component('Dropdown', Dropdown);
Vue.component('Fieldset', Fieldset);
Vue.component('InputSwitch', InputSwitch);
Vue.component('DataTable', DataTable);
Vue.component('Column', Column);
Vue.component('OverlayPanel', OverlayPanel);
Vue.component('Checkbox', Checkbox);
Vue.component('ProgressSpinner', ProgressSpinner);
Vue.component('InputText', InputText);
Vue.component('home', Home);
Vue.component('process-file', ProcessFile);
Vue.component('filter-view', Filter);
Vue.component('app-header', AppHeader);
Vue.component('app-footer', AppFooter);

100
resources/js/components/Home.vue

@ -1,100 +0,0 @@
<template>
<div class="wrap" v-if="!fileUploaded && !uploading">
<Toast position="top-right" />
<Panel header="Please upload a file">
<FileUpload
name="demo[]"
:customUpload="true"
:auto="true"
@uploader="uploadFile"
>
<template #empty>
<p>Drag and drop files to here to upload.</p>
</template>
</FileUpload>
</Panel>
<BlockUI :blocked="uiBlocked" :fullScreen="true"></BlockUI>
</div>
<div class="wrap" v-else-if="!fileUploaded && uploading">
<Skeleton />
<Skeleton />
<Skeleton />
<Skeleton />
<Skeleton />
<Skeleton />
<Skeleton />
</div>
<div class="wrap" v-else>
<process-file :file="uploadResult" :filters="filters"></process-file>
</div>
</template>
<script lang="ts">
import axios from 'axios';
// import Vue from 'vue';
// import Component from 'vue-class-component';
import { Vue, Component, Prop } from 'vue-property-decorator';
@Component
export default class Home extends Vue {
@Prop({ default: [] })
public readonly filters!: Array<object>
public uiBlocked = false;
public uploading = false;
public fileUploaded: boolean = false;
public uploadResult = null;
/**
*
*/
public created()
{
console.log(this.filters);
}
/**
* A method which uploads the files to the server for processing
*
* @param event The event containing the uploaded files information
*/
public uploadFile(event: any): void {
this.uploading = true;
this.fileUploaded = false;
this['$toast'].add({severity:'success', summary: 'Success Message', detail:'Order submitted', life: 3000});
let file = event.files[0];
let formData = new FormData();
formData.append('file', file);
setTimeout(
() => {
axios.post(
'http://core.sandd/api/file',
formData,
{
headers: {
'Content-Type': 'multipart/form-data'
}
}
).then(
(response) => {
this.fileUploaded = true;
this.uploadResult = response.data;
// console.log('Success: ', response);
}
).catch(
(err) => {
console.log('Error: ', err);
}
);
}, 500
)
}
}
</script>

42
resources/js/components/Home/Home.ts

@ -0,0 +1,42 @@
import axios from 'axios';
import { Vue, Component, Prop } from 'vue-property-decorator';
@Component
export default class Home extends Vue {
@Prop({ default: [] })
public readonly searchers!: { [key: string]: string; }
public uiBlocked = false;
public uploading = false;
public fileUploaded: boolean = false;
public uploadResult = null;
/**
*
*/
public created()
{}
/**
* A method which uploads the files to the server for processing
*
* @param event The event containing the uploaded files information
*/
public uploadFile(event: any): void {
this.uploading = true;
this.fileUploaded = false;
this.$toast.add({severity:'success', summary: 'Success Message', detail:'Order submitted', life: 3000});
let file = event.files[0];
setTimeout(
async () => {
let response = await this.$api.uploadFile(file);
this.fileUploaded = true;
this.uploadResult = response;
}, 500
)
}
}

35
resources/js/components/Home/Home.vue

@ -0,0 +1,35 @@
<template>
<div class="wrap" v-if="!fileUploaded && !uploading">
<Toast position="top-right" />
<Panel header="Please upload a file">
<FileUpload
name="demo[]"
:customUpload="true"
:auto="true"
@uploader="uploadFile"
>
<template #empty>
<p>Drag and drop files to here to upload.</p>
</template>
</FileUpload>
</Panel>
<BlockUI :blocked="uiBlocked" :fullScreen="true"></BlockUI>
</div>
<div class="wrap" v-else-if="!fileUploaded && uploading">
<Skeleton />
<Skeleton />
<Skeleton />
<Skeleton />
<Skeleton />
<Skeleton />
<Skeleton />
</div>
<div class="wrap" v-else>
<process-file :file="uploadResult" :searchers="searchers"></process-file>
</div>
</template>
<script lang="ts" src="./Home.ts">
</script>

84
resources/js/components/ProcessFile.vue

@ -1,84 +0,0 @@
<template>
<div class="p-d-flex p-flex-row p-jc-between p-ai-stretch">
<Panel
class="p-mr-2 p-as-stretch file-card"
>
<template #header>
File preview
</template>
<Skeleton /><br />
<Skeleton /><br />
<Skeleton /><br />
<Skeleton /><br />
<Skeleton /><br />
<Skeleton /><br />
<Skeleton /><br />
</Panel>
<Card class="p-mr-2 p-as-stretch filters-card">
<template #header>
<Toolbar>
<template #left>
<h3>Available filters</h3>
</template>
<template #right>
<Button
icon="pi pi-plus"
class="p-button-success"
/>
</template>
</Toolbar>
</template>
<template #content>
<filter-view
v-for="(filter, id, index) in filters"
:key="index"
:id="id"
:display-name="filter.display_name"
:options="filter.options"
></filter-view>
</template>
</Card>
</div>
</template>
<script lang="ts">
import axios from 'axios';
import { Vue, Component, Prop } from 'vue-property-decorator';
import { FileData } from '../interfaces/FileData';
import { FilterInterface } from '../interfaces/FilterInterface';
@Component
export default class ProcessFile extends Vue {
@Prop({ default: null })
public readonly file!: FileData|null;
@Prop({ default: [] })
public readonly filters!: { [keys:string]: FilterInterface }
private selectedFile: File|null = null;
private selectedFilters = [];
/**
*
*/
created() {
console.log('FILE: ', this.file);
console.log('FILTERS: ', this.filters);
}
}
</script>
<style lang="scss">
.file-card {
flex: 0 1 66%;
}
.filters-card {
flex: 0 1 32%
}
</style>

11
resources/js/components/ProcessFile/ProcessFile.scss

@ -0,0 +1,11 @@
.file-card {
flex: 0 1 74%;
}
.filters-card {
flex: 0 1 24%
}
.p-overlaypanel {
// width: 450px;
min-width: 300px;
}

121
resources/js/components/ProcessFile/ProcessFile.ts

@ -0,0 +1,121 @@
import axios from 'axios';
// import OverlayPanel from 'primevue/overlaypanel/OverlayPanel';
import { Vue, Component, Prop, Watch } from 'vue-property-decorator';
import { FileData } from '@interfaces/FileData';
@Component
export default class ProcessFile extends Vue {
/**
* Props
*/
// The data for the file we are processing
@Prop({ default: { id: -1, file: '', path: '' } })
public readonly file!: FileData;
// The list of available searchers
@Prop({ default: [] })
public readonly searchers!: { [keys: string]: string; }
/**
* Class members
*/
public $refs!: {
'searchers-overlay': any
}
// The id of the interval used to query the file status
private intervalId!: any;
// The content of the file we are processing
private fileContent: string = '';
// The list of filters/searchers in a format usable by the datatable
private searchersData: Array<{ id: string; name: string; }> = [];
// The list of selected filters/searchers
private selectedSearchers: Array<{ id: string; name: string; }> = [];
//The list of expanded rows in the selected filters/searchers table
private expandedRows: Array<{id: string; name: string; }> = [];
/**
*
*/
created() {
for(let index in this.searchers) {
let searcherData = {
id: index,
name: this.searchers[index]
};
this.searchersData.push(searcherData);
}
this.intervalId = setInterval(this.waitForFile, 3000);
}
/**
*
*/
private async waitForFile() {
const response = await this.$api.getFileData(this.file.id);
if (response.text !== null && response.ready === true) {
if (response.ingest_status === 'fail') {
this.$toast.add({
severity: 'error',
summary: 'File error',
detail: 'THere was an error processing the file in ingest',
life: 3000
});
} else {
this.fileContent = response.documentContent;
this.$toast.add({
severity:'success',
summary: 'File loaded',
detail: 'The file has been processed by ingest.',
life: 3000
});
clearInterval(this.intervalId);
}
} else {
console.log('FILE NOT READY YET!');
}
}
private toggleSearchersMenu($event: any) {
this.$refs['searchers-overlay'].toggle($event);
}
private onRowSelect($event: any) {
console.log('SELECT: ', $event);
console.log(this.selectedSearchers);
}
private onRowUnselect($event: any) {
console.log('UNSELECT: ', $event);
console.log(this.selectedSearchers);
}
private onSelectedSearchersReorder($event: any)
{
this.selectedSearchers = $event.value;
}
private onSelectedSearcherExpand($event:any)
{
}
private onSelectedSearcherCollapse($event:any)
{
}
}

111
resources/js/components/ProcessFile/ProcessFile.vue

@ -0,0 +1,111 @@
<template>
<div class="p-d-flex p-flex-row p-jc-between p-ai-stretch">
<Toast />
<Card
class="p-mr-2 p-as-stretch file-card"
>
<template #header>
<Toolbar>
<template #left>
<h3>File preview</h3>
</template>
</Toolbar>
</template>
<template #content>
<template v-if="fileContent === ''">
<Skeleton /><br />
<Skeleton /><br />
<Skeleton /><br />
<Skeleton /><br />
<Skeleton /><br />
<Skeleton /><br />
<Skeleton /><br />
</template>
<template v-else>
<vue-markdown :source="fileContent" />
</template>
</template>
</Card>
<Card class="p-mr-2 p-as-stretch filters-card">
<template #header>
<Toolbar>
<template #left>
<h3>Document searchers</h3>
</template>
<template #right>
<Button
icon="pi pi-plus"
class="p-button-success p-button-sm p-button-text"
@click="toggleSearchersMenu"
aria:haspopup="true"
aria-controls="overlay_panel" />
</template>
</Toolbar>
</template>
<template #content>
<DataTable
:value.sync="selectedSearchers"
dataKey="id"
:expandedRows.sync="expandedRows"
@row-reorder="onSelectedSearchersReorder"
@row-expand="onSelectedSearcherExpand"
@row-collapse="onSelectedSearcherCollapse">
<Column :rowReorder="true" headerStyle="width: 3rem" />
<Column field="name" header="Name" sortable></Column>
<Column :expander="true" headerStyle="width: 3rem" />
<template #expansion="slotProps">
<div class="options-subtable">
<!-- TODO: Add real options here -->
<h5>Options for {{slotProps.data.name}}</h5>
<!-- <ProgressSpinner /> -->
<div class="p-fluid">
<div class="p-field">
<label for="firstname">Option 1</label>
<InputText id="firstname" type="text" class="p-inputtext-sm" />
</div>
<div class="p-field">
<label for="lastname">Option 2</label>
<InputText id="lastname" type="text" class="p-inputtext-sm" />
</div>
</div>
</div>
</template>
</DataTable>
</template>
</Card>
<OverlayPanel
ref="searchers-overlay"
appendTo="body"
id="overlay_panel"
style="width: 300px">
<DataTable
:value.sync="searchersData"
:selection.sync="selectedSearchers"
dataKey="id"
selectionMode="multiple"
class="p-datatable-sm"
:metaKeySelection="false">
<Column selectionMode="multiple" headerStyle="width: 3em"></Column>
<Column field="name" header="Name" sortable></Column>
</DataTable>
</OverlayPanel>
</div>
</template>
<script lang="ts" src="./ProcessFile.ts"></script>
<style lang="scss" src="./ProcessFile.scss"></style>

69
resources/js/components/helpers/Filter.vue

@ -1,69 +0,0 @@
<template>
<Fieldset :legend="displayName" :toggleable="true" class="filter-container">
<div v-for="option of optionsList" :key="option.name" class="filter-option">
<h5>{{ option.name }}</h5>
<SelectButton
:key="option.name"
v-model="selectedOption"
:options="option.list"
optionLabel="name" />
</div>
</Fieldset>
</template>
<script lang="ts">
import { Vue, Component, Prop } from 'vue-property-decorator';
import { FilterOptions } from '../../interfaces/FilterOptions';
@Component
export default class Filter extends Vue {
@Prop(String)
public readonly id!: string;
@Prop(String)
public readonly displayName!: string;
@Prop({ default: [] })
public readonly options!: FilterOptions;
private optionsList = new Array;
public selectedOption = null;
public created()
{
for (let index in this.options) {
let words = index.split('_');
for (let i = 0; i < words.length; i++) {
words[i] = words[i].charAt(0).toUpperCase() + words[i].substr(1);
}
let option = {
name: words.join(' '),
list: new Array
};
this.options[index].forEach( opt => {
option.list.push({
'name': opt,
'value': opt
});
});
this.optionsList.push(option);
}
}
}
</script>
<style lang="scss">
.filter-container,
.filter-option {
margin-bottom: 10px;
}
</style>

7
resources/js/interfaces/FilterInterface.ts

@ -1,7 +0,0 @@
import { FilterOptions } from "./FilterOptions";
export interface FilterInterface
{
display_name: string;
options: FilterOptions;
}

4
resources/js/interfaces/FilterOptions.ts

@ -1,4 +0,0 @@
export interface FilterOptions
{
[keys: string]: string[]
}

18
resources/js/plugins/ApiPlugin.ts

@ -0,0 +1,18 @@
import _Vue, { PluginFunction } from 'vue';
import ApiService from '@services/ApiService';
const ApiPlugin = {
install: (Vue: typeof _Vue, options?: any) => {
let apiService = new ApiService();
Vue.mixin({
created() {
Vue.prototype.$api = apiService;
}
})
}
}
export default ApiPlugin;

7
resources/js/plugins/plugins.d.ts

@ -0,0 +1,7 @@
import ApiService from '@services/ApiService';
declare module 'vue/types/vue' {
interface Vue {
$api: ApiService;
}
}

60
resources/js/services/ApiService.ts

@ -0,0 +1,60 @@
import axios from 'axios';
export default class ApiService {
private readonly baseUrl: string = 'http://core.sandd';
private readonly apiRoutes = {
file: '/api/file',
searchAndDisplace: '/search-and-displace'
};
constructor()
{}
/**
* Upload a file to the server and return its response.
* Throws an error if the response wasn't successful
*
* @param file
* @returns
*/
public async uploadFile(file: File)
{
let formData = new FormData();
formData.append('file', file);
try {
let response = await axios.post(
this.baseUrl + this.apiRoutes.file,
formData,
{
headers: {
'Content-Type': 'multipart/form-data'
}
}
)
return response.data;
} catch (err) {
throw err;
}
}
/**
* Get data for a file from the server.
* Throws an error if the response wasn't successful
*
* @param fileId
* @returns
*/
public async getFileData(fileId: string)
{
try {
let response = await axios.get(this.baseUrl + this.apiRoutes.searchAndDisplace + `/${fileId}`);
return response.data;
} catch (err) {
throw err;
}
}
}

1
resources/sass/app.scss

@ -11,6 +11,7 @@
// @import '~primevue/resources/themes/fluent-light/theme.css';
// @import '~primevue/resources/themes/vela-green/theme.css';
@import '~primevue/resources/themes/mdc-light-indigo/theme.css';
// @import '~primevue/resources/themes/mdc-dark-indigo/theme.css';
@import '~primevue/resources/primevue.min.css';
@import '~primeicons/primeicons.css';

2
resources/views/pages/home.blade.php

@ -7,7 +7,7 @@
<app-header></app-header>
<div class="content">
<home :filters="{{ json_encode($filters) }}"></home>
<home :searchers="{{ json_encode($searchers) }}"></home>
</div>
</div>

2
routes/api.php

@ -35,7 +35,7 @@ Route::name('file.')->prefix('file')->group(
}
);
# File routes
# Filter routes
// Route::name('filter.')->prefix('filter')->middleware('auth:api')->group(
Route::name('filter.')->prefix('filter')->group(

5
routes/web.php

@ -19,9 +19,4 @@ Route::get('/', 'HomeController@index');
Route::get('/search-and-displace/{id}', 'SearchAndDisplaceController@show');
Route::post('/search-and-displace', 'SearchAndDisplaceController@store');
Route::get('/', [
PagesController::class,
'home'
]);
Route::webhooks('/webhooks', 'default');

7
webpack.mix.js

@ -15,8 +15,11 @@ const path = require('path');
mix.webpackConfig({
resolve: {
alias: {
"@/*": path.resolve(__dirname, "resources/js/"),
"@components/*": path.resolve(__dirname, "resources/js/components/"),
"@": path.resolve(__dirname, "resources/js/"),
"@components": path.resolve(__dirname, "resources/js/components/"),
"@interfaces": path.resolve(__dirname, "resources/js/interfaces/"),
"@services": path.resolve(__dirname, "resources/js/services/"),
"@plugins": path.resolve(__dirname, "resources/js/plugins/"),
}
}
});

Loading…
Cancel
Save