Compare commits
20
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
afa2ee472e | ||
|
|
912c120299 | ||
|
|
cb98e67e04 | ||
|
|
01f5fa8e75 | ||
|
|
0fb4223bfc | ||
|
|
fd6646c1ee | ||
|
|
b018a6e290 | ||
|
|
6391e38dbf | ||
|
|
02ee378ec9 | ||
|
|
1eb7c56729 | ||
|
|
ddda4c9f1d | ||
|
|
cd6dfdbe30 | ||
|
|
828e2c4236 | ||
|
|
77d2a5e998 | ||
|
|
c4a7061e87 | ||
|
|
83d617a0a7 | ||
|
|
0a689bb11f | ||
|
|
5c51cc4c73 | ||
|
|
36a4353269 | ||
|
|
465f6fe5ee |
@@ -27,3 +27,4 @@ yarn-error.log
|
||||
**/.DS_Store
|
||||
/provision/
|
||||
/.scannerwork/
|
||||
/storage/logs
|
||||
|
||||
@@ -1,168 +0,0 @@
|
||||
<laravel-boost-guidelines>
|
||||
=== foundation rules ===
|
||||
|
||||
# Laravel Boost Guidelines
|
||||
|
||||
The Laravel Boost guidelines are specifically curated by Laravel maintainers for this application. These guidelines should be followed closely to ensure the best experience when building Laravel applications.
|
||||
|
||||
## Foundational Context
|
||||
|
||||
This application is a Laravel application running on PHP 8.3. You are an expert with the Laravel ecosystem. Always use the APIs that match the installed major version of each package — do not assume a version.
|
||||
|
||||
Before relying on a package's API, confirm its installed version:
|
||||
- PHP packages: run `composer show --direct` to list direct dependencies with versions, or `composer show <vendor/package>` for a single package.
|
||||
- JS packages: check `package.json` for the installed versions.
|
||||
|
||||
## Skills Activation
|
||||
|
||||
This project has domain-specific skills available in `**/skills/**`. You MUST activate the relevant skill whenever you work in that domain—don't wait until you're stuck.
|
||||
|
||||
## Conventions
|
||||
|
||||
- You must follow all existing code conventions used in this application. When creating or editing a file, check sibling files for the correct structure, approach, and naming.
|
||||
- Use descriptive names for variables and methods. For example, `isRegisteredForDiscounts`, not `discount()`.
|
||||
- Check for existing components to reuse before writing a new one.
|
||||
|
||||
## Verification Scripts
|
||||
|
||||
- Do not create verification scripts or tinker when tests cover that functionality and prove they work. Unit and feature tests are more important.
|
||||
|
||||
## Application Structure & Architecture
|
||||
|
||||
- Stick to existing directory structure; don't create new base folders without approval.
|
||||
- Do not change the application's dependencies without approval.
|
||||
|
||||
## Frontend Bundling
|
||||
|
||||
- If the user doesn't see a frontend change reflected in the UI, it could mean they need to run `npm run build`, `npm run dev`, or `composer run dev`. Ask them.
|
||||
|
||||
## Documentation Files
|
||||
|
||||
- You must only create documentation files if explicitly requested by the user.
|
||||
|
||||
## Replies
|
||||
|
||||
- Be concise in your explanations - focus on what's important rather than explaining obvious details.
|
||||
|
||||
=== boost rules ===
|
||||
|
||||
# Laravel Boost
|
||||
|
||||
## Tools
|
||||
|
||||
- Laravel Boost is an MCP server with tools designed specifically for this application. Prefer Boost tools over manual alternatives like shell commands or file reads.
|
||||
- Use `database-query` to run read-only queries against the database instead of writing raw SQL in tinker.
|
||||
- Use `database-schema` to inspect table structure before writing migrations or models.
|
||||
- Use `get-absolute-url` to resolve the correct scheme, domain, and port for project URLs. Always use this before sharing a URL with the user.
|
||||
- Use `browser-logs` to read browser logs, errors, and exceptions. Only recent logs are useful, ignore old entries.
|
||||
|
||||
## Searching Documentation (IMPORTANT)
|
||||
|
||||
- Always use `search-docs` before making code changes. Do not skip this step. It returns version-specific docs based on installed packages automatically.
|
||||
- Pass a `packages` array to scope results when you know which packages are relevant.
|
||||
- Use multiple broad, topic-based queries: `['rate limiting', 'routing rate limiting', 'routing']`. Expect the most relevant results first.
|
||||
- Do not add package names to queries because package info is already shared. Use `test resource table`, not `filament 4 test resource table`.
|
||||
|
||||
### Search Syntax
|
||||
|
||||
1. Use words for auto-stemmed AND logic: `rate limit` matches both "rate" AND "limit".
|
||||
2. Use `"quoted phrases"` for exact position matching: `"infinite scroll"` requires adjacent words in order.
|
||||
3. Combine words and phrases for mixed queries: `middleware "rate limit"`.
|
||||
4. Use multiple queries for OR logic: `queries=["authentication", "middleware"]`.
|
||||
|
||||
## Project Rules
|
||||
|
||||
- This project contains committed, area-grouped rules in `.ai/rules` when that directory exists (settled decisions, non-obvious traps, standing constraints). Framework and package guidelines that only apply to specific paths (testing, frontend, components) also live there, under `.ai/rules/boost` — this is not just recorded decisions, it is load-bearing guidance you have not seen inline. Before you enter plan mode or create/edit any file, you MUST first: open @.ai/rules/index.md (it maps file globs to rule files), read every rule file whose globs cover the path(s) in scope, and run `grep -rin 'keyword' .ai/rules` to catch what a path match alone misses. Do not write code until you have read and are following every matching rule. If `.ai/rules` does not exist, continue without it.
|
||||
- Record durable rules with `record-rule` so the next agent or teammate inherits them instead of working them out again. Pass a `glob` (e.g. `app/Http/Controllers/**`), a short `title`, and a few-line `note`. Always use `record-rule`, never your native memory or notes tool — native memory is personal and session-scoped; only `.ai/rules` is shared with the team and persists in the repo.
|
||||
|
||||
## Artisan
|
||||
|
||||
- Run Artisan commands directly via the command line (e.g., `php artisan route:list`). Use `php artisan list` to discover available commands and `php artisan [command] --help` to check parameters.
|
||||
- Inspect routes with `php artisan route:list`. Filter with: `--method=GET`, `--name=users`, `--path=api`, `--except-vendor`, `--only-vendor`.
|
||||
- Read configuration values using dot notation: `php artisan config:show app.name`, `php artisan config:show database.default`. Or read config files directly from the `config/` directory.
|
||||
|
||||
## Tinker
|
||||
|
||||
- Execute PHP in app context for debugging and testing code. Do not create models without user approval, prefer tests with factories instead. Prefer existing Artisan commands over custom tinker code.
|
||||
- Always use single quotes to prevent shell expansion: `php artisan tinker --execute 'Your::code();'`
|
||||
- Double quotes for PHP strings inside: `php artisan tinker --execute 'User::where("active", true)->count();'`
|
||||
|
||||
=== php rules ===
|
||||
|
||||
# PHP
|
||||
|
||||
- Always use curly braces for control structures, even for single-line bodies.
|
||||
- Use PHP 8 constructor property promotion: `public function __construct(public GitHub $github) { }`. Do not leave empty zero-parameter `__construct()` methods unless the constructor is private.
|
||||
- Use explicit return type declarations and type hints for all method parameters: `function isAccessible(User $user, ?string $path = null): bool`
|
||||
- Use TitleCase for Enum keys: `FavoritePerson`, `BestLake`, `Monthly`.
|
||||
- Prefer PHPDoc blocks over inline comments. Only add inline comments for exceptionally complex logic.
|
||||
- Use array shape type definitions in PHPDoc blocks.
|
||||
|
||||
=== deployments rules ===
|
||||
|
||||
# Deployment
|
||||
|
||||
- Laravel can be deployed using [Laravel Cloud](https://cloud.laravel.com/), which is the fastest way to deploy and scale production Laravel applications.
|
||||
|
||||
=== tests rules ===
|
||||
|
||||
# Test Enforcement
|
||||
|
||||
- Every change must be programmatically tested. Write a new test or update an existing test, then run the affected tests to make sure they pass.
|
||||
- Run the minimum number of tests needed to ensure code quality and speed. Use `php artisan test --compact` with a specific filename or filter.
|
||||
|
||||
=== laravel/core rules ===
|
||||
|
||||
# Do Things the Laravel Way
|
||||
|
||||
- Use `php artisan make:` commands to create new files (i.e. migrations, controllers, models, etc.). You can list available Artisan commands using `php artisan list` and check their parameters with `php artisan [command] --help`.
|
||||
- If you're creating a generic PHP class, use `php artisan make:class`.
|
||||
- Pass `--no-interaction` to all Artisan commands to ensure they work without user input. You should also pass the correct `--options` to ensure correct behavior.
|
||||
|
||||
### Model Creation
|
||||
|
||||
- When creating new models, create useful factories and seeders for them too. Ask the user if they need any other things, using `php artisan make:model --help` to check the available options.
|
||||
|
||||
## APIs & Eloquent Resources
|
||||
|
||||
- For APIs, default to using Eloquent API Resources and API versioning unless existing API routes do not, then you should follow existing application convention.
|
||||
|
||||
## URL Generation
|
||||
|
||||
- When generating links to other pages, prefer named routes and the `route()` function.
|
||||
|
||||
## Testing
|
||||
|
||||
- When creating models for tests, use the factories for the models. Check if the factory has custom states that can be used before manually setting up the model.
|
||||
- Faker: Use methods such as `$this->faker->word()` or `fake()->randomDigit()`. Follow existing conventions whether to use `$this->faker` or `fake()`.
|
||||
- When creating tests, make use of `php artisan make:test [options] {name}` to create a feature test, and pass `--unit` to create a unit test. Most tests should be feature tests.
|
||||
|
||||
## Vite Error
|
||||
|
||||
- If you receive an "Illuminate\Foundation\ViteException: Unable to locate file in Vite manifest" error, you can run `npm run build` or ask the user to run `npm run dev` or `composer run dev`.
|
||||
|
||||
=== livewire/core rules ===
|
||||
|
||||
# Livewire
|
||||
|
||||
- Livewire allow to build dynamic, reactive interfaces in PHP without writing JavaScript.
|
||||
- You can use Alpine.js for client-side interactions instead of JavaScript frameworks.
|
||||
- Keep state server-side so the UI reflects it. Validate and authorize in actions as you would in HTTP requests.
|
||||
|
||||
=== pint/core rules ===
|
||||
|
||||
# Laravel Pint Code Formatter
|
||||
|
||||
- If you have modified any PHP files, you must run `vendor/bin/pint --dirty --format agent` before finalizing changes to ensure your code matches the project's expected style.
|
||||
- Do not run `vendor/bin/pint --test --format agent`, simply run `vendor/bin/pint --format agent` to fix any formatting issues.
|
||||
|
||||
=== pest/core rules ===
|
||||
|
||||
## Pest
|
||||
|
||||
- This project uses Pest for testing. Create tests: `php artisan make:test --pest {name}`.
|
||||
- The `{name}` argument should not include the test suite directory. Use `php artisan make:test --pest SomeFeatureTest` instead of `php artisan make:test --pest Feature/SomeFeatureTest`.
|
||||
- Run tests: `php artisan test --compact` or filter: `php artisan test --compact --filter=testName`.
|
||||
- Do NOT delete tests without approval.
|
||||
|
||||
</laravel-boost-guidelines>
|
||||
Generated
-2736
File diff suppressed because it is too large
Load Diff
@@ -1,11 +0,0 @@
|
||||
# iOS 12 build fix
|
||||
|
||||
The root build command now installs each module's own locked npm dependencies before Vite runs.
|
||||
This is required because Modules/Helpdesk/Resources/assets/js/app.js imports jquery, select2 and flatpickr from Modules/Helpdesk/package.json.
|
||||
|
||||
Use:
|
||||
|
||||
npm install
|
||||
npm run build
|
||||
|
||||
Do not manually install jquery/select2/flatpickr into the root project.
|
||||
@@ -1,5 +0,0 @@
|
||||
# iOS 12 compatibility
|
||||
|
||||
The backend detects iOS 12 in `resources/themes/backend/views/partials/head.blade.php` and adds an `ios12` class to `<html>`. The compatibility rules are at the end of `resources/themes/backend/assets/css/helpdesk.css`.
|
||||
|
||||
The iOS 12 dashboard deliberately uses flexbox instead of CSS Grid and uses inline SVG for critical shell/dashboard icons so it does not depend on modern Font Awesome webfont behaviour. Modern browsers continue to use the normal theme.
|
||||
@@ -0,0 +1,517 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Modules\Documentation\Console;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Str;
|
||||
use Modules\Documentation\Models\DocumentationCategory;
|
||||
use Modules\Documentation\Models\DocumentationDocument;
|
||||
use SplFileInfo;
|
||||
use Symfony\Component\Finder\Finder;
|
||||
use Throwable;
|
||||
|
||||
final class ImportDocumentationCommand extends Command
|
||||
{
|
||||
/**
|
||||
* The console command signature.
|
||||
*/
|
||||
protected $signature = 'helpdesk:import-documentation
|
||||
|
||||
{path? : Directory containing Markdown files; defaults to the bundled Sentinel documentation}
|
||||
|
||||
{--category=Sentinel Documentation : Documentation category name}
|
||||
|
||||
{--fresh : Remove previously imported documents in this category before importing}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*/
|
||||
protected $description = 'Import Markdown documentation into the Helpdesk Documentation module.';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*/
|
||||
public function handle(): int
|
||||
{
|
||||
|
||||
$path = $this->resolvePath();
|
||||
|
||||
$categoryName = trim((string) $this->option('category'));
|
||||
|
||||
if ($categoryName === '') {
|
||||
|
||||
$this->components->error('The documentation category name cannot be empty.');
|
||||
|
||||
return self::FAILURE;
|
||||
|
||||
}
|
||||
|
||||
if (! is_dir($path)) {
|
||||
|
||||
$this->components->error("Documentation directory does not exist: {$path}");
|
||||
|
||||
return self::FAILURE;
|
||||
|
||||
}
|
||||
|
||||
if (! is_readable($path)) {
|
||||
|
||||
$this->components->error("Documentation directory is not readable: {$path}");
|
||||
|
||||
return self::FAILURE;
|
||||
|
||||
}
|
||||
|
||||
$files = $this->markdownFiles($path);
|
||||
|
||||
if ($files === []) {
|
||||
|
||||
$this->components->warn("No Markdown files were found in: {$path}");
|
||||
|
||||
return self::SUCCESS;
|
||||
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
$category = DB::transaction(function () use ($categoryName): DocumentationCategory {
|
||||
|
||||
$category = DocumentationCategory::query()->firstOrCreate(
|
||||
|
||||
['slug' => Str::slug($categoryName)],
|
||||
|
||||
[
|
||||
|
||||
'name' => $categoryName,
|
||||
|
||||
'description' => 'Imported documentation.',
|
||||
|
||||
'sort_order' => 0,
|
||||
|
||||
'is_active' => true,
|
||||
|
||||
],
|
||||
|
||||
);
|
||||
|
||||
if ($category->name !== $categoryName) {
|
||||
|
||||
$category->name = $categoryName;
|
||||
|
||||
$category->save();
|
||||
|
||||
}
|
||||
|
||||
if ($this->option('fresh')) {
|
||||
|
||||
/*
|
||||
|
||||
* Force-delete because DocumentationDocument uses SoftDeletes.
|
||||
|
||||
* Otherwise the unique slug constraint can prevent the same
|
||||
|
||||
* documentation set being imported again.
|
||||
|
||||
*/
|
||||
|
||||
$category->documents()
|
||||
|
||||
->withTrashed()
|
||||
|
||||
->get()
|
||||
|
||||
->each(static function (DocumentationDocument $document): void {
|
||||
|
||||
$document->forceDelete();
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
return $category;
|
||||
|
||||
});
|
||||
|
||||
$progress = $this->output->createProgressBar(count($files));
|
||||
|
||||
$progress->start();
|
||||
|
||||
$imported = 0;
|
||||
|
||||
foreach ($files as $file) {
|
||||
|
||||
$this->importFile($category, $file, $path);
|
||||
|
||||
$imported++;
|
||||
|
||||
$progress->advance();
|
||||
|
||||
}
|
||||
|
||||
$progress->finish();
|
||||
|
||||
$this->newLine(2);
|
||||
|
||||
$this->components->info(
|
||||
|
||||
sprintf(
|
||||
|
||||
'Imported %d documentation %s into "%s".',
|
||||
|
||||
$imported,
|
||||
|
||||
$imported === 1 ? 'page' : 'pages',
|
||||
|
||||
$category->name,
|
||||
|
||||
),
|
||||
|
||||
);
|
||||
|
||||
return self::SUCCESS;
|
||||
|
||||
} catch (Throwable $exception) {
|
||||
|
||||
$this->newLine();
|
||||
|
||||
$this->components->error(
|
||||
|
||||
'Documentation import failed: '.$exception->getMessage(),
|
||||
|
||||
);
|
||||
|
||||
if ($this->output->isVerbose()) {
|
||||
|
||||
$this->newLine();
|
||||
|
||||
$this->line($exception->getTraceAsString());
|
||||
|
||||
}
|
||||
|
||||
return self::FAILURE;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the requested documentation source directory.
|
||||
*/
|
||||
private function resolvePath(): string
|
||||
{
|
||||
|
||||
$argument = $this->argument('path');
|
||||
|
||||
if (is_string($argument) && trim($argument) !== '') {
|
||||
|
||||
$path = trim($argument);
|
||||
|
||||
if (! str_starts_with($path, DIRECTORY_SEPARATOR)) {
|
||||
|
||||
$path = base_path($path);
|
||||
|
||||
}
|
||||
|
||||
return rtrim($path, DIRECTORY_SEPARATOR);
|
||||
|
||||
}
|
||||
|
||||
return module_path('Documentation', 'ImportData/docs');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Find Markdown files recursively.
|
||||
|
||||
*
|
||||
|
||||
* @return list<SplFileInfo>
|
||||
*/
|
||||
private function markdownFiles(string $path): array
|
||||
{
|
||||
|
||||
$finder = Finder::create()
|
||||
|
||||
->files()
|
||||
|
||||
->in($path)
|
||||
|
||||
->name('*.md')
|
||||
|
||||
->name('*.markdown')
|
||||
|
||||
->sortByName();
|
||||
|
||||
/** @var list<SplFileInfo> $files */
|
||||
$files = iterator_to_array($finder, false);
|
||||
|
||||
return $files;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Import one Markdown document.
|
||||
*/
|
||||
private function importFile(
|
||||
|
||||
DocumentationCategory $category,
|
||||
|
||||
SplFileInfo $file,
|
||||
|
||||
string $rootPath,
|
||||
|
||||
): void {
|
||||
|
||||
$realPath = $file->getRealPath();
|
||||
|
||||
if ($realPath === false || ! is_readable($realPath)) {
|
||||
|
||||
throw new \RuntimeException(
|
||||
sprintf('Unable to read documentation file: %s', $file->getPathname()),
|
||||
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
$body = file_get_contents($realPath);
|
||||
|
||||
if ($body === false) {
|
||||
|
||||
throw new \RuntimeException(
|
||||
sprintf('Unable to read documentation file: %s', $realPath),
|
||||
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
$body = $this->stripBom($body);
|
||||
|
||||
$relativePath = ltrim(
|
||||
|
||||
str_replace(
|
||||
|
||||
DIRECTORY_SEPARATOR,
|
||||
|
||||
'/',
|
||||
|
||||
substr($realPath, strlen(rtrim($rootPath, DIRECTORY_SEPARATOR))),
|
||||
|
||||
),
|
||||
|
||||
'/',
|
||||
|
||||
);
|
||||
|
||||
$title = $this->extractTitle($body, $file);
|
||||
|
||||
$summary = $this->extractSummary($body);
|
||||
|
||||
$slug = $this->makeSlug($relativePath, $title);
|
||||
|
||||
DocumentationDocument::withTrashed()->updateOrCreate(
|
||||
|
||||
['slug' => $slug],
|
||||
|
||||
[
|
||||
|
||||
'documentation_category_id' => $category->id,
|
||||
|
||||
'title' => $title,
|
||||
|
||||
'summary' => $summary,
|
||||
|
||||
'body' => $body,
|
||||
|
||||
'status' => DocumentationDocument::STATUS_PUBLISHED,
|
||||
|
||||
'is_featured' => strtolower($file->getBasename('.'.$file->getExtension())) === 'index',
|
||||
|
||||
'version' => '1.0.0',
|
||||
|
||||
'reference' => Str::limit($relativePath, 100, ''),
|
||||
|
||||
'published_at' => now(),
|
||||
|
||||
'deleted_at' => null,
|
||||
|
||||
],
|
||||
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the first Markdown H1 heading.
|
||||
*/
|
||||
private function extractTitle(string $body, SplFileInfo $file): string
|
||||
{
|
||||
|
||||
if (preg_match('/^\s*#\s+(.+?)\s*$/m', $body, $matches) === 1) {
|
||||
|
||||
$title = trim($matches[1]);
|
||||
|
||||
$title = preg_replace('/\s+#+\s*$/', '', $title) ?? $title;
|
||||
|
||||
$title = trim($title);
|
||||
|
||||
if ($title !== '') {
|
||||
|
||||
return Str::limit($title, 220, '');
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$filename = pathinfo($file->getFilename(), PATHINFO_FILENAME);
|
||||
|
||||
return Str::limit(
|
||||
|
||||
Str::headline(str_replace(['-', '_'], ' ', $filename)),
|
||||
|
||||
220,
|
||||
|
||||
'',
|
||||
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract a useful summary from the first normal Markdown paragraph.
|
||||
*/
|
||||
private function extractSummary(string $body): ?string
|
||||
{
|
||||
|
||||
$lines = preg_split('/\R/', $body);
|
||||
|
||||
if (! is_array($lines)) {
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
$paragraph = [];
|
||||
|
||||
foreach ($lines as $line) {
|
||||
|
||||
$line = trim($line);
|
||||
|
||||
if ($line === '') {
|
||||
|
||||
if ($paragraph !== []) {
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
if (
|
||||
|
||||
str_starts_with($line, '#')
|
||||
|
||||
|| str_starts_with($line, '```')
|
||||
|
||||
|| str_starts_with($line, '~~~')
|
||||
|
||||
|| str_starts_with($line, '>')
|
||||
|
||||
|| preg_match('/^[-*+]\s+/', $line) === 1
|
||||
|
||||
|| preg_match('/^\d+\.\s+/', $line) === 1
|
||||
|
||||
) {
|
||||
|
||||
if ($paragraph !== []) {
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
$paragraph[] = $line;
|
||||
|
||||
}
|
||||
|
||||
if ($paragraph === []) {
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
$summary = implode(' ', $paragraph);
|
||||
|
||||
$summary = preg_replace('/!$begin:math:display$\(\[\^$end:math:display$]*)\]$begin:math:text$\[\^\)\]\+$end:math:text$/', '$1', $summary) ?? $summary;
|
||||
|
||||
$summary = preg_replace('/$begin:math:display$\(\[\^$end:math:display$]+)\]$begin:math:text$\[\^\)\]\+$end:math:text$/', '$1', $summary) ?? $summary;
|
||||
|
||||
$summary = str_replace(['**', '__', '`', '*', '_'], '', $summary);
|
||||
|
||||
$summary = trim(preg_replace('/\s+/', ' ', $summary) ?? $summary);
|
||||
|
||||
return $summary === ''
|
||||
|
||||
? null
|
||||
|
||||
: Str::limit($summary, 500, '');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a stable globally unique slug from the source path.
|
||||
*/
|
||||
private function makeSlug(string $relativePath, string $title): string
|
||||
{
|
||||
|
||||
$withoutExtension = preg_replace(
|
||||
|
||||
'/\.(md|markdown)$/i',
|
||||
|
||||
'',
|
||||
|
||||
$relativePath,
|
||||
|
||||
) ?? $relativePath;
|
||||
|
||||
$slug = Str::slug(str_replace('/', '-', $withoutExtension));
|
||||
|
||||
if ($slug === '') {
|
||||
|
||||
$slug = Str::slug($title);
|
||||
|
||||
}
|
||||
|
||||
if ($slug === '') {
|
||||
|
||||
$slug = 'document-'.substr(sha1($relativePath), 0, 12);
|
||||
|
||||
}
|
||||
|
||||
return Str::limit($slug, 240, '');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a UTF-8 byte-order mark.
|
||||
*/
|
||||
private function stripBom(string $contents): string
|
||||
{
|
||||
|
||||
if (str_starts_with($contents, "\xEF\xBB\xBF")) {
|
||||
|
||||
return substr($contents, 3);
|
||||
|
||||
}
|
||||
|
||||
return $contents;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -31,7 +31,7 @@ class DocumentationController extends Controller
|
||||
}
|
||||
|
||||
if ($request->filled('search')) {
|
||||
$search = '%' . $request->string('search')->trim()->toString() . '%';
|
||||
$search = '%'.$request->string('search')->trim()->toString().'%';
|
||||
$query->where(function ($builder) use ($search): void {
|
||||
$builder->where('title', 'like', $search)
|
||||
->orWhere('summary', 'like', $search)
|
||||
|
||||
@@ -33,9 +33,9 @@ class StoreDocumentationDocumentRequest extends FormRequest
|
||||
'is_featured' => ['nullable', 'boolean'],
|
||||
'version' => ['required', 'string', 'max:50'],
|
||||
'reference' => ['nullable', 'string', 'max:100'],
|
||||
'attachment' => ['nullable', 'file', 'max:' . config('documentation.max_upload_kb', 20480), 'mimes:' . implode(',', config('documentation.allowed_upload_mimes', []))],
|
||||
'attachment' => ['nullable', 'file', 'max:'.config('documentation.max_upload_kb', 20480), 'mimes:'.implode(',', config('documentation.allowed_upload_mimes', []))],
|
||||
'attachments' => ['nullable', 'array'],
|
||||
'attachments.*' => ['file', 'max:' . config('documentation.max_upload_kb', 20480), 'mimes:' . implode(',', config('documentation.allowed_upload_mimes', []))],
|
||||
'attachments.*' => ['file', 'max:'.config('documentation.max_upload_kb', 20480), 'mimes:'.implode(',', config('documentation.allowed_upload_mimes', []))],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,9 +36,9 @@ class UpdateDocumentationDocumentRequest extends FormRequest
|
||||
'is_featured' => ['nullable', 'boolean'],
|
||||
'version' => ['required', 'string', 'max:50'],
|
||||
'reference' => ['nullable', 'string', 'max:100'],
|
||||
'attachment' => ['nullable', 'file', 'max:' . config('documentation.max_upload_kb', 20480), 'mimes:' . implode(',', config('documentation.allowed_upload_mimes', []))],
|
||||
'attachment' => ['nullable', 'file', 'max:'.config('documentation.max_upload_kb', 20480), 'mimes:'.implode(',', config('documentation.allowed_upload_mimes', []))],
|
||||
'attachments' => ['nullable', 'array'],
|
||||
'attachments.*' => ['file', 'max:' . config('documentation.max_upload_kb', 20480), 'mimes:' . implode(',', config('documentation.allowed_upload_mimes', []))],
|
||||
'attachments.*' => ['file', 'max:'.config('documentation.max_upload_kb', 20480), 'mimes:'.implode(',', config('documentation.allowed_upload_mimes', []))],
|
||||
'remove_attachment' => ['nullable', 'boolean'],
|
||||
];
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
### Sentinel API Development
|
||||
|
||||
This document details the overall development techniques for effective api development
|
||||
that makes the Sentinel product much more accessible and scalable.
|
||||
|
||||
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
### AS400 HTTP Server Documentation
|
||||
|
||||
To copy an Apache configuration file using an AS400 console, you'll need to use the IBM i operating system's file management tools. This involves creating a member for your HTTP server in a specific library, then using the COPY command to duplicate the configuration file.
|
||||
You can then edit the new member using the Data File Utility (DFU).
|
||||
|
||||
Here's a step-by-step guide:
|
||||
|
||||
1. Create the HTTP Server Member:
|
||||
Go to the QUSRSYS/QATMHINSTC library using the WRKMBRPDM command.
|
||||
Choose option 3 next to APACHEDFT and press F4 to prompt the COPYcommand.
|
||||
Change the TOMBR (To member) parameter to a unique name for your new HTTP server (e.g., MYAPACHE). This name cannot exceed 10 characters.
|
||||
Press Enter to accept the changes.
|
||||
|
||||
2. Edit the New Member:
|
||||
Type 18 next to the newly created member name (e.g., MYAPACHE) and press Enter.
|
||||
Page down once in the DFU.
|
||||
Modify the Instance Data value, ensuring it reflects the new configuration you want to use. For example:
|
||||
Change -apache -d /www/apachedft -f conf/httpd.conf -AutoStartN to a similar line that points to your new configuration files.
|
||||
Remember to update the paths to your configuration files (e.g., /www/MYAPACHE/conf/httpd.conf).
|
||||
|
||||
3. Create Directories and Copy Files:
|
||||
Use the 5250 command line to create the necessary directories for your new server instance:
|
||||
MKDIR '/www/MYAPACHE'
|
||||
MKDIR '/www/MYAPACHE/conf'
|
||||
MKDIR '/www/MYAPACHE/logs'
|
||||
MKDIR '/www/MYAPACHE/htdocs'
|
||||
Copy the configuration files from the source system to your new server instance using the COPY command or by using the IBM i's file management tools.
|
||||
|
||||
4. Configure the httpd.conf File (if necessary):
|
||||
Open the httpd.conf file (or apache2.conf) in a text editor.
|
||||
Make any necessary changes to the configuration, such as modifying paths, ports, or other settings as per your requirements.
|
||||
If you are setting up virtual hosts, ensure the virtual host definitions are included in the configuration file.
|
||||
Example:
|
||||
Code
|
||||
|
||||
|
||||
// Create a new member for the HTTP server
|
||||
|
||||
````
|
||||
WRKMBRPDM FILE(QUSRSYS/QATMHINSTC)
|
||||
````
|
||||
|
||||
// Select option 3 for APACHEDFT and press F4
|
||||
````
|
||||
COPY FROMBR(APACHEDFT) TOMBR(MYAPACHE)
|
||||
````
|
||||
|
||||
// Edit the new member using DFU
|
||||
|
||||
````
|
||||
WRKMBRPDM FILE(QUSRSYS/QATMHINSTC)
|
||||
````
|
||||
|
||||
// Type 18 next to MYAPACHE and press Enter
|
||||
|
||||
#### Important Notes:
|
||||
|
||||
The TOMBR parameter must be a unique name within the library.
|
||||
The new member's Instance Data must be correctly configured to point to your new Apache instance.
|
||||
Ensure you have the necessary permissions to modify the QUSRSYS/QATMHINSTClibrary.
|
||||
|
||||
You may need to restart the HTTP server after making changes to the configuration.
|
||||
This process duplicates an existing HTTP server instance. If you're configuring a new server, you may need to install Apache first, as well as configure the required directories and configuration files.
|
||||
BIN
Binary file not shown.
+141
@@ -0,0 +1,141 @@
|
||||
# Install and configure Cron Scheduling on IBM i
|
||||
|
||||
From IBM: Now available for #IBMi: cron, via the 'cronie' RPM package! Anacron, too!
|
||||
|
||||
This package can be a good way to schedule your open source jobs or CL commands to run on a regular basis.
|
||||
|
||||
Install cronie yum packages from IBM i ACS Open Source Package Management
|
||||
```
|
||||
Package list:
|
||||
cronie
|
||||
cronie-anacron
|
||||
```
|
||||
# Setting up sample crontab system schedule file
|
||||
|
||||
From your favorite bash editor, edit the system crontab file: in ***/QOpenSys/etc/crontab***
|
||||
|
||||
**The example listed below sends a message to QSYSOPR via calling an IBMi CL Command**
|
||||
|
||||
We also add APPLICATION_ENV=dev where dev is the environment file that is in use to take
|
||||
advantage of the environment switcher code and target the correct systems
|
||||
|
||||
```
|
||||
SHELL=/QOpenSys/pkgs/bin/bash
|
||||
PATH=/QOpenSys/pkgs/bin:/QOpenSys/usr/sbin:/QOpenSys/usr/bin
|
||||
MAILTO=qsecofr
|
||||
APPLICATION_ENV=DEV
|
||||
# For details see man 4 crontabs
|
||||
|
||||
# Example of job definition:
|
||||
# .---------------- minute (0 - 59)
|
||||
# | .------------- hour (0 - 23)
|
||||
# | | .---------- day of month (1 - 31)
|
||||
# | | | .------- month (1 - 12) OR jan,feb,mar,apr ...
|
||||
# | | | | .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
|
||||
# | | | | |
|
||||
# * * * * * ibmi-user-name command to be executed
|
||||
# Run a sample IBMi CL command every minute to send message to QSYSOPR
|
||||
*/1 * * * * QSECOFR system "SNDMSG MSG(CRONJOB) TOUSR(QSYSOPR)"
|
||||
# Run a sample IBMi CL command every minute to send message to QSYSOPR and log any stdout/stderr messages to custom log file /tmp/ibmicommand.log.
|
||||
*/1 * * * * QSECOFR system "SNDMSG MSG(CRONJOB) TOUSR(QSYSOPR)" >> /tmp/ibmicommand.log 2>&1
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
to monitor cron use crond -n -x proc this will dump its opertion to the console
|
||||
|
||||
```
|
||||
|
||||
|
||||
See crontab configuration sample links below for site that can teach you more about setting up your cron jobs via the crontab configration files.
|
||||
https://github.com/richardschoen/howtostuff/blob/master/installcronie.md#links
|
||||
|
||||
***Note: It appears that you must specify the user ID to run the selected job as. In the above example we are running the SNDMSG example as QSECOFR.***
|
||||
```Only /QOpenSys/etc/crontab and the files in /QOpenSys/etc/cron.d/ have a username field though. Ours on IBM i are prefixed with /QOpenSys obviously.```
|
||||
|
||||
Reading link for more info on running as a specific user.
|
||||
https://serverfault.com/questions/352835/crontab-running-as-a-specific-user
|
||||
|
||||
# Make sure crontab file and cron directories are owned by root user for running system jobs
|
||||
|
||||
Run the following commands from a SSH session to make sure root user (QSECOFR) owns the files and directories. Otherwise your crontab will not run correctly because of permission errors even though the crond daemon will start up.
|
||||
|
||||
```
|
||||
cd /QOpenSys/etc
|
||||
chown qsecofr crontab
|
||||
chown qsecofr cron.d
|
||||
chown qsecofr cron.hourly
|
||||
```
|
||||
|
||||
# Starting the crond daemon to run schedule jobs
|
||||
|
||||
Log in to SSH as IBM i QSECOFR level user. ```QSECOFR or a user with *ALLOBJ authority.```
|
||||
|
||||
Type: ```crond``` and press enter.
|
||||
|
||||
|
||||
From a 5250 session, run ***WRKACTJOB SBS(QUSRWRK) JOB(QP0ZSPWP)*** and you should see the active server jobs and threads in the QUSRWRK subsystem.
|
||||
|
||||
```
|
||||
--------------------------------------------------------------------------------
|
||||
QP0ZSPWP QSECOFR BCI .0 PGM-crond SELW
|
||||
--------------------------------------------------------------------------------
|
||||
```
|
||||
Tip: If your crontab jobs are not running, drill in to this job via ```option 5. Work with``` and then display the job log for the active crond daemon ```10. Display job log, if active, on job queue, or pending ```. Usually there will be an error listed if your crontab command line entries are bad or permissions aren't set right on your crond configuration files and directories.
|
||||
|
||||
|
||||
# Ending the crond daemon job
|
||||
|
||||
Log in to SSH as IBM i QSECOFR level user.
|
||||
|
||||
Type: ```kill `cat /QOpenSys/etc/crond.pid` ``` and press enter.
|
||||
|
||||
# Start crond daemon job bash script - startcrond.sh
|
||||
|
||||
This script can be used to start the crond background job as an active job in the QUSRWRK subsystem.
|
||||
|
||||
```
|
||||
#!/QOpenSys/pkgs/bin/bash
|
||||
crond -s
|
||||
```
|
||||
|
||||
# End crond daemon job bash script - endcrond.sh
|
||||
|
||||
This script can be used to end the crond background job if it's active. It used the process id stored in file /QOpenSys/etc/crond.pid to locate and kill the system job.
|
||||
|
||||
```
|
||||
#!/QOpenSys/pkgs/bin/bash
|
||||
kill `cat /QOpenSys/etc/crond.pid`
|
||||
```
|
||||
|
||||
# Start crond daemon job from QSHEXEC CL command
|
||||
|
||||
This CL command example utilizes the QSHEXEC command which is part of the QSHONI library for running QSH/PASE jobs from a regular IBM i job. https://github.com/richardschoen/qshoni
|
||||
|
||||
```
|
||||
QSHONI/QSHEXEC CMDLINE('crond') LOGSTDOUT(*YES)
|
||||
```
|
||||
|
||||
# End crond daemon job from QSHEXEC CL command
|
||||
|
||||
This CL command example utilizes the QSHEXEC command which is part of the QSHONI library for running QSH/PASE jobs from a regular IBM i job. https://github.com/richardschoen/qshoni
|
||||
|
||||
```
|
||||
QSHONI/QSHEXEC CMDLINE('kill ```cat /QOpenSys/etc/crond.pid```') LOGSTDOUT(*YES)
|
||||
```
|
||||
|
||||
This document does not cover production best practices. Best practices should be addressed with your Administration team or by researching Cron security best practices.
|
||||
|
||||
# Links
|
||||
|
||||
Cronie Github Site
|
||||
|
||||
https://github.com/cronie-crond/cronie
|
||||
|
||||
Crontab configuration examples
|
||||
|
||||
https://phoenixnap.com/kb/set-up-cron-job-linux
|
||||
|
||||
https://corenominal.org/2016/05/12/howto-setup-a-crontab-file/
|
||||
|
||||
https://pimylifeup.com/cron-jobs-and-crontab/
|
||||
+319
@@ -0,0 +1,319 @@
|
||||
View Model Implementation
|
||||
This is how the Laravel view model is used with the spares dashboard to remove all the logic
|
||||
from the blade view
|
||||
|
||||
### The DashboardViewModel
|
||||
|
||||
````
|
||||
<?php
|
||||
|
||||
namespace Modules\Spares\ViewModels;
|
||||
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Modules\Spares\Repositories\API\APIStorageRepository;
|
||||
use Psr\SimpleCache\InvalidArgumentException;
|
||||
use Throwable;
|
||||
|
||||
final class DashboardViewModel
|
||||
{
|
||||
public array $returns = [];
|
||||
public array $returnsLabels = [];
|
||||
public array $returnsValues = [];
|
||||
public float $totalPOValue = 0.0;
|
||||
|
||||
public array $inventory = [];
|
||||
public array $inventoryLabels = [];
|
||||
public array $inventoryValues = [];
|
||||
public float $totalInventoryValue = 0.0;
|
||||
|
||||
public array $issues = [];
|
||||
public array $issuesLabels = [];
|
||||
public array $issuesValues = [];
|
||||
public float $totalIssuesValue = 0.0;
|
||||
|
||||
public array $stock = [];
|
||||
public array $stockLabels = [];
|
||||
public array $stockValues = [];
|
||||
public float $totalStockValue = 0.0;
|
||||
public float $totalStockValueLastMonth = 0.0;
|
||||
|
||||
public float $grandTotal = 0.0;
|
||||
|
||||
public array $topTenIssues = [];
|
||||
public array $topTenInventory = [];
|
||||
|
||||
/**
|
||||
* Logs are normalized for the Blade:
|
||||
* [
|
||||
* ['key'=>'inventory','label'=>'<i ...>Adjustments Sync','run_at'=>'14 Oct 2025, 12:30','server_name'=>'maximo01'],
|
||||
* ...
|
||||
* ]
|
||||
*/
|
||||
public array $logs = [];
|
||||
|
||||
private APIStorageRepository $api;
|
||||
private bool $useCache;
|
||||
private int $cacheMinutes;
|
||||
|
||||
public function __construct(APIStorageRepository $api = null, ?bool $useCache = null, int $cacheMinutes = 60)
|
||||
{
|
||||
$this->api = $api ?? new APIStorageRepository();
|
||||
$this->useCache = $useCache ?? (bool)settings()->group('maximo')->get('dashboard_cache', false);
|
||||
$this->cacheMinutes = $cacheMinutes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the data ready fro the view
|
||||
* @return $this
|
||||
* @throws Throwable
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function build(): self
|
||||
{
|
||||
$start = microtime(true);
|
||||
$apiToken = (string)$this->api->getApiToken();
|
||||
$params = [];
|
||||
|
||||
// ------- Returns -------
|
||||
$this->returns = $this->fetch('/api/v1/returns/index', $apiToken, $params, 'returns');
|
||||
$returnsByWeek = $this->groupByIsoWeek($this->returns, 'SRRTRDT', 'SRRUCST');
|
||||
$this->returnsLabels = array_keys($returnsByWeek);
|
||||
$this->returnsValues = array_values($returnsByWeek);
|
||||
$this->totalPOValue = array_sum($this->returnsValues);
|
||||
|
||||
// ------- Inventory -------
|
||||
$this->inventory = $this->fetch('/api/v1/inventory/index', $apiToken, $params, 'inventory');
|
||||
$this->totalInventoryValue = (float)(collect($this->inventory)->sum('SPACOST') ?: 0.0);
|
||||
$inventoryByWeek = $this->groupByIsoWeek($this->inventory, 'SPATRDT', 'SPACOST');
|
||||
$this->inventoryLabels = array_keys($inventoryByWeek);
|
||||
$this->inventoryValues = array_values($inventoryByWeek);
|
||||
|
||||
// ------- Issues -------
|
||||
$this->issues = $this->fetch('/api/v1/issues/index', $apiToken, $params, 'issues');
|
||||
$issuesByWeek = $this->groupByIsoWeek($this->issues, 'SPRTRDT', 'SPRUCST');
|
||||
$this->issuesLabels = array_keys($issuesByWeek);
|
||||
$this->issuesValues = array_values($issuesByWeek);
|
||||
$this->totalIssuesValue = array_sum($this->issuesValues);
|
||||
|
||||
// ------- Stock -------
|
||||
$stock = $this->fetch('/api/v1/stock/index', $apiToken, $params, 'stock');
|
||||
$stockLastMonth = $this->fetch('/api/v1/stock/index/last_month', $apiToken, $params, 'stock_last_month');
|
||||
|
||||
$totalStockNow = (float)(collect($stock)->sum('SPSRCST') ?: 0.0);
|
||||
$this->totalStockValueLastMonth = (float)(collect($stockLastMonth)->sum('SPSRCST') ?: 0.0);
|
||||
$this->totalStockValue = $totalStockNow - $this->totalStockValueLastMonth;
|
||||
|
||||
$combinedStock = array_merge(is_array($stock) ? $stock : [], is_array($stockLastMonth) ? $stockLastMonth : []);
|
||||
$this->stock = $combinedStock;
|
||||
|
||||
$stockByMonth = $this->groupByMonth($combinedStock, 'SPSTRDT', 'SPSRCST');
|
||||
$this->stockLabels = array_keys($stockByMonth);
|
||||
$this->stockValues = array_values($stockByMonth);
|
||||
array_multisort($this->stockLabels, SORT_ASC, $this->stockValues);
|
||||
|
||||
// ------- Top Tens (defensive) -------
|
||||
$this->topTenIssues = $this->fetch('/api/v1/issues/index/top_ten', $apiToken, $params, 'top_ten_issues');
|
||||
$this->topTenInventory = $this->fetch('/api/v1/inventory/index/top_ten', $apiToken, $params,
|
||||
'top_ten_inventory');
|
||||
|
||||
// ------- Logs (with label mapping & formatted timestamps) -------
|
||||
$labelMap = [
|
||||
'INVENTORY' => '<i class="fa-fw fas fa-sliders-h mr-2"></i>Adjustments Sync',
|
||||
'ISSUES' => '<i class="fas fa-exchange-alt mr-2"></i>Item Usage Sync',
|
||||
'RETURNS' => '<i class="fa-fw fas fa-thermometer-full mr-2"></i>PO Analysis Sync',
|
||||
'STOCK' => '<i class="fa-fw fas fa-warehouse mr-2"></i>Movement Sync',
|
||||
];
|
||||
|
||||
$this->logs = collect(['RETURNS', 'STOCK', 'ISSUES', 'INVENTORY'])
|
||||
->map(function (string $type) use ($labelMap) {
|
||||
$raw = (array)$this->api->getRunLog('/api/v1/runlog/last', $type);
|
||||
|
||||
return [
|
||||
'key' => strtolower($type),
|
||||
'label' => $labelMap[$type] ?? e($type),
|
||||
'run_at' => $this->formatDate($raw['run_at'] ?? null),
|
||||
'server_name' => (string)($raw['server_name'] ?? 'N/A'),
|
||||
];
|
||||
})
|
||||
->values()
|
||||
->toArray();
|
||||
|
||||
$this->grandTotal = $this->totalPOValue + $this->totalIssuesValue + $this->totalInventoryValue + $this->totalStockValue;
|
||||
|
||||
if (app()->environment(['local', 'dev', 'qat'])) {
|
||||
$runtime = round(microtime(true) - $start, 3);
|
||||
Log::channel('dashboard')->info(emoji('orange') . "Dashboard ViewModel build() runtime: {$runtime} seconds");
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all the variables as an array.
|
||||
* @return array
|
||||
*/
|
||||
public function toArray(): array
|
||||
{
|
||||
return [
|
||||
'totalPOValue' => $this->totalPOValue,
|
||||
'totalInventoryValue' => $this->totalInventoryValue,
|
||||
'totalIssuesValue' => $this->totalIssuesValue,
|
||||
'totalStockValueLastMonth' => $this->totalStockValueLastMonth,
|
||||
'totalStockValue' => $this->totalStockValue,
|
||||
'grandTotal' => $this->grandTotal,
|
||||
|
||||
'inventory' => $this->inventory,
|
||||
'inventoryLabels' => $this->inventoryLabels,
|
||||
'inventoryValues' => $this->inventoryValues,
|
||||
|
||||
'stock' => $this->stock,
|
||||
'stockLabels' => $this->stockLabels,
|
||||
'stockValues' => $this->stockValues,
|
||||
|
||||
'issues' => $this->issues,
|
||||
'issuesLabels' => $this->issuesLabels,
|
||||
'issuesValues' => $this->issuesValues,
|
||||
|
||||
'returns' => $this->returns,
|
||||
'returnsLabels' => $this->returnsLabels,
|
||||
'returnsValues' => $this->returnsValues,
|
||||
|
||||
'topTenIssues' => $this->topTenIssues,
|
||||
'topTenInventory' => $this->topTenInventory,
|
||||
'logs' => $this->logs,
|
||||
];
|
||||
}
|
||||
|
||||
// ----------------- helpers -----------------
|
||||
|
||||
/**
|
||||
* A combined log formatter
|
||||
* @param string $url
|
||||
* @param string $token
|
||||
* @param array $params
|
||||
* @param string $name
|
||||
* @return array|mixed
|
||||
*/
|
||||
private function fetch(string $url, string $token, array $params, string $name)
|
||||
{
|
||||
// normalize everything to strings for cache key safety
|
||||
$url = (string)$url;
|
||||
$name = (string)$name;
|
||||
$paramsJson = json_encode($params, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
|
||||
|
||||
$key = $name . '_' . md5($url . '|' . ($paramsJson ?? '[]'));
|
||||
|
||||
if (!$this->useCache) {
|
||||
return $this->executeApi($token, $url, $params);
|
||||
}
|
||||
|
||||
return Cache::remember($key, now()->addMinutes($this->cacheMinutes), function () use ($token, $url, $params) {
|
||||
return $this->executeApi($token, $url, $params);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* A common API executor
|
||||
* @param string $token
|
||||
* @param string $url
|
||||
* @param array $params
|
||||
* @return array
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
private function executeApi(string $token, string $url, array $params)
|
||||
{
|
||||
try {
|
||||
$data = APIStorageRepository::execute($token, $url, $params);
|
||||
// Always return an array so downstream code is predictable
|
||||
return is_array($data) ? $data : [];
|
||||
} catch (Throwable $e) {
|
||||
if (app()->environment(['local', 'dev', 'qat'])) {
|
||||
Log::channel('dashboard')->warning("API fetch failed for {$url}: {$e->getMessage()}");
|
||||
}
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/** ISO year-week to avoid cross-year collisions, e.g. '2025-W01'. */
|
||||
private function groupByIsoWeek(array $data, string $dateField, string $valueField): array
|
||||
{
|
||||
return collect($data)
|
||||
->filter(fn($i) => !empty($i[$dateField]) && is_numeric($i[$valueField] ?? null))
|
||||
->groupBy(function ($i) use ($dateField) {
|
||||
$d = Carbon::parse($i[$dateField]);
|
||||
return $d->format('o-\WW');
|
||||
})
|
||||
->map(fn($items) => collect($items)->sum($valueField))
|
||||
->toArray();
|
||||
}
|
||||
|
||||
private function groupByMonth(array $data, string $dateField, string $valueField): array
|
||||
{
|
||||
return collect($data)
|
||||
->filter(fn($i) => !empty($i[$dateField]) && is_numeric($i[$valueField] ?? null))
|
||||
->groupBy(fn($i) => Carbon::parse($i[$dateField])->format('Y-m'))
|
||||
->map(fn($items) => collect($items)->sum($valueField))
|
||||
->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Nice helper for format dates
|
||||
* @param string|null $value
|
||||
* @return string
|
||||
*/
|
||||
private function formatDate(?string $value): string
|
||||
{
|
||||
if (empty($value)) {
|
||||
return 'N/A';
|
||||
}
|
||||
try {
|
||||
return Carbon::parse($value)->format('d M Y, H:i');
|
||||
} catch (Throwable $e) {
|
||||
return 'N/A';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
````
|
||||
|
||||
And the new controller DashBoardController.php
|
||||
|
||||
````
|
||||
<?php
|
||||
|
||||
namespace Modules\Spares\Http\Controllers;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Modules\Spares\ViewModels\DashboardViewModel;
|
||||
|
||||
class DashboardController extends Controller
|
||||
{
|
||||
|
||||
/**
|
||||
* Main View Loader
|
||||
* now uses a view model
|
||||
* @return View
|
||||
*
|
||||
*/
|
||||
public function index(): View
|
||||
{
|
||||
$dashboardViewModel = (new DashboardViewModel())->build();
|
||||
|
||||
if (app()->environment(['local', 'dev', 'qat'])) {
|
||||
$useCache = (bool)settings()->group('maximo')->get('dashboard_cache', false);
|
||||
logger()->channel('dashboard')->info(
|
||||
$useCache
|
||||
? emoji('green') . 'Using Cached Data'
|
||||
: emoji('red') . 'Not Using Cached Data'
|
||||
);
|
||||
}
|
||||
return view('spares::Components.dashboard', $dashboardViewModel->toArray());
|
||||
}
|
||||
}
|
||||
|
||||
````
|
||||
|
||||
This abstracts the data from the view and makes it far more maintainable and extendable.
|
||||
@@ -0,0 +1,54 @@
|
||||
### Developer Websites
|
||||
|
||||
In your how directory you will see a new directory epro, this is the base directory
|
||||
with the code base living in /home/<username>/epro/htdocs/epro2,
|
||||
If one has not been created for your please reach out to ``` mark.gregory@mbpa.com```
|
||||
|
||||
All of your work should take place in this environment using the branches as defined above
|
||||
you can switch your own environment with ``` git checkout ``` complete you work and then merge
|
||||
into the develop branch and switch back to complete testing. its wise also to do a ``` git pull origin develop ```
|
||||
to collect other developer changes, if at this stage you get merge conflicts you must resolve these and push back to
|
||||
develop. and merge back into your own issue, feature or hotfix branch.
|
||||
|
||||
This will eliminate all of the code overwrites suffered to date
|
||||
|
||||
### Defined Hosts
|
||||
192.168.0.81:10020 Mark Gregory
|
||||
192.168.0.81:10021 Tomasz
|
||||
192.168.0.81:10022 Malak
|
||||
192.168.0.81:10023 Brad
|
||||
192.168.0.81:10024 Karl
|
||||
|
||||
When we have defined the firewall exclusions you will be able to substitute 192.168.0.81 for 164.39.2.139 we will expand this list as
|
||||
require when new developers are provisioned.
|
||||
|
||||
The current MPBA testing URL is ``` http://164.39.2.139:10008/admin ```
|
||||
and a backup on ``` http://164.39.2.139:10011/admin```
|
||||
|
||||
|
||||
### Production Deployment Process
|
||||
1. Prior to release day a code freeze takes place
|
||||
2. A new branch is created release/version-date
|
||||
3. UAT servers are switched to this branch and retested
|
||||
4. RELEASE DAY, merge release/version-date into master
|
||||
5. Seek release approval via slack.
|
||||
6. Deploy master and then test release and perform any hotfixes as require
|
||||
7. Push any hot fixes back and merge release/version-date into develop
|
||||
8. Release complete - alert team and then code freeze removed.
|
||||
9. Release issues revert the comment and liaise with team.
|
||||
|
||||
The release should take place by the selected developer and on a rota if possible so all
|
||||
developers are upto date with how to release the system.
|
||||
|
||||
|
||||
### Basic System Information
|
||||
PHP Version: 8.0
|
||||
Node Version: 16.20.2
|
||||
Laravel Version: 8.X
|
||||
|
||||
### Git Branch Structure
|
||||
1. MPBA Server /develop
|
||||
2. MediaDev /stage
|
||||
3. MediaUat /qa
|
||||
4. Production /master
|
||||
|
||||
+183
@@ -0,0 +1,183 @@
|
||||
### System Developer Notes
|
||||
|
||||
This documents how one should develop using the sentinel laravel project.
|
||||
|
||||
#### Git Structure
|
||||
|
||||
The project is tracked using git and has several key branches, we also operate a pull request system and
|
||||
these branches are protected, a pull request must be raised and approved before code can be merged into the
|
||||
relevant develop, stage, release or main branches. ****** Code will not be merged in any other way *****
|
||||
|
||||
#### main
|
||||
|
||||
This is the production branch and is protected from direct commits into this branch except
|
||||
for senior developers, in normal circumstances this branch in never tampered with hot fixes and
|
||||
releases being the only exception. This key branch provides the code for http://mediuk:10008
|
||||
it resides upon the mediuk server in a directory /www/laravel/htdocs.
|
||||
|
||||
#### stage
|
||||
|
||||
This branch is mainly deployed to support user quality testing and reside on http://mediqat:10008
|
||||
NB from time to time other branches may be in effect on this server when progressing towards a software release
|
||||
this structure is normally release/RC-(date)-Vx when (Vx) is is the format of "V" followed by a number to indicate the
|
||||
release candidate version. its location on the mediqat server is /www/laravel/htdocs
|
||||
|
||||
#### develop
|
||||
|
||||
This is the key branch that runs on http://medidev:10008 this is not really to be considered a true development
|
||||
branch as historically this has been use as a pseudo user QAT branch.
|
||||
|
||||
## Important Note
|
||||
|
||||
The medidev server also runs th e Oracle Connectors required to run the Spares (MAXIMO) system and you
|
||||
should ensure that this server is working at all times, this may well be backed up by an additional server
|
||||
running on medidev when time permits.
|
||||
|
||||
There are also other key branches
|
||||
|
||||
#### release
|
||||
|
||||
primarily for release candidates as above.
|
||||
|
||||
#### bugfix
|
||||
|
||||
Branches under this in the format bugfix/details are used to provide fixes for running systems
|
||||
|
||||
#### feature
|
||||
|
||||
This is for new systems, as we use Laravel modules and all code is self contained with within the module
|
||||
follows the format feature/module_name
|
||||
|
||||
#### hotfix
|
||||
|
||||
This branch structure is for hotfixes into the production system ofr emergency updates in the format
|
||||
hotfix/fix_details
|
||||
|
||||
#### support
|
||||
|
||||
This is for minor fixes into all of the Sentinel system.
|
||||
|
||||
#### Commit messages
|
||||
|
||||
An important aspect of commit messages is the ability to search these in good commit messages are vital
|
||||
to prevent developer confusion and code loss when merging.
|
||||
these should follow the format [Module_Name] or [System_Name] and then a concise narrative of what the commit contains.
|
||||
short and non descriptive commit messages will mean that a pull request is rejected with a request to refine the commit
|
||||
message.
|
||||
|
||||
#### Starting a new project
|
||||
|
||||
In amy cases developers have been using the medidev server for pure development and this can cause issues
|
||||
in, medidev should NOT be used for pure development in all cases a separate server should be requested, in the
|
||||
current DB2 database setup there is only one database instance and this can and will cause you issues.
|
||||
|
||||
It's recommended that you develop locally using docker a high performance docker_compose file and a docker directory
|
||||
has been provided, you should install docker, once installed you should reach to to MPBA staff to get a backup of
|
||||
the core databases AAMEDIUK, MPDAT10 and ARCHIVE when using docker you will be using MYSQL as a database server
|
||||
the database backups will be provided and these cna be restored to you local database's
|
||||
|
||||
Always we aware of the fact that the target DB on all Abbot Servers is IBM DB2 and guard code should be produced to
|
||||
ensure that migrations and seeders which are fully support on DB2 , ensure that they only run once as needed
|
||||
and log all of their actions. This aids other developers.
|
||||
|
||||
All permissions and roles should be defined in a seeder so that simple commands can be used to populate the various
|
||||
systems as needed .
|
||||
|
||||
We do use actually Laravel Sail in some instances so you can use
|
||||
|
||||
```
|
||||
docker-compose build --no-cahe
|
||||
or
|
||||
sail build --no-cache
|
||||
|
||||
```
|
||||
|
||||
To download the images and build containers, then once build you can use
|
||||
|
||||
```
|
||||
sail up -d
|
||||
or
|
||||
docker-compose up -d
|
||||
|
||||
```
|
||||
|
||||
This will start the database server, and php webserver using nginx, its recommended that you add
|
||||
entries to your hosts file for the following
|
||||
|
||||
````
|
||||
127.0.0.1 mysql
|
||||
127.0.0.1 mailpit
|
||||
127.0.0.1 redis
|
||||
127.0.0.1 host.docker.internal
|
||||
|
||||
127.0.0.1 medidev.vm
|
||||
127.0.0.1 mediuk.vm
|
||||
127.0.0.1 mediqat.vm
|
||||
127.0.0.1 sonarcube
|
||||
127.0.0.1 nginx
|
||||
|
||||
````
|
||||
|
||||
Your browser will then respond on http://medidev.v, for example. You can use local self certified SSL if you desire and
|
||||
you should reach out to MPBA staff for details.
|
||||
|
||||
### Important Apple Silicon Development
|
||||
|
||||
With later releases of Apple OSX the file system is case sensitive, where the IBM AS400 Apache server / filesystem is
|
||||
not. Therefore its not possible to hold the mysql database files on a case sensitive drive this will cause the
|
||||
server to crash when loading data etc. We use the Linux sub system provided by the container to overcome this
|
||||
and performance issues with docker and shared volumes.
|
||||
|
||||
Beware if you clean your docker system and purge all the volumes you must rebuilt and
|
||||
re-import the database backups.
|
||||
|
||||
One could use a separate case insensitive volume but this will impact docker performance.
|
||||
|
||||
When starting a new project the root branch is develop and you should create your new branch as feature/module name
|
||||
|
||||
### Development Steps
|
||||
|
||||
1. Perform a git pull using the develop branch ```` goit pull origin develop ````
|
||||
2. Create your new feature branch and switch ```` git branch feature/module_name && git checkout feature/module_name````
|
||||
3. Create a suitable env file .env
|
||||
3. Execute docker commands to build system.
|
||||
4. Restore the 3 database backups
|
||||
5. Add the host file entries
|
||||
6. execute ``` docker-compose up -d or sail up -d``` to start the docker system.
|
||||
7. create your new module with ```` php artisan module:make (name)`
|
||||
|
||||
You should now have a running system.
|
||||
|
||||
### Module Naming
|
||||
|
||||
Think about how you name you module and make it as short as possible with NO spaces
|
||||
``` php artisan module:make Spares ``` for example. Changing a module name later is hard and will require a
|
||||
senior developer.
|
||||
|
||||
In previous releases we were using an environment switcher so that .env.dev ate were added to the SCM ( git) this
|
||||
is not now the case and it relies upon the .env file, the .env file SHOULD NOT BE COMMITTED under any circumstances.
|
||||
|
||||
The existing modules provide a great starting point and you should review the code under the Modules directory
|
||||
|
||||
#### FINAL IMPORTANT NOTES
|
||||
|
||||
1. commit and push pull at high frequency
|
||||
|
||||
When a piece has been worked upon commit your changes with a suitable commit message and pull al push any changes, its a
|
||||
good idea to
|
||||
pull and push frequently.
|
||||
|
||||
2. Commit all work at the end of day
|
||||
This is important. ALL WORK should be committed and PUSHED to GIT at the end of the day NO EXCEPTIONS
|
||||
|
||||
3. You are responsible for your own code, if you generate merge conflicts YOU sort them out to ensure no DATA LOSS
|
||||
4. if yo do not commit frequently do not expect your code to be updated to GIT you MUST COMMIT your work
|
||||
|
||||
Do not rely on backups, its your code, own it and ensure its added to the source control system and also ensure you do
|
||||
not over write
|
||||
and core code in the process, if in doubt ASK !!
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
+183
@@ -0,0 +1,183 @@
|
||||
## Docker Usage for Local Development
|
||||
|
||||
This documents hwo to use docker for local development on OSX but can be modified to run under
|
||||
windows, it uses a multi stage build process and the latest alpine images to keep the container sizes to a minimum.
|
||||
it fully supports xdebug and a server version of mysql server. This presents a very fast development
|
||||
experience that does not pollute the host operating system.
|
||||
|
||||
### Why I Use Docker
|
||||
|
||||
Docker plays a crucial role in my deployment strategy. It allows me to containerize my Laravel applications, ensuring
|
||||
consistency across different environments and across multiple services that I need to run a production Laravel app -
|
||||
Queue workers, Schedulers, Nightwatch agent, etc..
|
||||
|
||||
1. Consistent Environments: Every deployment maintains the same configurations, reducing bugs and deployment issues.
|
||||
|
||||
2. Scalability: Docker’s lightweight containers.
|
||||
|
||||
3. The possibility for automated deployment, Integration with Git allows for continuous deployment workflows.
|
||||
|
||||
## Docker Compose
|
||||
|
||||
1. We assume you have docker installed and running
|
||||
2. and also docker-compose installed
|
||||
3. you can also use laravel sail *** the configuration overrides the default sail definitions
|
||||
|
||||
```
|
||||
services:
|
||||
php-fpm:
|
||||
build:
|
||||
context: ./docker/php-fpm
|
||||
dockerfile: Dockerfile
|
||||
container_name: laravel-php
|
||||
working_dir: /var/www/html
|
||||
volumes:
|
||||
# ##########################################################
|
||||
# Source code via bind mount (fast reads on mac:delegated)
|
||||
# This makes docker much faster
|
||||
# ##########################################################
|
||||
- ./:/var/www/html:delegated
|
||||
# ##########################################################
|
||||
# Hot paths on named volumes (fast writes, Linux FS)
|
||||
# This means we have very fast writes as they are not replicated
|
||||
# to the host file system, this means that they must be recreated
|
||||
# when built and also you must run composer install as well
|
||||
# ##########################################################
|
||||
- vendor:/var/www/html/vendor
|
||||
- storage:/var/www/html/storage
|
||||
- cache:/var/www/html/bootstrap/cache
|
||||
environment:
|
||||
PHP_OPCACHE_ENABLE: "1"
|
||||
PHP_OPCACHE_MEMORY: "256"
|
||||
PHP_FPM_MAX_CHILDREN: "16"
|
||||
XDEBUG_MODE: "debug,develop"
|
||||
extra_hosts:
|
||||
- "host.docker.internal:host-gateway"
|
||||
expose:
|
||||
- "9000"
|
||||
- "9003"
|
||||
networks:
|
||||
web:
|
||||
shared:
|
||||
aliases: [ api.medidev.vm, nginx, gateway ]
|
||||
nginx:
|
||||
image: nginx:alpine
|
||||
container_name: laravel-nginx
|
||||
entrypoint: [ "nginx", "-g", "daemon off;" ]
|
||||
depends_on: [ php-fpm ]
|
||||
volumes:
|
||||
- ./:/var/www/html:ro,delegated
|
||||
- ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
|
||||
- ./docker/nginx/logs:/var/log/nginx
|
||||
- ./docker/nginx/ssl:/etc/nginx/ssl:ro
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
networks:
|
||||
web:
|
||||
shared:
|
||||
aliases:
|
||||
- nginx
|
||||
- gateway
|
||||
- api.medidev.vm
|
||||
redis:
|
||||
image: redis:alpine
|
||||
container_name: laravel-redis
|
||||
command: [ "redis-server", "--save", "", "--appendonly", "no", "--loglevel", "warning" ]
|
||||
ports:
|
||||
- "6379:6379"
|
||||
networks: [ web ]
|
||||
mysql:
|
||||
image: mysql:9.0
|
||||
container_name: laravel-mysql
|
||||
command: [ "mysqld", "--log-error-verbosity=2","--mysqlx=0","--defaults-file=/etc/mysql/conf.d/my.cnf" ]
|
||||
logging:
|
||||
driver: "none"
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD: "987400Kmh"
|
||||
MYSQL_DATABASE: "AAMEDIUK"
|
||||
MYSQL_LOG_CONSOLE: "false"
|
||||
#>/dev/null 2>&1
|
||||
entrypoint: [ "sh","-lc","exec mysqld --datadir=/var/lib/mysql --user=mysql --mysqlx=0 --log-error-verbosity=2 " ]
|
||||
ports:
|
||||
- "3306:3306"
|
||||
volumes:
|
||||
- dbdata_medidev:/var/lib/mysql/
|
||||
# ##########################################################
|
||||
# Optional custom config / init files:
|
||||
# ##########################################################
|
||||
- ./docker/mysql/conf.d:/etc/mysql/conf.d:ro
|
||||
healthcheck:
|
||||
test: [ "CMD", "mysqladmin", "ping", "-p987400Kmh" ]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
networks: [ web ]
|
||||
queue:
|
||||
build:
|
||||
context: ./docker/php-fpm
|
||||
dockerfile: Dockerfile
|
||||
container_name: laravel-queue
|
||||
command: [ "/usr/bin/supervisord", "-c", "/etc/supervisord.conf" ]
|
||||
working_dir: /var/www/html
|
||||
volumes:
|
||||
- ./:/var/www/html:delegated
|
||||
- vendor:/var/www/html/vendor
|
||||
- storage:/var/www/html/storage
|
||||
- cache:/var/www/html/bootstrap/cache
|
||||
depends_on:
|
||||
- redis
|
||||
- mysql
|
||||
networks: [ web ]
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
web:
|
||||
driver: bridge
|
||||
shared:
|
||||
external: true
|
||||
name: shared-frontend
|
||||
volumes:
|
||||
vendor:
|
||||
storage:
|
||||
cache:
|
||||
dbdata_medidev:
|
||||
|
||||
```
|
||||
|
||||
You need to create a docker directory from the project root
|
||||
and add the following files to this directory once downloaded.
|
||||
|
||||
[Download docker.zip](assets/docker.zip){: download}
|
||||
|
||||
you will also need to contact the author for a copy of the mysql databases;
|
||||
|
||||
Once all the files are in place you can execute
|
||||
|
||||
```
|
||||
sail up --build
|
||||
or
|
||||
docker-compose build --no-cache
|
||||
```
|
||||
|
||||
Fix invalid cache path after rebuild as were using names paths
|
||||
|
||||
You can also use this command
|
||||
|
||||
````
|
||||
docker exec -it laravel-php bash -lc \
|
||||
"mkdir -p bootstrap/cache storage/framework/{cache,sessions,views} \
|
||||
&& chown -R www-data:www-data bootstrap storage \
|
||||
&& chmod -R ug+rwX bootstrap storage"
|
||||
`````
|
||||
|
||||
NB also run composer install
|
||||
|
||||
````
|
||||
docker network create shared-frontend
|
||||
````
|
||||
|
||||
This makes the necessary cache dirs etc
|
||||
|
||||
````
|
||||
mkdir -p bootstrap/cache storage/framework/{cache,sessions,views,testing,cache/data} && chown -R www-data:www-data bootstrap storage
|
||||
````
|
||||
@@ -0,0 +1,96 @@
|
||||
# Laravel Environment Switcher
|
||||
|
||||
### Introduction
|
||||
|
||||
*** THIS HAS BEEN DEPRECATED AND IS NO LONGER USED
|
||||
|
||||
The basic operation of the environment switcher is to permit the use of different environment files
|
||||
based upon a variable that is added to the web servers configuration to control which one is loaded.
|
||||
|
||||
when you make changes to the environment files you need to execute
|
||||
|
||||
``php artisan config:clear``
|
||||
|
||||
and
|
||||
``php artisan config:cache``
|
||||
|
||||
The various env files are committed to source control with the exception of the .local environment file
|
||||
this file is used for local development and is developer specific
|
||||
|
||||
1. .dev is used on MEDIDEV
|
||||
2. .qat is used on MEDIQAT
|
||||
3. .prod is used on MEDIUK
|
||||
|
||||
.local is reserved for local development environments
|
||||
|
||||
The files in use are
|
||||
``` /app/Bootstrap/DetectEnviroment.php``` and ``` /app/Bootstrap/LoadEnvironment.php```
|
||||
These are added to ``` app/Http/Kernel.php```
|
||||
|
||||
```
|
||||
protected $bootstrappers = [
|
||||
\App\Bootstrap\DetectEnvironment::class,
|
||||
\App\Bootstrap\LoadEnvironment::class,
|
||||
\Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables::class,
|
||||
\Illuminate\Foundation\Bootstrap\LoadConfiguration::class,
|
||||
\Illuminate\Foundation\Bootstrap\HandleExceptions::class,
|
||||
\Illuminate\Foundation\Bootstrap\RegisterFacades::class,
|
||||
\Illuminate\Foundation\Bootstrap\SetRequestForConsole::class,
|
||||
\Illuminate\Foundation\Bootstrap\RegisterProviders::class,
|
||||
\Illuminate\Foundation\Bootstrap\BootProviders::class,
|
||||
];
|
||||
|
||||
```
|
||||
|
||||
and for console commands These are added to ``` app/Helpers/Kernel.php```
|
||||
|
||||
````
|
||||
protected $bootstrappers = [
|
||||
\App\Bootstrap\DetectEnvironment::class,
|
||||
\App\Bootstrap\LoadEnvironment::class,
|
||||
//\Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables::class,
|
||||
\Illuminate\Foundation\Bootstrap\LoadConfiguration::class,
|
||||
\Illuminate\Foundation\Bootstrap\HandleExceptions::class,
|
||||
\Illuminate\Foundation\Bootstrap\RegisterFacades::class,
|
||||
\Illuminate\Foundation\Bootstrap\SetRequestForConsole::class,
|
||||
\Illuminate\Foundation\Bootstrap\RegisterProviders::class,
|
||||
\Illuminate\Foundation\Bootstrap\BootProviders::class,
|
||||
];
|
||||
````
|
||||
|
||||
This permits the console to use the relevant env file also
|
||||
|
||||
### Apache Web Server Configuration
|
||||
|
||||
For the Apache Web Server a line is added to the configuration file in
|
||||
`` /www/laravel/conf/httpd.conf``
|
||||
This line is `` SetEnv APPLICATION_ENV dev`` for example on MEDIDEV and the corresponding env file
|
||||
created .env.dev
|
||||
|
||||
Apache then needs to be restarted for the new environment file to be activated.
|
||||
|
||||
### nginx configuration
|
||||
|
||||
The config file for valet etc is changed to add these variables
|
||||
|
||||
````
|
||||
location ~ [^/]\.php(/|$) {
|
||||
fastcgi_split_path_info ^(.+\.php)(/.+)$;
|
||||
fastcgi_pass "unix:/Users/markgregory/.config/valet/valet.sock";
|
||||
fastcgi_index "/Users/markgregory/.composer/vendor/laravel/valet/server.php";
|
||||
include fastcgi_params;
|
||||
fastcgi_param APPLICATION_ENV "local";
|
||||
fastcgi_param APP_ENV "local";
|
||||
fastcgi_param SCRIPT_FILENAME "/Users/markgregory/.composer/vendor/laravel/valet/server.php";
|
||||
fastcgi_param PATH_INFO $fastcgi_path_info;
|
||||
}
|
||||
````
|
||||
|
||||
Again nginx should be restarted with nginx -s reload or for valet ``` valet restart ```
|
||||
|
||||
### Debugging
|
||||
|
||||
When setting this up if the variables are not added you will receive a warning and the app will not
|
||||
start, for debug only you can add normal entries to .env but do not commit these to the SVM .env is only committed
|
||||
to show it's not in use.
|
||||
|
||||
Executable
+98
@@ -0,0 +1,98 @@
|
||||
### GitHub Branching Name Best Practices
|
||||
|
||||
On GitHub, branching is a crucial component of collaborative software development. In addition to keeping your project
|
||||
organized, using consistent and unambiguous branch naming conventions makes it easier for team members to quickly
|
||||
comprehend each branch's purpose. Some best practices for naming branches in your GitHub projects are listed below.
|
||||
|
||||
1. Use Prefixes to Indicate Purpose
|
||||
Prefixing branch names based on their purpose helps categorize and identify them quickly. Here are some common
|
||||
prefixes:
|
||||
|
||||
feature/: For new features or functionalities.
|
||||
|
||||
bugfix/: For fixing bugs in the code.
|
||||
|
||||
hotfix/: For urgent patches, usually applied to production.
|
||||
|
||||
design/: For user interface or user experience updates.
|
||||
|
||||
refactor/: For improving code structure without changing functionality.
|
||||
|
||||
test/: For writing or improving automated tests.
|
||||
|
||||
doc/: For documentation updates.
|
||||
|
||||
### Example Prefix Usage
|
||||
|
||||
feature/user-authentication
|
||||
|
||||
bugfix/fix-login-error
|
||||
|
||||
hotfix/urgent-patch-crash
|
||||
|
||||
design/update-navbar
|
||||
|
||||
refactor/remove-unused-code
|
||||
|
||||
test/add-unit-tests
|
||||
|
||||
doc/update-readme
|
||||
|
||||
2. Keep Names Short and Descriptive
|
||||
Branch names should be concise yet informative. A good branch name briefly describes what it is for without being
|
||||
overly long or vague. Here are some tips:
|
||||
|
||||
Use hyphens (-) to separate words for better readability.
|
||||
|
||||
Avoid generic terms like update, changes, or stuff.
|
||||
|
||||
Focus on the primary task or issue the branch addresses.
|
||||
|
||||
### Examples of Clear Branch Names
|
||||
|
||||
'''
|
||||
Feature Branches
|
||||
feature/add-user-profile
|
||||
feature/implement-chat-notifications
|
||||
Bug Fixes
|
||||
bugfix/correct-date-display
|
||||
bugfix/fix-404-error
|
||||
Design Updates
|
||||
design/improve-dashboard-ui
|
||||
design/revise-mobile-layout
|
||||
Refactoring
|
||||
refactor/optimize-database-queries
|
||||
refactor/simplify-api-routes
|
||||
Hotfixes
|
||||
hotfix/security-patch
|
||||
hotfix/fix-login-issue
|
||||
Documentation
|
||||
doc/add-api-instructions
|
||||
doc/update-contributor-guidelines
|
||||
'''
|
||||
|
||||
3. Incorporate Ticket Numbers or Identifiers
|
||||
For teams using project management tools like Jira or Trello, include the ticket number or issue ID in the branch
|
||||
name. This links the branch to its corresponding task, making it easier to track progress.
|
||||
|
||||
## Examples with Ticket Numbers
|
||||
|
||||
feature/JIRA-1234-add-login
|
||||
|
||||
bugfix/TICKET-567-resolve-crash
|
||||
|
||||
hotfix/ISSUE-890-fix-api
|
||||
|
||||
4. Collaborate on a Branch Naming Strategy
|
||||
Every team is different, so it’s crucial to agree on a branching strategy that works for everyone. Document the
|
||||
naming conventions in your project’s contribution guidelines or README file so that new contributors can easily
|
||||
follow them.
|
||||
|
||||
### Benefits of Consistent Branch Naming
|
||||
|
||||
Improved Collaboration: Team members can quickly understand the purpose of a branch without needing extra context.
|
||||
|
||||
Easier Navigation: Searching for specific branches becomes straightforward.
|
||||
|
||||
Better Automation: Many CI/CD tools can leverage structured branch names for workflows (e.g., deploying hotfix/ branches
|
||||
automatically to production).
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
# MPBA Helpdesk
|
||||
|
||||
The MPBA Helpdesk is available at [Helpdesk](https://helpdesk.mpba.dev).
|
||||
|
||||
You can create tickets here once you have a valid account and use the ticket numbers in your branches as required.
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
# Welcome to Sentinel Docs
|
||||
|
||||
## Sentinel EPRO
|
||||
|
||||
This document details the Sentinel development process that will prevent collisions and code overwrites
|
||||
it's a living document and will be updated frequently and as the process is refined.
|
||||
|
||||
The MPBA Helpdesk is available at [Helpdesk](https://helpdesk.mpba.dev).
|
||||
|
||||
This documentation used mark down files, if you wish to read more please checkout
|
||||
out [Mark Down Guild](https://www.markdownguide.org/).
|
||||
|
||||
One important aspect of this is that in an ideal world one would develop on a local system with a suitable
|
||||
ODBC driver, if this is not available then we have made a development environment for each developer
|
||||
This system resides on the MPBA AS400 server, the details of this developer system is detailed below.
|
||||
|
||||
This may be in some cases informing developers of how 'git' does its work its not a definitive
|
||||
guide to git and anyone who is unsure should reach out so that any issues can be quickly dealt with.
|
||||
|
||||
On important aspect of this system is to use a proper git branch structure no longer should developers be working on
|
||||
the master branch, the master branch is reserved for production servers only.
|
||||
Developers should always create a branch off develop which will contain the latest developer codebase.
|
||||
|
||||
Git is a DVCS we are all used to the older file based SCM's like subversion and PVCS a DVCS only records the
|
||||
changes. its important to understand that in every case its better to go git pull and push
|
||||
frequently.
|
||||
|
||||
Also do a ``` git fetch ``` this will download new branches for you
|
||||
|
||||
Please do ``` git pull ``` and ``` git push ``` as frequently as possible.
|
||||
|
||||
Also another useful command is ``` git status``` the output form this speaks for itself as does ``` git log ```.
|
||||
|
||||
### Commit Messages
|
||||
|
||||
Please make you commit messages useful for developers reason being we can search for a commit message
|
||||
and isolate changed code quickly
|
||||
so "Module Debug" is not helpful but "Module debug - corrected issie with service provider and updated .gitignore" is
|
||||
far more useful
|
||||
|
||||
### Production Branches
|
||||
|
||||
Production servers will only ever use master or main these are considered to be protected
|
||||
branches there will not be used to make live edits under any circumstances.
|
||||
the only exception is a Priority One emergency with a system down and in operable,
|
||||
even in this case the developer must ensure that develop is also upto date.
|
||||
|
||||
In the case of such an emergency the assigned developer should create a new branch hotfix/issue-name and
|
||||
perform the fix task in there and merge back into master and then master though to develop.
|
||||
|
||||
```` git branch hotfix\error-500-sparos ````
|
||||
|
||||
then
|
||||
|
||||
```` git checkout hotfix\error-500-sparos ````
|
||||
|
||||
perform your fixes and verify they are ok push all changes to gitlab and
|
||||
|
||||
```` git checkout master ````
|
||||
|
||||
then
|
||||
|
||||
```` git merge hotfix\error-500-sparos ````
|
||||
then
|
||||
|
||||
```` git push origin master ````
|
||||
|
||||
then verify fix worked ok finally
|
||||
|
||||
```` git checkout develop ````
|
||||
then
|
||||
|
||||
```` git merge master &&& git push origin develop ````
|
||||
|
||||
All of your fixes are in place and merged back.
|
||||
|
||||
### Branch Model
|
||||
|
||||
The following branches are permitted
|
||||
|
||||
* 'master' or 'main' for production servers only
|
||||
* 'develop' main branch for development environments
|
||||
* 'qat' for UAT servers
|
||||
* 'stage' pre production servers *** if used
|
||||
* 'issues' for code fixes
|
||||
* 'feature' for major improvements and new systems
|
||||
* 'hotfix' for emergency fixes
|
||||
* 'archive' this is for copies of various branches for convenience
|
||||
* 'release' for candidate releases that are production ready and may be used on a pre-prod server
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
### Indexing DB2 for speed
|
||||
|
||||
This area details why you should add indexes to key fields to increase DB2 lookup performance
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
### Developer Knowledge Base
|
||||
|
||||
### Laravel Eloquent
|
||||
|
||||
to debug an SQL Query you can use
|
||||
|
||||
```
|
||||
|
||||
$rawSql = vsprintf(str_replace(['?'], ['\'%s\''], $query->toSql()), $query->getBindings());
|
||||
|
||||
```
|
||||
|
||||
This will hold the rea; SQL call in $rawSQL
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
### Sentinel Migrations
|
||||
|
||||
This contains important information regarding migrations.
|
||||
|
||||
### Migration Errors
|
||||
|
||||
NB these migrations should only been run on MEDIDEV
|
||||
|
||||
This is an important step, the current DB_USER on mediuk is not as powerful as
|
||||
a user with QSECOFR, migrations will fail with a resource 904 error, to overcome this
|
||||
change the active env file DB_USERNAME and DB_PASSWORD and re-run the migration.
|
||||
|
||||
When running migrations on production always for this with care
|
||||
|
||||
To run a migration
|
||||
|
||||
```
|
||||
php artisan module:migrate Settings
|
||||
|
||||
```
|
||||
|
||||
to revert the migration
|
||||
|
||||
```
|
||||
php artisan module:migrate-rollback Settings
|
||||
|
||||
```
|
||||
|
||||
### Writing Migrations
|
||||
|
||||
In line with general Laravel Migration creation and Taylor Ortwel we do not create a down action to prevent tables
|
||||
being erased in error. Also we should check if a table exists and example ois below.
|
||||
|
||||
```
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
if (!Schema::hasTable(Priority::TABLE)) {
|
||||
Schema::create(Priority::TABLE, function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->integer('is_default')->default(0);
|
||||
$table->integer('is_protected')->default(0);
|
||||
$table->integer('sort_order')->default(0);
|
||||
$table->string('title')->nullable();
|
||||
$table->string('slug')->nullable();
|
||||
$table->text('description')->nullable();
|
||||
$table->char('uuid', 36)->nullable();
|
||||
$table->timestamp('deleted_at')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
One should never run migrations on production, any tables are to be created using IBM Utilities.
|
||||
*** and Never run the commands php artisan migrate, php artisan migrate-rollback or php artisan db:wipe.
|
||||
|
||||
|
||||
|
||||
+147
@@ -0,0 +1,147 @@
|
||||
---
|
||||
title: "New page"
|
||||
language: "en"
|
||||
previous: "index.html"
|
||||
---
|
||||
|
||||
## Sentinel EPRO
|
||||
|
||||
### System Information
|
||||
PHP Version: 8.0
|
||||
Node Version: 16.20.2
|
||||
Laravel Version: 8.X
|
||||
|
||||
# Main Development AS400
|
||||
Development URL: http://164.39.2.139:10011/
|
||||
Server Path: /www/ADC8/htdocs/epro2/
|
||||
branch: develop
|
||||
|
||||
# Custom Development AS400 ( Malak's Work )
|
||||
Development URL: http://164.39.2.139:10008/login
|
||||
Server Path: /www/epro/htdocs/epro2
|
||||
branch: master
|
||||
|
||||
### Git Branch Structure
|
||||
1. MPBA Server /develop
|
||||
2. MediaDev /stage
|
||||
3. MediaUat /qa
|
||||
4. Production /master
|
||||
|
||||
Other possible branch names are:
|
||||
production
|
||||
main
|
||||
staging
|
||||
*** it is to developers to adopt these as needed.
|
||||
|
||||
|
||||
The Application does not currently use redis nor memcached and has no reliance upon these caching
|
||||
servers.
|
||||
|
||||
### Important files
|
||||
There are few important files that change from host to host, these are contained in the provision directory
|
||||
and should be kept upto date with their respective target hosts
|
||||
the Keepass file will contain urls and credentials for the various hosts systems.
|
||||
|
||||
|
||||
### Local Development
|
||||
|
||||
There are several alternatives when it comes to local development of web application
|
||||
development, One can use vagrant, Laravel Valet or MAMP LAMP etc,one of the best development systems is
|
||||
docker, this builds containers for the various components and is available
|
||||
on all major platforms.
|
||||
|
||||
The first thing to do on your development machine is to install docker and docker desktop along with support for
|
||||
docker composer.
|
||||
|
||||
#### Image Storage
|
||||
When running docker the php artisan storage:link does not resolve to the correct path
|
||||
to overcome this issue do a docker ps and find the container ID
|
||||
```
|
||||
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
|
||||
1dd8f887cebb sail-8.1/app "start-container" 19 hours ago Up 15 minutes 0.0.0.0:80->80/tcp, :::80->80/tcp, 0.0.0.0:5173->5173/tcp, :::5173->5173/tcp, 8000/tcp epro2-sentinal-1
|
||||
4d60252a7927 mailhog/mailhog "MailHog" 3 days ago Up 15 minutes 0.0.0.0:1025->1025/tcp, :::1025->1025/tcp, 0.0.0.0:8025->8025/tcp, :::8025->8025/tcp mailhog
|
||||
```
|
||||
these execute
|
||||
```
|
||||
docker exec -it 1dd8f887cebb /bin/sh
|
||||
```
|
||||
navigate to public and remove the storage link, then execute
|
||||
``` ln -s ../storage/app/public storage ```
|
||||
|
||||
this will link the storage folder correctly
|
||||
and do not run storage link as this wil use the UPLOAD_DIR flag from the .env file that will contain the an incorrect
|
||||
path
|
||||
|
||||
On AS400 hosts this is normally /tmp/quotations and storage link does work properly
|
||||
|
||||
#### SSL Self Signed Certificates
|
||||
to import your local self signed certs into chrome got to settings then setting privacy and security then
|
||||
Authorities click import and navigate to the .valet directory then CA then import .valet/CA/LaravelValetCASelfSigned.pem
|
||||
accepting all the options and then restart chrome, you local site is now using SSL.
|
||||
|
||||
|
||||
#### Introduction
|
||||
|
||||
Laravel Sail is a light-weight command-line interface for interacting with Laravel's default Docker
|
||||
development environment. Sail provides a great starting point for building a Laravel application using PHP, MySQL, and Redis without requiring prior Docker experience.
|
||||
You can also use laravel valet ( see below)
|
||||
|
||||
At its heart, Sail is the docker-compose.yml file and the sail script that is stored at the root of your project. The sail script provides a CLI with convenient methods for interacting with the Docker containers defined by the docker-compose.yml file.
|
||||
|
||||
Laravel Sail is supported on macOS, Linux, and Windows (via WSL2).
|
||||
|
||||
#### Initial Installation
|
||||
Laravel Sail is automatically installed with all new Laravel applications so you may start using it
|
||||
immediately. To learn how to create a new Laravel application, please consult Laravel's installation
|
||||
documentation for your operating system.
|
||||
During installation, you will be asked to choose which Sail supported services your application will be
|
||||
interacting with.
|
||||
|
||||
To install Laravel sail use ``` composer require --dev laravel\sail```
|
||||
|
||||
|
||||
The documentation is available at https://laravel.com/docs/10.x/sail
|
||||
|
||||
#### Docker Notes
|
||||
|
||||
Some important docker commands are as follows:
|
||||
|
||||
NB when running these commands ensure that you have no running instances for example executing sail down.
|
||||
|
||||
``` docker system prune -a```
|
||||
This command will remove the build containers and any downloaded containers, this is useful for saving disk space
|
||||
|
||||
``` docker volume rm $(docker volume ls -q) ```
|
||||
Used to delete any of the volumes created, this is where the database is stored etc again great for cleaning up
|
||||
and saving disk space.
|
||||
|
||||
``` sail build --no-cache ```
|
||||
this is perfect for rebuilding your containers
|
||||
|
||||
### Linux ODBC Installs
|
||||
The ODBC drivers for linux can present a challenge and its important to
|
||||
install IBM Client Access for Linux, this includes the CLI drivers for many linux distributions
|
||||
The database.php in the config directory is the place to set the
|
||||
drivers and the DSN one also add a specific config file if needed.
|
||||
|
||||
We have set credentials in the env file to suite, typically to aid switching between databases
|
||||
we recommend using the same db credentials as 192.168.0.81 ( MPBA AS400 Host)
|
||||
|
||||
|
||||
'odbc_local' => [
|
||||
'driver' => 'odbc',
|
||||
'odbc_driver' => '/opt/ibm/iaccess/lib64/libcwbodbc.so',
|
||||
'host' => env('DB_HOST', 'localhost'),
|
||||
'database' => env('DB_DATABASE'),
|
||||
'username' => env('DB_USERNAME'),
|
||||
'password' => env('DB_PASSWORD'),
|
||||
'dsn' => 'Driver={IBM i Access ODBC Driver 64-bit};System=192.168.0.81;AlwaysCalculateResultLength=1;CCSID=1208;NAM=1;DBQ=,'.env('DBQ'),
|
||||
'options' => [
|
||||
PDO::ATTR_CASE => PDO::CASE_NATURAL, // PDO::CASE_UPPER PDO::CASE_LOWER PDO::CASE_NATURAL
|
||||
//PDO::ATTR_AUTOCOMMIT => false
|
||||
],WARN - #c.j.p.b.d.BladeDebugPathMapper
|
||||
|
||||
DB2 on docker is presenting more of a challenge as none of the current
|
||||
ODBC drivers see to work as expected.
|
||||
|
||||
#### Laravel Valet Usage Guidelines
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
# AS400 Queue Operation
|
||||
|
||||
### Overview
|
||||
|
||||
There is a core issue with Laravel and IBM Db2 drivers in the current version of sentinel,.
|
||||
this means that queues will not run properly that have any large payloads teh table struct is not
|
||||
suitable and jbs will simply fail to load into the table called QUEUE.
|
||||
|
||||
### The solution
|
||||
|
||||
The easiest way to fix this issue is not to use DB2 for queue operation but switch to REDIS
|
||||
the REDIS sever has been installed on MEDIDEV and can now be used to Caching, sessions and also more importantly
|
||||
QUEUES.
|
||||
|
||||
The entries in the env file set these to use redis as opposed to database, file system or array.
|
||||
|
||||
One further issue when using Maximo with cron is that cron has no concept of the Oracle Environment Variables
|
||||
we are devising a solution for this issue.
|
||||
|
||||
#### current cron entries for MEDIDEV
|
||||
|
||||
```
|
||||
SHELL=/QOpenSys/pkgs/bin/bash
|
||||
PATH=/QOpenSys/pkgs/bin:/QOpenSys/usr/sbin:/QOpenSys/usr/bin
|
||||
MAILTO=qsecofr
|
||||
APPLICATION_ENV=dev
|
||||
|
||||
# For details see man 4 crontabs
|
||||
|
||||
# Example of job definition:
|
||||
|
||||
# .---------------- minute (0 - 59)
|
||||
|
||||
# | .------------- hour (0 - 23)
|
||||
|
||||
# | | .---------- day of month (1 - 31)
|
||||
|
||||
# | | | .------- month (1 - 12) OR jan,feb,mar,apr ...
|
||||
|
||||
# | | | | .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
|
||||
|
||||
# | | | | |
|
||||
|
||||
# * * * * * user-name command to be executed
|
||||
|
||||
* * * * * pricedx1 php /www/laravel/htdocs/artisan schedule:run
|
||||
*/1 * * * * pricedx1 php /www/laravel/htdocs/artisan queue:work --max-time=30
|
||||
```
|
||||
|
||||
This means that the cron job runs every minute and then for a maximum of 30 seconds, if there are no jobs to process
|
||||
then
|
||||
the queue:work command will quite.
|
||||
|
||||
in most cases a maximum of 3 crn jobs will run on the AS400 1, for the schedule and then two for the queue:work command
|
||||
if the --max-time parameter is removed then the queue:work command does not quit and you end up with lots of cron jobs
|
||||
running
|
||||
which is not ideal as this will kill system resources and slow the AS400 server.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
### Redis Server
|
||||
|
||||
to start the redis server on AS400 execute
|
||||
|
||||
```
|
||||
redis-server --daemonize yes
|
||||
```
|
||||
|
||||
you can then use
|
||||
|
||||
redis-cli ping
|
||||
|
||||
to see if it;s working
|
||||
|
||||
+665
@@ -0,0 +1,665 @@
|
||||
# Task Scheduling
|
||||
|
||||
- [Introduction](#introduction)
|
||||
- [Defining Schedules](#defining-schedules)
|
||||
- [Scheduling Artisan Commands](#scheduling-artisan-commands)
|
||||
- [Scheduling Queued Jobs](#scheduling-queued-jobs)
|
||||
- [Scheduling Shell Commands](#scheduling-shell-commands)
|
||||
- [Schedule Frequency Options](#schedule-frequency-options)
|
||||
- [Timezones](#timezones)
|
||||
- [Preventing Task Overlaps](#preventing-task-overlaps)
|
||||
- [Running Tasks on One Server](#running-tasks-on-one-server)
|
||||
- [Background Tasks](#background-tasks)
|
||||
- [Maintenance Mode](#maintenance-mode)
|
||||
- [Schedule Groups](#schedule-groups)
|
||||
- [Running the Scheduler](#running-the-scheduler)
|
||||
- [Sub-Minute Scheduled Tasks](#sub-minute-scheduled-tasks)
|
||||
- [Running the Scheduler Locally](#running-the-scheduler-locally)
|
||||
- [Task Output](#task-output)
|
||||
- [Task Hooks](#task-hooks)
|
||||
- [Events](#events)
|
||||
|
||||
<a name="introduction"></a>
|
||||
|
||||
## Introduction
|
||||
|
||||
In the past, you may have written a cron configuration entry for each task you needed to schedule on your server.
|
||||
However, this can quickly become a pain because your task schedule is no longer in source control and you must SSH into
|
||||
your server to view your existing cron entries or add additional entries.
|
||||
|
||||
Laravel's command scheduler offers a fresh approach to managing scheduled tasks on your server. The scheduler allows you
|
||||
to fluently and expressively define your command schedule within your Laravel application itself. When using the
|
||||
scheduler, only a single cron entry is needed on your server. Your task schedule is typically defined in your
|
||||
application's `routes/console.php` file.
|
||||
|
||||
<a name="defining-schedules"></a>
|
||||
|
||||
## Defining Schedules
|
||||
|
||||
You may define all of your scheduled tasks in your application's `routes/console.php` file. To get started, let's take a
|
||||
look at an example. In this example, we will schedule a closure to be called every day at midnight. Within the closure
|
||||
we will execute a database query to clear a table:
|
||||
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schedule;
|
||||
|
||||
Schedule::call(function () {
|
||||
DB::table('recent_users')->delete();
|
||||
})->daily();
|
||||
|
||||
In addition to scheduling using closures, you may also
|
||||
schedule [invokable objects](https://secure.php.net/manual/en/language.oop5.magic.php#object.invoke). Invokable objects
|
||||
are simple PHP classes that contain an `__invoke` method:
|
||||
|
||||
Schedule::call(new DeleteRecentUsers)->daily();
|
||||
|
||||
If you prefer to reserve your `routes/console.php` file for command definitions only, you may use the `withSchedule`
|
||||
method in your application's `bootstrap/app.php` file to define your scheduled tasks. This method accepts a closure that
|
||||
receives an instance of the scheduler:
|
||||
|
||||
use Illuminate\Console\Scheduling\Schedule;
|
||||
|
||||
->withSchedule(function (Schedule $schedule) {
|
||||
$schedule->call(new DeleteRecentUsers)->daily();
|
||||
})
|
||||
|
||||
If you would like to view an overview of your scheduled tasks and the next time they are scheduled to run, you may use
|
||||
the `schedule:list` Artisan command:
|
||||
|
||||
```bash
|
||||
php artisan schedule:list
|
||||
```
|
||||
|
||||
<a name="scheduling-artisan-commands"></a>
|
||||
|
||||
### Scheduling Artisan Commands
|
||||
|
||||
In addition to scheduling closures, you may also schedule [Artisan commands](/docs/{{version}}/artisan) and system
|
||||
commands. For example, you may use the `command` method to schedule an Artisan command using either the command's name
|
||||
or class.
|
||||
|
||||
When scheduling Artisan commands using the command's class name, you may pass an array of additional command-line
|
||||
arguments that should be provided to the command when it is invoked:
|
||||
|
||||
use App\Console\Commands\SendEmailsCommand;
|
||||
use Illuminate\Support\Facades\Schedule;
|
||||
|
||||
Schedule::command('emails:send Taylor --force')->daily();
|
||||
|
||||
Schedule::command(SendEmailsCommand::class, ['Taylor', '--force'])->daily();
|
||||
|
||||
<a name="scheduling-artisan-closure-commands"></a>
|
||||
|
||||
#### Scheduling Artisan Closure Commands
|
||||
|
||||
If you want to schedule an Artisan command defined by a closure, you may chain the scheduling related methods after the
|
||||
command's definition:
|
||||
|
||||
Artisan::command('delete:recent-users', function () {
|
||||
DB::table('recent_users')->delete();
|
||||
})->purpose('Delete recent users')->daily();
|
||||
|
||||
If you need to pass arguments to the closure command, you may provide them to the `schedule` method:
|
||||
|
||||
Artisan::command('emails:send {user} {--force}', function ($user) {
|
||||
// ...
|
||||
})->purpose('Send emails to the specified user')->schedule(['Taylor', '--force'])->daily();
|
||||
|
||||
<a name="scheduling-queued-jobs"></a>
|
||||
|
||||
### Scheduling Queued Jobs
|
||||
|
||||
The `job` method may be used to schedule a [queued job](/docs/{{version}}/queues). This method provides a convenient way
|
||||
to schedule queued jobs without using the `call` method to define closures to queue the job:
|
||||
|
||||
use App\Jobs\Heartbeat;
|
||||
use Illuminate\Support\Facades\Schedule;
|
||||
|
||||
Schedule::job(new Heartbeat)->everyFiveMinutes();
|
||||
|
||||
Optional second and third arguments may be provided to the `job` method which specifies the queue name and queue
|
||||
connection that should be used to queue the job:
|
||||
|
||||
use App\Jobs\Heartbeat;
|
||||
use Illuminate\Support\Facades\Schedule;
|
||||
|
||||
// Dispatch the job to the "heartbeats" queue on the "sqs" connection...
|
||||
Schedule::job(new Heartbeat, 'heartbeats', 'sqs')->everyFiveMinutes();
|
||||
|
||||
<a name="scheduling-shell-commands"></a>
|
||||
|
||||
### Scheduling Shell Commands
|
||||
|
||||
The `exec` method may be used to issue a command to the operating system:
|
||||
|
||||
use Illuminate\Support\Facades\Schedule;
|
||||
|
||||
Schedule::exec('node /home/forge/script.js')->daily();
|
||||
|
||||
<a name="schedule-frequency-options"></a>
|
||||
|
||||
### Schedule Frequency Options
|
||||
|
||||
We've already seen a few examples of how you may configure a task to run at specified intervals. However, there are many
|
||||
more task schedule frequencies that you may assign to a task:
|
||||
|
||||
```
|
||||
|------------------------------------|----------------------------------------------------------|
|
||||
| Method | Description |
|
||||
|------------------------------------|----------------------------------------------------------|
|
||||
| `->cron('* * * * *');` | Run the task on a custom cron schedule. |
|
||||
| `->everySecond();` | Run the task every second. |
|
||||
| `->everyTwoSeconds();` | Run the task every two seconds. |
|
||||
| `->everyFiveSeconds();` | Run the task every five seconds. |
|
||||
| `->everyTenSeconds();` | Run the task every ten seconds. |
|
||||
| `->everyFifteenSeconds();` | Run the task every fifteen seconds. |
|
||||
| `->everyTwentySeconds();` | Run the task every twenty seconds. |
|
||||
| `->everyThirtySeconds();` | Run the task every thirty seconds. |
|
||||
| `->everyMinute();` | Run the task every minute. |
|
||||
| `->everyTwoMinutes();` | Run the task every two minutes. |
|
||||
| `->everyThreeMinutes();` | Run the task every three minutes. |
|
||||
| `->everyFourMinutes();` | Run the task every four minutes. |
|
||||
| `->everyFiveMinutes();` | Run the task every five minutes. |
|
||||
| `->everyTenMinutes();` | Run the task every ten minutes. |
|
||||
| `->everyFifteenMinutes();` | Run the task every fifteen minutes. |
|
||||
| `->everyThirtyMinutes();` | Run the task every thirty minutes. |
|
||||
| `->hourly();` | Run the task every hour. |
|
||||
| `->hourlyAt(17);` | Run the task every hour at 17 minutes past the hour. |
|
||||
| `->everyOddHour($minutes = 0);` | Run the task every odd hour. |
|
||||
| `->everyTwoHours($minutes = 0);` | Run the task every two hours. |
|
||||
| `->everyThreeHours($minutes = 0);` | Run the task every three hours. |
|
||||
| `->everyFourHours($minutes = 0);` | Run the task every four hours. |
|
||||
| `->everySixHours($minutes = 0);` | Run the task every six hours. |
|
||||
| `->daily();` | Run the task every day at midnight. |
|
||||
| `->dailyAt('13:00');` | Run the task every day at 13:00. |
|
||||
| `->twiceDaily(1, 13);` | Run the task daily at 1:00 & 13:00. |
|
||||
| `->twiceDailyAt(1, 13, 15);` | Run the task daily at 1:15 & 13:15. |
|
||||
| `->weekly();` | Run the task every Sunday at 00:00. |
|
||||
| `->weeklyOn(1, '8:00');` | Run the task every week on Monday at 8:00. |
|
||||
| `->monthly();` | Run the task on the first day of every month at 00:00. |
|
||||
| `->monthlyOn(4, '15:00');` | Run the task every month on the 4th at 15:00. |
|
||||
| `->twiceMonthly(1, 16, '13:00');` | Run the task monthly on the 1st and 16th at 13:00. |
|
||||
| `->lastDayOfMonth('15:00');` | Run the task on the last day of the month at 15:00. |
|
||||
| `->quarterly();` | Run the task on the first day of every quarter at 00:00. |
|
||||
| `->quarterlyOn(4, '14:00');` | Run the task every quarter on the 4th at 14:00. |
|
||||
| `->yearly();` | Run the task on the first day of every year at 00:00. |
|
||||
| `->yearlyOn(6, 1, '17:00');` | Run the task every year on June 1st at 17:00. |
|
||||
| `->timezone('America/New_York');` | Set the timezone for the task. |
|
||||
|------------------------------------|----------------------------------------------------------|
|
||||
|
||||
```
|
||||
|
||||
These methods may be combined with additional constraints to create even more finely tuned schedules that only run on
|
||||
certain days of the week. For example, you may schedule a command to run weekly on Monday:
|
||||
|
||||
use Illuminate\Support\Facades\Schedule;
|
||||
|
||||
// Run once per week on Monday at 1 PM...
|
||||
Schedule::call(function () {
|
||||
// ...
|
||||
})->weekly()->mondays()->at('13:00');
|
||||
|
||||
// Run hourly from 8 AM to 5 PM on weekdays...
|
||||
Schedule::command('foo')
|
||||
->weekdays()
|
||||
->hourly()
|
||||
->timezone('America/Chicago')
|
||||
->between('8:00', '17:00');
|
||||
|
||||
A list of additional schedule constraints may be found below:
|
||||
|
||||
```
|
||||
|------------------------------------------|--------------------------------------------------------|
|
||||
| Method | Description |
|
||||
|------------------------------------------|--------------------------------------------------------|
|
||||
| `->weekdays();` | Limit the task to weekdays. |
|
||||
| `->weekends();` | Limit the task to weekends. |
|
||||
| `->sundays();` | Limit the task to Sunday. |
|
||||
| `->mondays();` | Limit the task to Monday. |
|
||||
| `->tuesdays();` | Limit the task to Tuesday. |
|
||||
| `->wednesdays();` | Limit the task to Wednesday. |
|
||||
| `->thursdays();` | Limit the task to Thursday. |
|
||||
| `->fridays();` | Limit the task to Friday. |
|
||||
| `->saturdays();` | Limit the task to Saturday. |
|
||||
| `->days(array\|mixed);` | Limit the task to specific days. |
|
||||
| `->between($startTime, $endTime);` | Limit the task to run between start and end times. |
|
||||
| `->unlessBetween($startTime, $endTime);` | Limit the task to not run between start and end times. |
|
||||
| `->when(Closure);` | Limit the task based on a truth test. |
|
||||
| `->environments($env);` | Limit the task to specific environments. |
|
||||
|------------------------------------------|--------------------------------------------------------|
|
||||
|
||||
```
|
||||
|
||||
<a name="day-constraints"></a>
|
||||
|
||||
#### Day Constraints
|
||||
|
||||
The `days` method may be used to limit the execution of a task to specific days of the week. For example, you may
|
||||
schedule a command to run hourly on Sundays and Wednesdays:
|
||||
|
||||
use Illuminate\Support\Facades\Schedule;
|
||||
|
||||
Schedule::command('emails:send')
|
||||
->hourly()
|
||||
->days([0, 3]);
|
||||
|
||||
Alternatively, you may use the constants available on the `Illuminate\Console\Scheduling\Schedule` class when defining
|
||||
the days on which a task should run:
|
||||
|
||||
use Illuminate\Support\Facades;
|
||||
use Illuminate\Console\Scheduling\Schedule;
|
||||
|
||||
Facades\Schedule::command('emails:send')
|
||||
->hourly()
|
||||
->days([Schedule::SUNDAY, Schedule::WEDNESDAY]);
|
||||
|
||||
<a name="between-time-constraints"></a>
|
||||
|
||||
#### Between Time Constraints
|
||||
|
||||
The `between` method may be used to limit the execution of a task based on the time of day:
|
||||
|
||||
Schedule::command('emails:send')
|
||||
->hourly()
|
||||
->between('7:00', '22:00');
|
||||
|
||||
Similarly, the `unlessBetween` method can be used to exclude the execution of a task for a period of time:
|
||||
|
||||
Schedule::command('emails:send')
|
||||
->hourly()
|
||||
->unlessBetween('23:00', '4:00');
|
||||
|
||||
<a name="truth-test-constraints"></a>
|
||||
|
||||
#### Truth Test Constraints
|
||||
|
||||
The `when` method may be used to limit the execution of a task based on the result of a given truth test. In other
|
||||
words, if the given closure returns `true`, the task will execute as long as no other constraining conditions prevent
|
||||
the task from running:
|
||||
|
||||
Schedule::command('emails:send')->daily()->when(function () {
|
||||
return true;
|
||||
});
|
||||
|
||||
The `skip` method may be seen as the inverse of `when`. If the `skip` method returns `true`, the scheduled task will not
|
||||
be executed:
|
||||
|
||||
Schedule::command('emails:send')->daily()->skip(function () {
|
||||
return true;
|
||||
});
|
||||
|
||||
When using chained `when` methods, the scheduled command will only execute if all `when` conditions return `true`.
|
||||
|
||||
<a name="environment-constraints"></a>
|
||||
|
||||
#### Environment Constraints
|
||||
|
||||
The `environments` method may be used to execute tasks only on the given environments (as defined by the
|
||||
`APP_ENV` [environment variable](/docs/{{version}}/configuration#environment-configuration)):
|
||||
|
||||
Schedule::command('emails:send')
|
||||
->daily()
|
||||
->environments(['staging', 'production']);
|
||||
|
||||
<a name="timezones"></a>
|
||||
|
||||
### Timezones
|
||||
|
||||
Using the `timezone` method, you may specify that a scheduled task's time should be interpreted within a given timezone:
|
||||
|
||||
use Illuminate\Support\Facades\Schedule;
|
||||
|
||||
Schedule::command('report:generate')
|
||||
->timezone('America/New_York')
|
||||
->at('2:00')
|
||||
|
||||
If you are repeatedly assigning the same timezone to all of your scheduled tasks, you can specify which timezone should
|
||||
be assigned to all schedules by defining a `schedule_timezone` option within your application's `app` configuration
|
||||
file:
|
||||
|
||||
'timezone' => env('APP_TIMEZONE', 'UTC'),
|
||||
|
||||
'schedule_timezone' => 'America/Chicago',
|
||||
|
||||
> [!WARNING]
|
||||
> Remember that some timezones utilize daylight savings time. When daylight saving time changes occur, your scheduled
|
||||
> task may run twice or even not run at all. For this reason, we recommend avoiding timezone scheduling when possible.
|
||||
|
||||
<a name="preventing-task-overlaps"></a>
|
||||
|
||||
### Preventing Task Overlaps
|
||||
|
||||
By default, scheduled tasks will be run even if the previous instance of the task is still running. To prevent this, you
|
||||
may use the `withoutOverlapping` method:
|
||||
|
||||
use Illuminate\Support\Facades\Schedule;
|
||||
|
||||
Schedule::command('emails:send')->withoutOverlapping();
|
||||
|
||||
In this example, the `emails:send` [Artisan command](/docs/{{version}}/artisan) will be run every minute if it is not
|
||||
already running. The `withoutOverlapping` method is especially useful if you have tasks that vary drastically in their
|
||||
execution time, preventing you from predicting exactly how long a given task will take.
|
||||
|
||||
If needed, you may specify how many minutes must pass before the "without overlapping" lock expires. By default, the
|
||||
lock will expire after 24 hours:
|
||||
|
||||
Schedule::command('emails:send')->withoutOverlapping(10);
|
||||
|
||||
Behind the scenes, the `withoutOverlapping` method utilizes your application's [cache](/docs/{{version}}/cache) to
|
||||
obtain locks. If necessary, you can clear these cache locks using the `schedule:clear-cache` Artisan command. This is
|
||||
typically only necessary if a task becomes stuck due to an unexpected server problem.
|
||||
|
||||
<a name="running-tasks-on-one-server"></a>
|
||||
|
||||
### Running Tasks on One Server
|
||||
|
||||
> [!WARNING]
|
||||
> To utilize this feature, your application must be using the `database`, `memcached`, `dynamodb`, or `redis` cache
|
||||
> driver as your application's default cache driver. In addition, all servers must be communicating with the same
|
||||
> central
|
||||
> cache server.
|
||||
|
||||
If your application's scheduler is running on multiple servers, you may limit a scheduled job to only execute on a
|
||||
single server. For instance, assume you have a scheduled task that generates a new report every Friday night. If the
|
||||
task scheduler is running on three worker servers, the scheduled task will run on all three servers and generate the
|
||||
report three times. Not good!
|
||||
|
||||
To indicate that the task should run on only one server, use the `onOneServer` method when defining the scheduled task.
|
||||
The first server to obtain the task will secure an atomic lock on the job to prevent other servers from running the same
|
||||
task at the same time:
|
||||
|
||||
use Illuminate\Support\Facades\Schedule;
|
||||
|
||||
Schedule::command('report:generate')
|
||||
->fridays()
|
||||
->at('17:00')
|
||||
->onOneServer();
|
||||
|
||||
<a name="naming-unique-jobs"></a>
|
||||
|
||||
#### Naming Single Server Jobs
|
||||
|
||||
Sometimes you may need to schedule the same job to be dispatched with different parameters, while still instructing
|
||||
Laravel to run each permutation of the job on a single server. To accomplish this, you may assign each schedule
|
||||
definition a unique name via the `name` method:
|
||||
|
||||
```php
|
||||
Schedule::job(new CheckUptime('https://laravel.com'))
|
||||
->name('check_uptime:laravel.com')
|
||||
->everyFiveMinutes()
|
||||
->onOneServer();
|
||||
|
||||
Schedule::job(new CheckUptime('https://vapor.laravel.com'))
|
||||
->name('check_uptime:vapor.laravel.com')
|
||||
->everyFiveMinutes()
|
||||
->onOneServer();
|
||||
```
|
||||
|
||||
Similarly, scheduled closures must be assigned a name if they are intended to be run on one server:
|
||||
|
||||
```php
|
||||
Schedule::call(fn () => User::resetApiRequestCount())
|
||||
->name('reset-api-request-count')
|
||||
->daily()
|
||||
->onOneServer();
|
||||
```
|
||||
|
||||
<a name="background-tasks"></a>
|
||||
|
||||
### Background Tasks
|
||||
|
||||
By default, multiple tasks scheduled at the same time will execute sequentially based on the order they are defined in
|
||||
your `schedule` method. If you have long-running tasks, this may cause subsequent tasks to start much later than
|
||||
anticipated. If you would like to run tasks in the background so that they may all run simultaneously, you may use the
|
||||
`runInBackground` method:
|
||||
|
||||
use Illuminate\Support\Facades\Schedule;
|
||||
|
||||
Schedule::command('analytics:report')
|
||||
->daily()
|
||||
->runInBackground();
|
||||
|
||||
> [!WARNING]
|
||||
> The `runInBackground` method may only be used when scheduling tasks via the `command` and `exec` methods.
|
||||
|
||||
<a name="maintenance-mode"></a>
|
||||
|
||||
### Maintenance Mode
|
||||
|
||||
Your application's scheduled tasks will not run when the application is
|
||||
in [maintenance mode](/docs/{{version}}/configuration#maintenance-mode), since we don't want your tasks to interfere
|
||||
with any unfinished maintenance you may be performing on your server. However, if you would like to force a task to run
|
||||
even in maintenance mode, you may call the `evenInMaintenanceMode` method when defining the task:
|
||||
|
||||
Schedule::command('emails:send')->evenInMaintenanceMode();
|
||||
|
||||
<a name="schedule-groups"></a>
|
||||
|
||||
### Schedule Groups
|
||||
|
||||
When defining multiple scheduled tasks with similar configurations, you can use Laravel’s task grouping feature to avoid
|
||||
repeating the same settings for each task. Grouping tasks simplifies your code and ensures consistency across related
|
||||
tasks.
|
||||
|
||||
To create a group of scheduled tasks, invoke the desired task configuration methods, followed by the `group` method. The
|
||||
`group` method accepts a closure that is responsible for defining the tasks that share the specified configuration:
|
||||
|
||||
```php
|
||||
use Illuminate\Support\Facades\Schedule;
|
||||
|
||||
Schedule::daily()
|
||||
->onOneServer()
|
||||
->timezone('America/New_York')
|
||||
->group(function () {
|
||||
Schedule::command('emails:send --force');
|
||||
Schedule::command('emails:prune');
|
||||
});
|
||||
```
|
||||
|
||||
<a name="running-the-scheduler"></a>
|
||||
|
||||
## Running the Scheduler
|
||||
|
||||
Now that we have learned how to define scheduled tasks, let's discuss how to actually run them on our server. The
|
||||
`schedule:run` Artisan command will evaluate all of your scheduled tasks and determine if they need to run based on the
|
||||
server's current time.
|
||||
|
||||
So, when using Laravel's scheduler, we only need to add a single cron configuration entry to our server that runs the
|
||||
`schedule:run` command every minute. If you do not know how to add cron entries to your server, consider using a service
|
||||
such as [Laravel Forge](https://forge.laravel.com) which can manage the cron entries for you:
|
||||
|
||||
```shell
|
||||
* * * * * cd /path-to-your-project && php artisan schedule:run >> /dev/null 2>&1
|
||||
```
|
||||
|
||||
<a name="sub-minute-scheduled-tasks"></a>
|
||||
|
||||
### Sub-Minute Scheduled Tasks
|
||||
|
||||
On most operating systems, cron jobs are limited to running a maximum of once per minute. However, Laravel's scheduler
|
||||
allows you to schedule tasks to run at more frequent intervals, even as often as once per second:
|
||||
|
||||
use Illuminate\Support\Facades\Schedule;
|
||||
|
||||
Schedule::call(function () {
|
||||
DB::table('recent_users')->delete();
|
||||
})->everySecond();
|
||||
|
||||
When sub-minute tasks are defined within your application, the `schedule:run` command will continue running until the
|
||||
end of the current minute instead of exiting immediately. This allows the command to invoke all required sub-minute
|
||||
tasks throughout the minute.
|
||||
|
||||
Since sub-minute tasks that take longer than expected to run could delay the execution of later sub-minute tasks, it is
|
||||
recommended that all sub-minute tasks dispatch queued jobs or background commands to handle the actual task processing:
|
||||
|
||||
use App\Jobs\DeleteRecentUsers;
|
||||
|
||||
Schedule::job(new DeleteRecentUsers)->everyTenSeconds();
|
||||
|
||||
Schedule::command('users:delete')->everyTenSeconds()->runInBackground();
|
||||
|
||||
<a name="interrupting-sub-minute-tasks"></a>
|
||||
|
||||
#### Interrupting Sub-Minute Tasks
|
||||
|
||||
As the `schedule:run` command runs for the entire minute of invocation when sub-minute tasks are defined, you may
|
||||
sometimes need to interrupt the command when deploying your application. Otherwise, an instance of the `schedule:run`
|
||||
command that is already running would continue using your application's previously deployed code until the current
|
||||
minute ends.
|
||||
|
||||
To interrupt in-progress `schedule:run` invocations, you may add the `schedule:interrupt` command to your application's
|
||||
deployment script. This command should be invoked after your application is finished deploying:
|
||||
|
||||
```shell
|
||||
php artisan schedule:interrupt
|
||||
```
|
||||
|
||||
<a name="running-the-scheduler-locally"></a>
|
||||
|
||||
### Running the Scheduler Locally
|
||||
|
||||
Typically, you would not add a scheduler cron entry to your local development machine. Instead, you may use the
|
||||
`schedule:work` Artisan command. This command will run in the foreground and invoke the scheduler every minute until you
|
||||
terminate the command. When sub-minute tasks are defined, the scheduler will continue running within each minute to
|
||||
process those tasks:
|
||||
|
||||
```shell
|
||||
php artisan schedule:work
|
||||
```
|
||||
|
||||
<a name="task-output"></a>
|
||||
|
||||
## Task Output
|
||||
|
||||
The Laravel scheduler provides several convenient methods for working with the output generated by scheduled tasks.
|
||||
First, using the `sendOutputTo` method, you may send the output to a file for later inspection:
|
||||
|
||||
use Illuminate\Support\Facades\Schedule;
|
||||
|
||||
Schedule::command('emails:send')
|
||||
->daily()
|
||||
->sendOutputTo($filePath);
|
||||
|
||||
If you would like to append the output to a given file, you may use the `appendOutputTo` method:
|
||||
|
||||
Schedule::command('emails:send')
|
||||
->daily()
|
||||
->appendOutputTo($filePath);
|
||||
|
||||
Using the `emailOutputTo` method, you may email the output to an email address of your choice. Before emailing the
|
||||
output of a task, you should configure Laravel's [email services](/docs/{{version}}/mail):
|
||||
|
||||
Schedule::command('report:generate')
|
||||
->daily()
|
||||
->sendOutputTo($filePath)
|
||||
->emailOutputTo('taylor@example.com');
|
||||
|
||||
If you only want to email the output if the scheduled Artisan or system command terminates with a non-zero exit code,
|
||||
use the `emailOutputOnFailure` method:
|
||||
|
||||
Schedule::command('report:generate')
|
||||
->daily()
|
||||
->emailOutputOnFailure('taylor@example.com');
|
||||
|
||||
> [!WARNING]
|
||||
> The `emailOutputTo`, `emailOutputOnFailure`, `sendOutputTo`, and `appendOutputTo` methods are exclusive to the
|
||||
`command` and `exec` methods.
|
||||
|
||||
<a name="task-hooks"></a>
|
||||
|
||||
## Task Hooks
|
||||
|
||||
Using the `before` and `after` methods, you may specify code to be executed before and after the scheduled task is
|
||||
executed:
|
||||
|
||||
use Illuminate\Support\Facades\Schedule;
|
||||
|
||||
Schedule::command('emails:send')
|
||||
->daily()
|
||||
->before(function () {
|
||||
// The task is about to execute...
|
||||
})
|
||||
->after(function () {
|
||||
// The task has executed...
|
||||
});
|
||||
|
||||
The `onSuccess` and `onFailure` methods allow you to specify code to be executed if the scheduled task succeeds or
|
||||
fails. A failure indicates that the scheduled Artisan or system command terminated with a non-zero exit code:
|
||||
|
||||
Schedule::command('emails:send')
|
||||
->daily()
|
||||
->onSuccess(function () {
|
||||
// The task succeeded...
|
||||
})
|
||||
->onFailure(function () {
|
||||
// The task failed...
|
||||
});
|
||||
|
||||
If output is available from your command, you may access it in your `after`, `onSuccess` or `onFailure` hooks by
|
||||
type-hinting an `Illuminate\Support\Stringable` instance as the `$output` argument of your hook's closure definition:
|
||||
|
||||
use Illuminate\Support\Stringable;
|
||||
|
||||
Schedule::command('emails:send')
|
||||
->daily()
|
||||
->onSuccess(function (Stringable $output) {
|
||||
// The task succeeded...
|
||||
})
|
||||
->onFailure(function (Stringable $output) {
|
||||
// The task failed...
|
||||
});
|
||||
|
||||
<a name="pinging-urls"></a>
|
||||
|
||||
#### Pinging URLs
|
||||
|
||||
Using the `pingBefore` and `thenPing` methods, the scheduler can automatically ping a given URL before or after a task
|
||||
is executed. This method is useful for notifying an external service, such as [Envoyer](https://envoyer.io), that your
|
||||
scheduled task is beginning or has finished execution:
|
||||
|
||||
Schedule::command('emails:send')
|
||||
->daily()
|
||||
->pingBefore($url)
|
||||
->thenPing($url);
|
||||
|
||||
The `pingOnSuccess` and `pingOnFailure` methods may be used to ping a given URL only if the task succeeds or fails. A
|
||||
failure indicates that the scheduled Artisan or system command terminated with a non-zero exit code:
|
||||
|
||||
Schedule::command('emails:send')
|
||||
->daily()
|
||||
->pingOnSuccess($successUrl)
|
||||
->pingOnFailure($failureUrl);
|
||||
|
||||
The `pingBeforeIf`,`thenPingIf`,`pingOnSuccessIf`, and `pingOnFailureIf` methods may be used to ping a given URL only if
|
||||
a given condition is `true`:
|
||||
|
||||
Schedule::command('emails:send')
|
||||
->daily()
|
||||
->pingBeforeIf($condition, $url)
|
||||
->thenPingIf($condition, $url);
|
||||
|
||||
Schedule::command('emails:send')
|
||||
->daily()
|
||||
->pingOnSuccessIf($condition, $successUrl)
|
||||
->pingOnFailureIf($condition, $failureUrl);
|
||||
|
||||
<a name="events"></a>
|
||||
|
||||
## Events
|
||||
|
||||
Laravel dispatches a variety of [events](/docs/{{version}}/events) during the scheduling process. You
|
||||
may [define listeners](/docs/{{version}}/events) for any of the following events:
|
||||
|
||||
```
|
||||
|-------------------------------------------------------------|
|
||||
| Event Name |
|
||||
|-------------------------------------------------------------|
|
||||
| `Illuminate\Console\Events\ScheduledTaskStarting` |
|
||||
| `Illuminate\Console\Events\ScheduledTaskFinished` |
|
||||
| `Illuminate\Console\Events\ScheduledBackgroundTaskFinished` |
|
||||
| `Illuminate\Console\Events\ScheduledTaskSkipped` |
|
||||
| `Illuminate\Console\Events\ScheduledTaskFailed` |
|
||||
|-------------------------------------------------------------|
|
||||
```
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
### The Spares Module
|
||||
|
||||
This details the operation and key highlights and developer notes for the Maximo ( Spares) module
|
||||
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
### SSHD Server
|
||||
|
||||
to restart the SSH Server on AS400 use in 5250 Console
|
||||
|
||||
```
|
||||
STRTCPSVR *SSHD
|
||||
|
||||
```
|
||||
+461
@@ -0,0 +1,461 @@
|
||||
# Stop Treating Your Blade Files Like Trash Bins. Give Them Contracts And Structure
|
||||
|
||||
Are you a Laravel developer? Do you love Blade? It’s simple, expressive, and fits naturally with the framework. But
|
||||
let’s be honest: most projects eventually turn their Blade files into dumping grounds for random variables. The
|
||||
Controllers pass loose data, views end up receiving unstructured data, partials rely on implicit assumptions, and the
|
||||
whole setup becomes fragile and error-prone.
|
||||
|
||||
## The Result?
|
||||
|
||||
- No autocomplete.
|
||||
- Runtime errors from typos.
|
||||
- Partial views with zero contracts.
|
||||
- A mess that only grows as the app scales.
|
||||
|
||||
It doesn’t have to be this way. Blade files deserve the same contracts and structure we give to APIs, database models,
|
||||
or services. With a few clear practices, you can bring discipline, contracts, and structure to Blade.
|
||||
|
||||
This article will show you the complete approach:
|
||||
|
||||
1. The problem of passing data as arrays or variables in views — solved by introducing ViewModels as contracts.
|
||||
2. Enable Autocomplete in Blade so your IDE actually helps.
|
||||
3. Annotation to views and partials bound to their own ViewModels.
|
||||
4. Lock down data structures with DTO classes for strict typing.
|
||||
5. Establish Principles for sustainable Blade development.
|
||||
|
||||
**Remember, we are only targeting Blade for now.** Not Twig or Antlr.
|
||||
Grab a coffee — this is a long read. But by the end, you’ll never look at Blade the same way again.
|
||||
|
||||
---
|
||||
|
||||
## The Crime Scene: What’s Wrong With “Array Soup” in Blade
|
||||
|
||||
Here’s the standard Laravel approach we’ve all seen in controllers:
|
||||
|
||||
```php
|
||||
class ProductController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
$products = Product::all();
|
||||
$categories = Category::all();
|
||||
$brand = Brand::all();
|
||||
$title = 'Products';
|
||||
|
||||
return view('products.index', compact('products','categories','brands','title') );
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Or maybe:
|
||||
|
||||
```php
|
||||
return view('products.index', [
|
||||
'title' => 'Products',
|
||||
'products' => Product::all(),
|
||||
'categories' => Category::all(),
|
||||
'brand' => Brand::all(),
|
||||
]);
|
||||
```
|
||||
|
||||
Or a slightly cleaner:
|
||||
|
||||
```php
|
||||
$data = [
|
||||
'title' => 'Products',
|
||||
'products' => Product::all(),
|
||||
'categories' => Category::all(),
|
||||
'brand' => Brand::all(),
|
||||
];
|
||||
|
||||
return view('products.index', $data);
|
||||
```
|
||||
|
||||
And here is how we do it for partials:
|
||||
|
||||
```blade
|
||||
@foreach ($products as $product)
|
||||
@include('products.partials.product')
|
||||
@endforeach
|
||||
|
||||
// or pass some additional data
|
||||
@foreach ($products as $product)
|
||||
@include('products.partials.product', ['editable' => $editable])
|
||||
@endforeach
|
||||
```
|
||||
|
||||
And finally for components:
|
||||
|
||||
```blade
|
||||
@foreach ($products as $product)
|
||||
<x-product-row :name="$product->name" :price ="$product->price" />
|
||||
@endforeach
|
||||
```
|
||||
|
||||
### The Old Lovely Blade
|
||||
|
||||
Here’s how it works well:
|
||||
|
||||
```blade
|
||||
<h1>{{ $title }}</h1>
|
||||
|
||||
<ul>
|
||||
@foreach ($products as $product)
|
||||
<li>{{ $product->name }} ({{ $product->price }})</li>
|
||||
{{-- or partial --}}
|
||||
@include('products.partials.product')
|
||||
{{-- or component --}}
|
||||
<x-product-row :name="$product->name" :price ="$product->price" />
|
||||
@endforeach
|
||||
</ul>
|
||||
```
|
||||
|
||||
But ask yourself:
|
||||
|
||||
- Do you remember all the variables passed to your views?
|
||||
- Do you get autocomplete in Blade to help you catch typos?
|
||||
- What about partials and includes — are you sure the data they rely on is really there?
|
||||
- If a teammate edits the controller, how do you even know the view won’t silently break?
|
||||
- How many times have you opened a Blade file and had no clue what’s in scope?
|
||||
|
||||
---
|
||||
|
||||
## 1. Introducing ViewModels: Contracts for Your Views
|
||||
|
||||
Instead of throwing arrays around, define a ViewModel — a simple DTO class. It declares exactly what data is expected.
|
||||
|
||||
```php
|
||||
namespace App\ViewModels;
|
||||
|
||||
class ProductsViewModel
|
||||
{
|
||||
public string $title;
|
||||
public array $products;
|
||||
public array $categories;
|
||||
public array $brand;
|
||||
}
|
||||
```
|
||||
|
||||
And in your controller:
|
||||
|
||||
```php
|
||||
class ProductController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
$viewModel = new ProductsViewModel();
|
||||
|
||||
$viewModel->title = 'Products';
|
||||
$viewModel->products = Product::all();
|
||||
$viewModel->categories = Category::all();
|
||||
$viewModel->brands = Brand::all();
|
||||
|
||||
return view('products.index', ['model' => $viewModel]);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> Suggestion: Always pass view‑model with name `model` for consistency. This will help in autocomplete.
|
||||
|
||||
Now the Blade file might look like:
|
||||
|
||||
```blade
|
||||
<h1>{{ $model->title }}</h1>
|
||||
<ul>
|
||||
@foreach ($model->products as $product)
|
||||
<li>{{ $product->name }} ({{ $product->price }})</li>
|
||||
{{-- or partial --}}
|
||||
@include('products.partials.product',['model' => $product])
|
||||
{{-- or component --}}
|
||||
<x-product-row :model="$product" />
|
||||
@endforeach
|
||||
</ul>
|
||||
|
||||
@include('partials.brands', ['model' => $model->brands])
|
||||
@include('partials.categories', ['model' => $model->categories])
|
||||
```
|
||||
|
||||
Again, the suggestion: for partials and components, always pass data with name `$model` for consistency to aid
|
||||
autocomplete.
|
||||
|
||||
**Benefits:**
|
||||
|
||||
- The contract is explicit.
|
||||
- Adding or removing data requires updating the ViewModel.
|
||||
- Each view, partial, or component has a single data access point `$model`.
|
||||
|
||||
---
|
||||
|
||||
## 2. Installing Extension for Autocomplete
|
||||
|
||||
This does not require code setup, but you’ll need to install a plugin/extension in your IDE. The author uses VS Code and
|
||||
recommends **PHP Tools by DevSense** (also available for other editors).
|
||||
|
||||
If you use a different editor, find a similar extension — support for Blade autocomplete is key.
|
||||
|
||||
---
|
||||
|
||||
## 3. Enabling Autocomplete in Blade
|
||||
|
||||
Even with ViewModels, Blade doesn’t automatically know the type of `$model`. The trick is to annotate it in Blade views,
|
||||
partials, and components:
|
||||
|
||||
```blade
|
||||
{{-- views/products/index.blade.php --}}
|
||||
@php
|
||||
/** @var \App\ViewModels\ProductsViewModel $model */
|
||||
@endphp
|
||||
<ul>
|
||||
@foreach ($model->products as $product)
|
||||
<li>{{ $product->name }} ({{ $product->price }})</li>
|
||||
{{-- or partial --}}
|
||||
@include('products.partials.product')
|
||||
{{-- or component --}}
|
||||
<x-product-row :name="$product->name" :price="$product->price" />
|
||||
@endforeach
|
||||
</ul>
|
||||
```
|
||||
|
||||
In partials or components:
|
||||
|
||||
```blade
|
||||
{{-- views/products/partials/product.blade.php --}}
|
||||
@php
|
||||
/** @var \App\Models\Product $model */
|
||||
@endphp
|
||||
|
||||
<span>
|
||||
{{ $model->name }}
|
||||
</span>
|
||||
```
|
||||
|
||||
And in components:
|
||||
|
||||
```blade
|
||||
{{-- views/components/product.blade.php --}}
|
||||
@php
|
||||
/** @var \App\View\Components\Product $model */
|
||||
@endphp
|
||||
|
||||
<span>
|
||||
{{ $model->name }}
|
||||
</span>
|
||||
```
|
||||
|
||||
Now, in an IDE like VS Code, typing `$model->` will give you real autocomplete suggestions.
|
||||
|
||||
This is a game-changer:
|
||||
|
||||
- No more guessing property names.
|
||||
- Mistyped variables get caught instantly.
|
||||
- New developers know exactly what’s available in the view.
|
||||
|
||||
---
|
||||
|
||||
## 4. Enforce Types at Runtime
|
||||
|
||||
Since now we pass ViewModels into views, partials, or components and define annotations, let’s enforce Blade to accept
|
||||
only specific types. The author adds:
|
||||
|
||||
1. **TypedViewFactory** – A custom view factory that parses `@var` declarations at the top of Blade files and enforces
|
||||
them.
|
||||
2. **TypedViewServiceProvider** – Wires everything into Laravel automatically.
|
||||
|
||||
If you declare a type in a Blade file, Laravel must pass the correct class, array, or collection; otherwise, it throws
|
||||
an exception.
|
||||
|
||||
Example:
|
||||
|
||||
```blade
|
||||
{{-- products/index.blade.php --}}
|
||||
@php /** @var App\ViewModels\ProductsViewModel $model */ @endphp
|
||||
<h1>{{ $model->title }}</h1>
|
||||
```
|
||||
|
||||
Only `ProductsViewModel` works—anything else throws an exception.
|
||||
|
||||
Similarly for partials and components, the wrong type is no longer silently accepted; it fails loudly.
|
||||
|
||||
You can do the same for arrays and collections:
|
||||
|
||||
```blade
|
||||
@php
|
||||
/** @var App\Models\Product[] $model */
|
||||
@endphp
|
||||
|
||||
{{-- or --}}
|
||||
@php
|
||||
/** @var \Illuminate\Support\Collection<App\Models\Product> $model */
|
||||
@endphp
|
||||
```
|
||||
|
||||
Wrong types cause errors rather than silent bugs.
|
||||
|
||||
---
|
||||
|
||||
## 5. Going Fully Typed With DTO Classes
|
||||
|
||||
So far, we’ve wrapped data in ViewModels. But what about the data itself? Passing raw Eloquent models to views can be
|
||||
risky — they carry too much baggage and autocomplete may expose a jungle of methods and properties.
|
||||
|
||||
Let’s create DTO classes to define exactly what your views need. (Note: components themselves can act as DTOs, so
|
||||
sometimes you don’t need separate DTOs.)
|
||||
|
||||
### BaseDTO
|
||||
|
||||
```php
|
||||
namespace App\DTO;
|
||||
|
||||
use InvalidArgumentException;
|
||||
|
||||
abstract class BaseDTO
|
||||
{
|
||||
public function __construct(array $data = [])
|
||||
{
|
||||
foreach ($data as $key => $value) {
|
||||
if (!property_exists($this, $key)) {
|
||||
throw new InvalidArgumentException(
|
||||
"Property '{$key}' is not defined in " . static::class
|
||||
);
|
||||
}
|
||||
$this->$key = $value;
|
||||
}
|
||||
}
|
||||
public function __get($name)
|
||||
{
|
||||
throw new InvalidArgumentException(
|
||||
"Tried to access undefined property '{$name}' on " . static::class
|
||||
);
|
||||
}
|
||||
public function __set($name, $value)
|
||||
{
|
||||
throw new InvalidArgumentException(
|
||||
"Tried to set undefined property '{$name}' on " . static::class
|
||||
);
|
||||
}
|
||||
public static function columns(): array
|
||||
{
|
||||
return array_map(
|
||||
fn($prop) => $prop->getName(),
|
||||
(new \ReflectionClass(static::class))->getProperties()
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### SimpleProduct DTO
|
||||
|
||||
```php
|
||||
namespace App\DTO\Product;
|
||||
|
||||
use App\DTO\BaseDTO;
|
||||
|
||||
class SimpleProduct extends BaseDTO
|
||||
{
|
||||
public string $name;
|
||||
public string $image;
|
||||
public float $price;
|
||||
public int $stock;
|
||||
}
|
||||
```
|
||||
|
||||
In the controller:
|
||||
|
||||
```php
|
||||
class ProductController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
$viewModel = new ProductsViewModel();
|
||||
|
||||
$viewModel->products = Product::select(SimpleProduct::columns())->get();
|
||||
// other assignments...
|
||||
return view('products.index', ['model' => $viewModel]);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
In the partial:
|
||||
|
||||
```blade
|
||||
{{-- views/products/partials/product.blade.php --}}
|
||||
@php
|
||||
/** @var \App\DTO\Product\SimpleProduct $model */
|
||||
@endphp
|
||||
|
||||
<span>
|
||||
{{ $model->name }}
|
||||
</span>
|
||||
```
|
||||
|
||||
Autocomplete now shows only DTO properties.
|
||||
|
||||
#### Caveats & Tips
|
||||
|
||||
- If you only select `DTO::columns()` in your query and still pass raw models to Blade, IDE autocomplete works via
|
||||
annotations—but at runtime Blade can still access everything.
|
||||
- For stricter discipline, wrap results into DTO instances.
|
||||
- Schema Drift Protection: if a DTO includes a property not in the table, MySQL will error, keeping your DTOs in sync.
|
||||
- You lose Eloquent helpers, relations, and accessors. Do transformations before mapping to DTOs.
|
||||
- Mapping overhead is minimal: a base DTO + mapper makes it clean and efficient.
|
||||
|
||||
Example mapper:
|
||||
|
||||
```php
|
||||
class DTOMapper
|
||||
{
|
||||
public static function map(object $source, string $dtoClass): object
|
||||
{
|
||||
$dtoReflection = new ReflectionClass($dtoClass);
|
||||
$properties = $dtoReflection->getProperties();
|
||||
|
||||
$args = [];
|
||||
|
||||
foreach ($properties as $property) {
|
||||
$name = $property->getName();
|
||||
if (isset($source->$name)) {
|
||||
$args[$name] = $source->$name;
|
||||
}
|
||||
}
|
||||
|
||||
return new $dtoClass(...$args);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Usage:
|
||||
|
||||
```php
|
||||
$dto = DTOMapper::map($product, SimpleProduct::class);
|
||||
$dtos = $products->map(fn($p) => DTOMapper::map($p, ProductDTO::class));
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Principles of Structured Blade
|
||||
|
||||
This approach holds only if you enforce ground rules:
|
||||
|
||||
1. **No untyped arrays in views** — every view receives a single typed contract.
|
||||
2. **One ViewModel per Blade file** — keep mental load low.
|
||||
3. **Partials and components need contracts too** — no freeloaders.
|
||||
4. **Always annotate with `@var`** — autocomplete is non‑negotiable.
|
||||
5. **Always pass data as `model` for consistency** — every blade view has a single entry point.
|
||||
6. **Business logic stays out of Blade views** — data shaping and conditions belong in ViewModels.
|
||||
7. **Use DTOs to avoid Eloquent jungle** — views see pure, predictable DTOs.
|
||||
8. **Strict access, fail loudly** — undefined properties in ViewModel should throw, not silently fail.
|
||||
|
||||
---
|
||||
|
||||
## Final Word
|
||||
|
||||
Blade isn’t broken. The way most developers use it is.
|
||||
|
||||
Treating Blade files as unstructured trash bins creates brittle, unmaintainable code. Adding ViewModels, autocomplete,
|
||||
contracts for partials, and DTOs gives your views the same level of professionalism as the rest of your codebase.
|
||||
|
||||
This isn’t overkill. It’s discipline. And discipline is what separates fragile projects from sustainable ones.
|
||||
|
||||
So stop passing arrays. Start passing contracts. Give your Blade files the structure they deserve.
|
||||
|
||||
---
|
||||
@@ -7,13 +7,13 @@ use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
* @property int $documentation_document_id
|
||||
* @property string $disk
|
||||
* @property string $path
|
||||
* @property string $original_name
|
||||
* @property int $id
|
||||
* @property int $documentation_document_id
|
||||
* @property string $disk
|
||||
* @property string $path
|
||||
* @property string $original_name
|
||||
* @property string|null $mime_type
|
||||
* @property int|null $size
|
||||
* @property int|null $size
|
||||
*/
|
||||
class DocumentationAttachment extends Model
|
||||
{
|
||||
@@ -57,13 +57,13 @@ class DocumentationAttachment extends Model
|
||||
}
|
||||
|
||||
if ($bytes < 1024) {
|
||||
return $bytes . ' B';
|
||||
return $bytes.' B';
|
||||
}
|
||||
|
||||
if ($bytes < 1048576) {
|
||||
return number_format($bytes / 1024, 1) . ' KB';
|
||||
return number_format($bytes / 1024, 1).' KB';
|
||||
}
|
||||
|
||||
return number_format($bytes / 1048576, 1) . ' MB';
|
||||
return number_format($bytes / 1048576, 1).' MB';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,14 +9,14 @@ use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
* @property string $name
|
||||
* @property string $slug
|
||||
* @property int $id
|
||||
* @property string $name
|
||||
* @property string $slug
|
||||
* @property string|null $icon
|
||||
* @property string $colour
|
||||
* @property string $colour
|
||||
* @property string|null $description
|
||||
* @property int $sort_order
|
||||
* @property bool $is_active
|
||||
* @property int $sort_order
|
||||
* @property bool $is_active
|
||||
*/
|
||||
class DocumentationCategory extends Model
|
||||
{
|
||||
@@ -66,8 +66,7 @@ class DocumentationCategory extends Model
|
||||
/**
|
||||
* Active category scope.
|
||||
*
|
||||
* @param Builder<DocumentationCategory> $query
|
||||
*
|
||||
* @param Builder<DocumentationCategory> $query
|
||||
* @return Builder<DocumentationCategory>
|
||||
*/
|
||||
public function scopeActive(Builder $query): Builder
|
||||
@@ -78,8 +77,7 @@ class DocumentationCategory extends Model
|
||||
/**
|
||||
* Ordered category scope.
|
||||
*
|
||||
* @param Builder<DocumentationCategory> $query
|
||||
*
|
||||
* @param Builder<DocumentationCategory> $query
|
||||
* @return Builder<DocumentationCategory>
|
||||
*/
|
||||
public function scopeOrdered(Builder $query): Builder
|
||||
|
||||
@@ -11,15 +11,15 @@ use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
* @property int|null $documentation_category_id
|
||||
* @property string $title
|
||||
* @property string $slug
|
||||
* @property int $id
|
||||
* @property int|null $documentation_category_id
|
||||
* @property string $title
|
||||
* @property string $slug
|
||||
* @property string|null $summary
|
||||
* @property string|null $body
|
||||
* @property string $status
|
||||
* @property bool $is_featured
|
||||
* @property string $version
|
||||
* @property string $status
|
||||
* @property bool $is_featured
|
||||
* @property string $version
|
||||
* @property string|null $reference
|
||||
* @property-read string $rendered_body
|
||||
*/
|
||||
@@ -101,8 +101,7 @@ class DocumentationDocument extends Model
|
||||
/**
|
||||
* Published document scope.
|
||||
*
|
||||
* @param Builder<DocumentationDocument> $query
|
||||
*
|
||||
* @param Builder<DocumentationDocument> $query
|
||||
* @return Builder<DocumentationDocument>
|
||||
*/
|
||||
public function scopePublished(Builder $query): Builder
|
||||
@@ -113,8 +112,7 @@ class DocumentationDocument extends Model
|
||||
/**
|
||||
* Featured document scope.
|
||||
*
|
||||
* @param Builder<DocumentationDocument> $query
|
||||
*
|
||||
* @param Builder<DocumentationDocument> $query
|
||||
* @return Builder<DocumentationDocument>
|
||||
*/
|
||||
public function scopeFeatured(Builder $query): Builder
|
||||
@@ -140,7 +138,7 @@ class DocumentationDocument extends Model
|
||||
]);
|
||||
}
|
||||
|
||||
return '<p>' . nl2br(e($body), false) . '</p>';
|
||||
return '<p>'.nl2br(e($body), false).'</p>';
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -7,6 +7,7 @@ namespace Modules\Documentation\Providers;
|
||||
use Illuminate\Support\Facades\Blade;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Modules\Documentation\Console\ImportDocumentationCommand;
|
||||
|
||||
final class DocumentationServiceProvider extends ServiceProvider
|
||||
{
|
||||
@@ -29,9 +30,24 @@ final class DocumentationServiceProvider extends ServiceProvider
|
||||
public function boot(): void
|
||||
{
|
||||
$this->registerViews();
|
||||
$this->registerCommands();
|
||||
$this->loadMigrationsFrom(module_path('Documentation', 'Database/Migrations'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Register module console commands.
|
||||
*/
|
||||
private function registerCommands(): void
|
||||
{
|
||||
if (! $this->app->runningInConsole()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->commands([
|
||||
ImportDocumentationCommand::class,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register module views and anonymous components.
|
||||
*/
|
||||
@@ -47,12 +63,12 @@ final class DocumentationServiceProvider extends ServiceProvider
|
||||
$paths = [$sourcePath];
|
||||
|
||||
foreach (Config::get('view.paths', []) as $path) {
|
||||
if (is_dir($path . '/modules/documentation')) {
|
||||
array_unshift($paths, $path . '/modules/documentation');
|
||||
if (is_dir($path.'/modules/documentation')) {
|
||||
array_unshift($paths, $path.'/modules/documentation');
|
||||
}
|
||||
}
|
||||
|
||||
$this->loadViewsFrom($paths, 'documentation');
|
||||
Blade::anonymousComponentPath($sourcePath . '/components', 'documentation');
|
||||
Blade::anonymousComponentPath($sourcePath.'/components', 'documentation');
|
||||
}
|
||||
}
|
||||
|
||||
Executable → Regular
+70
@@ -622,3 +622,73 @@ html.dark .doc-content code {
|
||||
border-radius: 1.375rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* Documentation reading experience */
|
||||
.doc-card-body:has(.doc-content) {
|
||||
padding: clamp(1.5rem, 3vw, 3rem);
|
||||
}
|
||||
|
||||
.doc-content {
|
||||
max-width: 68rem;
|
||||
margin: 0 auto;
|
||||
color: var(--doc-text);
|
||||
font-size: 1.0625rem;
|
||||
line-height: 1.8;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.doc-content > :first-child { margin-top: 0; }
|
||||
.doc-content > :last-child { margin-bottom: 0; }
|
||||
.doc-content h1 { font-size: clamp(2rem, 4vw, 2.75rem); margin-top: 0; margin-bottom: 1.25rem; }
|
||||
.doc-content h2 { font-size: clamp(1.45rem, 2.5vw, 1.8rem); margin-top: 2.4rem; margin-bottom: 1rem; padding-bottom: .55rem; }
|
||||
.doc-content h3 { font-size: 1.3rem; margin-top: 2rem; margin-bottom: .75rem; }
|
||||
.doc-content h4 { font-size: 1.1rem; margin: 1.75rem 0 .65rem; }
|
||||
.doc-content p { margin: 0 0 1.2rem; }
|
||||
.doc-content ul,
|
||||
.doc-content ol { margin: 0 0 1.35rem 1.5rem; padding-left: .75rem; }
|
||||
.doc-content li { margin: .4rem 0; padding-left: .25rem; }
|
||||
.doc-content li::marker { color: #60a5fa; font-weight: 700; }
|
||||
.doc-content a { color: #60a5fa; text-decoration: underline; text-decoration-color: rgba(96,165,250,.4); text-underline-offset: .18em; }
|
||||
.doc-content a:hover { color: #93c5fd; text-decoration-color: currentColor; }
|
||||
.doc-content pre { margin: 1.4rem 0 1.65rem; border: 1px solid #263244; background: #0b1220; padding: 1.15rem 1.25rem; box-shadow: inset 0 1px 0 rgba(255,255,255,.03); }
|
||||
.doc-content pre code { font-size: .925rem; line-height: 1.65; white-space: pre; }
|
||||
.doc-content :not(pre) > code { border: 1px solid rgba(148,163,184,.18); background: rgba(30,41,59,.85); color: #e2e8f0; }
|
||||
.doc-content blockquote { margin: 1.5rem 0; border-left-width: 3px; border-radius: 0 .6rem .6rem 0; background: rgba(37,99,235,.07); padding: .9rem 1.1rem; }
|
||||
.doc-content table { display: block; overflow-x: auto; margin: 1.5rem 0; border-radius: .75rem; }
|
||||
.doc-content th { background: rgba(255,255,255,.035); font-weight: 700; }
|
||||
.doc-content hr { margin: 2.25rem 0; border: 0; border-top: 1px solid var(--doc-line); }
|
||||
|
||||
/* Pagination: never use Laravel's light/white button treatment in the dark Helpdesk. */
|
||||
.doc-pagination { margin-top: 1.125rem; }
|
||||
.doc-pagination nav > div:first-child { display: none; }
|
||||
.doc-pagination nav > div:last-child { display: flex; align-items: center; justify-content: space-between; gap: 1rem; }
|
||||
.doc-pagination nav > div:last-child > div:first-child { color: var(--doc-muted); }
|
||||
.doc-pagination nav span[aria-current="page"] > span,
|
||||
.doc-pagination nav a,
|
||||
.doc-pagination nav span[aria-disabled="true"] > span {
|
||||
background: #171a1f !important;
|
||||
border-color: #343a46 !important;
|
||||
color: #d6dae2 !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
.doc-pagination nav a:hover {
|
||||
background: #232831 !important;
|
||||
border-color: #4b5563 !important;
|
||||
color: #fff !important;
|
||||
}
|
||||
.doc-pagination nav span[aria-current="page"] > span {
|
||||
background: #2563eb !important;
|
||||
border-color: #2563eb !important;
|
||||
color: #fff !important;
|
||||
}
|
||||
.doc-pagination nav span[aria-disabled="true"] > span { color: #697180 !important; cursor: not-allowed; }
|
||||
.doc-pagination nav svg { width: 1rem; height: 1rem; }
|
||||
|
||||
/* Documentation: professional contrast and strict light/dark mode parity. */
|
||||
html:not(.dark) .documentation-surface,
|
||||
html:not(.dark) [data-documentation-surface] { color:#18181b !important; }
|
||||
html:not(.dark) .documentation-surface :is(.text-zinc-400,.text-zinc-500,.text-zinc-600,.text-gray-400,.text-gray-500,.text-gray-600),
|
||||
html:not(.dark) [data-documentation-surface] :is(.text-zinc-400,.text-zinc-500,.text-zinc-600,.text-gray-400,.text-gray-500,.text-gray-600) { color:#52525b !important; }
|
||||
html.dark .documentation-surface :is(.text-zinc-400,.text-zinc-500,.text-zinc-600,.text-gray-400,.text-gray-500,.text-gray-600),
|
||||
html.dark [data-documentation-surface] :is(.text-zinc-400,.text-zinc-500,.text-zinc-600,.text-gray-400,.text-gray-500,.text-gray-600) { color:#a1a1aa !important; }
|
||||
html:not(.dark) .documentation-surface :is(section,article,.card,[class*="rounded"]):not([class*="bg-"]){ color:#27272a; }
|
||||
|
||||
Executable → Regular
+1
-1
@@ -115,7 +115,7 @@
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
<div style="margin-top:18px;">{{ $documents->links() }}</div>
|
||||
<div class="doc-pagination">{{ $documents->links() }}</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
@@ -7,7 +7,6 @@ namespace Modules\Documentation\Tests\Feature;
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Modules\Documentation\Models\DocumentationAttachment;
|
||||
use Modules\Documentation\Models\DocumentationDocument;
|
||||
use Tests\TestCase;
|
||||
|
||||
|
||||
@@ -17,8 +17,7 @@ class DocumentationModuleTest extends TestCase
|
||||
/**
|
||||
* Add a CSRF token for projects that keep web middleware enabled during tests.
|
||||
*
|
||||
* @param array<string, mixed> $payload
|
||||
*
|
||||
* @param array<string, mixed> $payload
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
private function csrfPayload(array $payload): array
|
||||
|
||||
@@ -5,6 +5,7 @@ declare(strict_types=1);
|
||||
return [
|
||||
'route_prefix' => env('HELPDESK_ROUTE_PREFIX', 'admin/helpdesk'),
|
||||
'middleware' => ['web', 'auth'],
|
||||
'legacy_connection' => env('HELPDESK_LEGACY_DB_CONNECTION', config('database.default')),
|
||||
'disk' => env('HELPDESK_ATTACHMENTS_DISK', 'local'),
|
||||
'max_upload_kb' => (int) env('HELPDESK_MAX_UPLOAD_KB', 10240),
|
||||
|
||||
@@ -44,6 +45,11 @@ return [
|
||||
'blocked_extensions' => ['exe', 'dll', 'com', 'scr', 'msi', 'app', 'dmg', 'pkg', 'jar', 'war'],
|
||||
'virus_scanner' => env('HELPDESK_VIRUS_SCANNER', null),
|
||||
|
||||
'legacy' => [
|
||||
'enabled' => (bool) env('HELPDESK_LEGACY_ENABLED', false),
|
||||
'connection' => env('HELPDESK_LEGACY_CONNECTION', 'helpdesk_legacy'),
|
||||
],
|
||||
|
||||
'allowed_mimes' => [],
|
||||
'default_status_slug' => 'new',
|
||||
'closed_status_slug' => 'closed',
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Modules\Helpdesk\Console;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Database\ConnectionInterface;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Modules\Helpdesk\Models\LegacyCategory;
|
||||
use Modules\Helpdesk\Models\LegacyComment;
|
||||
use Modules\Helpdesk\Models\LegacyTicket;
|
||||
use Throwable;
|
||||
|
||||
final class ImportLegacyHelpdeskCommand extends Command
|
||||
{
|
||||
protected $signature = 'helpdesk:import-legacy {--connection= : Laravel database connection containing the old tickets tables} {--fresh : Clear previously imported legacy records first}';
|
||||
|
||||
protected $description = 'Import the old Helpdesk tickets and categories into the read-only Legacy System';
|
||||
|
||||
public function handle(): int
|
||||
{
|
||||
if (! config('helpdesk.legacy.enabled', false)) {
|
||||
$this->error('Legacy Helpdesk support is disabled. Set HELPDESK_LEGACY_ENABLED=true to enable it.');
|
||||
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
$connectionName = (string) ($this->option('connection') ?: config('helpdesk.legacy_connection', config('database.default')));
|
||||
$source = DB::connection($connectionName);
|
||||
$schema = Schema::connection($connectionName);
|
||||
|
||||
foreach (['tickets', 'tickets_categories'] as $table) {
|
||||
if (! $schema->hasTable($table)) {
|
||||
$this->error("Source table {$table} was not found on connection [{$connectionName}].");
|
||||
|
||||
return self::FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->option('fresh')) {
|
||||
LegacyComment::query()->delete();
|
||||
LegacyTicket::query()->delete();
|
||||
LegacyCategory::query()->delete();
|
||||
}
|
||||
|
||||
$this->importCategories($source);
|
||||
$this->importTickets($source, $schema);
|
||||
$this->importComments($source, $schema);
|
||||
$this->refreshCategoryCounts();
|
||||
|
||||
$this->info(sprintf('Legacy import complete: %d tickets, %d categories, %d comments.', LegacyTicket::count(), LegacyCategory::count(), LegacyComment::count()));
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
private function importCategories(ConnectionInterface $source): void
|
||||
{
|
||||
$source->table('tickets_categories')->orderBy('id')->chunk(500, function ($rows): void {
|
||||
foreach ($rows as $row) {
|
||||
LegacyCategory::updateOrCreate(['legacy_id' => $row->id], ['name' => (string) $row->name, 'color' => $row->color ?? null]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private function importTickets(ConnectionInterface $source, $schema): void
|
||||
{
|
||||
$columns = collect($schema->getColumnListing('tickets'));
|
||||
$lookups = [
|
||||
'category' => $this->lookup($source, $schema, 'tickets_categories'),
|
||||
'status' => $this->lookup($source, $schema, 'tickets_statuses'),
|
||||
'priority' => $this->lookup($source, $schema, 'tickets_priorities'),
|
||||
'project' => $this->lookup($source, $schema, 'projects'),
|
||||
'user' => $this->lookup($source, $schema, 'users'),
|
||||
];
|
||||
|
||||
$source->table('tickets')->orderBy('id')->chunk(250, function ($rows) use ($lookups): void {
|
||||
foreach ($rows as $row) {
|
||||
$data = (array) $row;
|
||||
LegacyTicket::updateOrCreate(['legacy_id' => $row->id], [
|
||||
'reference' => $data['reference'] ?? null,
|
||||
'subject' => (string) ($data['subject'] ?? 'Legacy ticket #'.$row->id),
|
||||
'content' => $data['content'] ?? null,
|
||||
'html_content' => $data['htmlcontent'] ?? null,
|
||||
'legacy_category_id' => $data['category_id'] ?? null,
|
||||
'category_name' => $lookups['category'][$data['category_id'] ?? 0] ?? null,
|
||||
'status_name' => $lookups['status'][$data['status_id'] ?? 0] ?? null,
|
||||
'priority_name' => $lookups['priority'][$data['priority_id'] ?? 0] ?? null,
|
||||
'requester_name' => $lookups['user'][$data['user_id'] ?? 0] ?? null,
|
||||
'agent_name' => $lookups['user'][$data['agent_id'] ?? 0] ?? null,
|
||||
'project_name' => $lookups['project'][$data['project_id'] ?? 0] ?? null,
|
||||
'legacy_created_at' => $data['created_at'] ?? null,
|
||||
'legacy_updated_at' => $data['updated_at'] ?? null,
|
||||
'completed_at' => $data['completed_at'] ?? null,
|
||||
'archived_at' => $data['archived_at'] ?? null,
|
||||
'legacy_data' => $data,
|
||||
]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private function importComments(ConnectionInterface $source, $schema): void
|
||||
{
|
||||
if (! $schema->hasTable('tickets_comments')) {
|
||||
return;
|
||||
}
|
||||
$users = $this->lookup($source, $schema, 'users');
|
||||
$source->table('tickets_comments')->orderBy('id')->chunk(500, function ($rows) use ($users): void {
|
||||
foreach ($rows as $row) {
|
||||
$data = (array) $row;
|
||||
LegacyComment::updateOrCreate(['legacy_id' => $row->id], [
|
||||
'legacy_ticket_id' => $data['ticket_id'],
|
||||
'author_name' => $users[$data['user_id'] ?? 0] ?? null,
|
||||
'content' => $data['content'] ?? null,
|
||||
'html_content' => $data['htmlcontent'] ?? null,
|
||||
'legacy_created_at' => $data['created_at'] ?? null,
|
||||
'legacy_updated_at' => $data['updated_at'] ?? null,
|
||||
]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private function lookup(ConnectionInterface $source, $schema, string $table): array
|
||||
{
|
||||
if (! $schema->hasTable($table)) {
|
||||
return [];
|
||||
}
|
||||
$columns = $schema->getColumnListing($table);
|
||||
$nameColumn = in_array('name', $columns, true) ? 'name' : (in_array('username', $columns, true) ? 'username' : null);
|
||||
if ($nameColumn === null) {
|
||||
return [];
|
||||
}
|
||||
try {
|
||||
return $source->table($table)->pluck($nameColumn, 'id')->map(fn ($v) => (string) $v)->all();
|
||||
} catch (Throwable) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
private function refreshCategoryCounts(): void
|
||||
{
|
||||
LegacyCategory::query()->each(function (LegacyCategory $category): void {
|
||||
$category->update(['ticket_count' => LegacyTicket::query()->where('legacy_category_id', $category->legacy_id)->count()]);
|
||||
});
|
||||
}
|
||||
}
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('helpdesk_legacy_categories', function (Blueprint $table): void {
|
||||
$table->id();
|
||||
$table->unsignedBigInteger('legacy_id')->unique();
|
||||
$table->string('name');
|
||||
$table->string('color', 32)->nullable();
|
||||
$table->unsignedInteger('ticket_count')->default(0);
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
Schema::create('helpdesk_legacy_tickets', function (Blueprint $table): void {
|
||||
$table->id();
|
||||
$table->unsignedBigInteger('legacy_id')->unique();
|
||||
$table->string('reference')->nullable()->index();
|
||||
$table->string('subject');
|
||||
$table->longText('content')->nullable();
|
||||
$table->longText('html_content')->nullable();
|
||||
$table->unsignedBigInteger('legacy_category_id')->nullable()->index();
|
||||
$table->string('category_name')->nullable();
|
||||
$table->string('status_name')->nullable();
|
||||
$table->string('priority_name')->nullable();
|
||||
$table->string('requester_name')->nullable();
|
||||
$table->string('agent_name')->nullable();
|
||||
$table->string('project_name')->nullable();
|
||||
$table->timestamp('legacy_created_at')->nullable()->index();
|
||||
$table->timestamp('legacy_updated_at')->nullable();
|
||||
$table->timestamp('completed_at')->nullable();
|
||||
$table->timestamp('archived_at')->nullable();
|
||||
$table->json('legacy_data')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
Schema::create('helpdesk_legacy_comments', function (Blueprint $table): void {
|
||||
$table->id();
|
||||
$table->unsignedBigInteger('legacy_id')->unique();
|
||||
$table->unsignedBigInteger('legacy_ticket_id')->index();
|
||||
$table->string('author_name')->nullable();
|
||||
$table->longText('content')->nullable();
|
||||
$table->longText('html_content')->nullable();
|
||||
$table->timestamp('legacy_created_at')->nullable();
|
||||
$table->timestamp('legacy_updated_at')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('helpdesk_legacy_comments');
|
||||
Schema::dropIfExists('helpdesk_legacy_tickets');
|
||||
Schema::dropIfExists('helpdesk_legacy_categories');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Modules\Helpdesk\Http\Controllers;
|
||||
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Illuminate\Http\Request;
|
||||
use Modules\Helpdesk\Models\LegacyCategory;
|
||||
use Modules\Helpdesk\Models\LegacyTicket;
|
||||
|
||||
final class LegacySystemController
|
||||
{
|
||||
public function tickets(Request $request): View
|
||||
{
|
||||
$search = trim((string) $request->query('search', ''));
|
||||
$category = $request->integer('category');
|
||||
|
||||
$tickets = LegacyTicket::query()
|
||||
->when($search !== '', fn ($query) => $query->where(function ($q) use ($search): void {
|
||||
$q->where('reference', 'like', "%{$search}%")
|
||||
->orWhere('subject', 'like', "%{$search}%")
|
||||
->orWhere('requester_name', 'like', "%{$search}%");
|
||||
}))
|
||||
->when($category > 0, fn ($query) => $query->where('legacy_category_id', $category))
|
||||
->orderByDesc('legacy_created_at')
|
||||
->orderByDesc('legacy_id')
|
||||
->paginate(30)
|
||||
->withQueryString();
|
||||
|
||||
return view('helpdesk::legacy.tickets', [
|
||||
'tickets' => $tickets,
|
||||
'categories' => LegacyCategory::query()->orderBy('name')->get(),
|
||||
'search' => $search,
|
||||
'selectedCategory' => $category,
|
||||
]);
|
||||
}
|
||||
|
||||
public function show(LegacyTicket $ticket): View
|
||||
{
|
||||
$ticket->load('comments');
|
||||
|
||||
return view('helpdesk::legacy.show', compact('ticket'));
|
||||
}
|
||||
|
||||
public function categories(): View
|
||||
{
|
||||
return view('helpdesk::legacy.categories', [
|
||||
'categories' => LegacyCategory::query()->orderBy('name')->paginate(50),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -26,8 +26,11 @@ final class ArchivedTicketIndex extends Component
|
||||
public string $search = '';
|
||||
|
||||
public bool $deleteModalOpen = false;
|
||||
|
||||
public ?int $pendingDeleteTicketId = null;
|
||||
|
||||
public ?string $pendingDeleteTicketReference = null;
|
||||
|
||||
public ?string $pendingDeleteTicketSubject = null;
|
||||
|
||||
public function updatedSearch(): void
|
||||
@@ -75,6 +78,7 @@ final class ArchivedTicketIndex extends Component
|
||||
{
|
||||
if ($this->pendingDeleteTicketId === null) {
|
||||
$this->resetDeleteState();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,9 @@ final class HelpdeskDashboardWidget extends Component
|
||||
|
||||
public function updatedDays(): void
|
||||
{
|
||||
if (! in_array($this->days, [7, 14, 30], true)) $this->days = 7;
|
||||
if (! in_array($this->days, [7, 14, 30], true)) {
|
||||
$this->days = 7;
|
||||
}
|
||||
}
|
||||
|
||||
public function render(): View
|
||||
@@ -33,6 +35,7 @@ final class HelpdeskDashboardWidget extends Component
|
||||
$trendRows = (clone $base)->where('created_at', '>=', now()->subDays($this->days - 1)->startOfDay())->get(['created_at', 'completed_at']);
|
||||
$trend = collect($period)->map(function ($date) use ($trendRows): array {
|
||||
$day = $date->toDateString();
|
||||
|
||||
return [
|
||||
'label' => $date->format('M j'),
|
||||
'created' => $trendRows->filter(fn ($ticket) => optional($ticket->created_at)->toDateString() === $day)->count(),
|
||||
|
||||
@@ -39,17 +39,29 @@ final class SettingsManager extends Component
|
||||
public bool $teamModalOpen = false;
|
||||
|
||||
public bool $statusModalOpen = false;
|
||||
|
||||
public bool $priorityModalOpen = false;
|
||||
|
||||
public bool $categoryModalOpen = false;
|
||||
|
||||
public bool $projectModalOpen = false;
|
||||
|
||||
public bool $boardModalOpen = false;
|
||||
|
||||
public bool $repositoryModalOpen = false;
|
||||
|
||||
public bool $workflowModalOpen = false;
|
||||
|
||||
public bool $cannedModalOpen = false;
|
||||
|
||||
public bool $slaModalOpen = false;
|
||||
|
||||
public bool $automationModalOpen = false;
|
||||
|
||||
public bool $checklistModalOpen = false;
|
||||
|
||||
public bool $tagModalOpen = false;
|
||||
|
||||
public bool $productModalOpen = false;
|
||||
|
||||
/** @var array<string, mixed> */
|
||||
@@ -1041,57 +1053,57 @@ final class SettingsManager extends Component
|
||||
return view()->file(
|
||||
resource_path('themes/backend/views/modules/helpdesk/livewire/settings-manager.blade.php'),
|
||||
[
|
||||
'statuses' => $this->orderedStatuses(),
|
||||
'priorities' => $this->orderedPriorities(),
|
||||
'categories' => $this->orderedCategories(),
|
||||
'teams' => $this->orderedTeams(),
|
||||
'teamUsers' => User::query()
|
||||
->orderBy('name')
|
||||
->get(['id', 'name', 'email', 'helpdesk_agent', 'helpdesk_admin']),
|
||||
'projects' => $this->orderedProjects(),
|
||||
'boardOwners' => User::query()->where(static function ($query): void {
|
||||
$query->where('helpdesk_agent', true)->orWhere('helpdesk_admin', true);
|
||||
})->orderBy('name')->get(['id', 'name', 'email']),
|
||||
'boards' => KanbanBoard::query()
|
||||
->with(['statuses', 'owner:id,name,email'])
|
||||
->withCount('tickets')
|
||||
->orderBy('sort_order')
|
||||
->orderBy('name')
|
||||
->paginate(10, ['*'], 'boardsPage'),
|
||||
'repositories' => GitRepository::query()
|
||||
->with(['project'])
|
||||
->withCount(['commits', 'webhookLogs'])
|
||||
->orderBy('name')
|
||||
->paginate(10, ['*'], 'gitPage'),
|
||||
'workflowTemplates' => WorkflowTemplate::query()
|
||||
->orderBy('event')
|
||||
->orderBy('name')
|
||||
->paginate(10, ['*'], 'workflowPage'),
|
||||
'cannedResponses' => CannedResponse::query()
|
||||
->with(['category', 'team'])
|
||||
->orderBy('sort_order')
|
||||
->orderBy('name')
|
||||
->paginate(10, ['*'], 'cannedPage'),
|
||||
'slaPolicies' => SlaPolicy::query()
|
||||
->with(['priority', 'category'])
|
||||
->orderByDesc('is_default')
|
||||
->orderBy('name')
|
||||
->paginate(10, ['*'], 'slaPage'),
|
||||
'automationRules' => AutomationRule::query()
|
||||
->orderBy('sort_order')
|
||||
->orderBy('name')
|
||||
->paginate(10, ['*'], 'rulesPage'),
|
||||
'products' => Product::query()
|
||||
->withCount('tickets')
|
||||
->orderBy('name')
|
||||
->paginate(10, ['*'], 'productsPage'),
|
||||
'tags' => Tag::query()
|
||||
->orderBy('name')
|
||||
->paginate(10, ['*'], 'tagsPage'),
|
||||
'checklistTemplates' => ChecklistTemplate::query()
|
||||
->orderBy('name')
|
||||
->paginate(10, ['*'], 'checksPage'),
|
||||
'colourOptions' => Color::options(),
|
||||
'statuses' => $this->orderedStatuses(),
|
||||
'priorities' => $this->orderedPriorities(),
|
||||
'categories' => $this->orderedCategories(),
|
||||
'teams' => $this->orderedTeams(),
|
||||
'teamUsers' => User::query()
|
||||
->orderBy('name')
|
||||
->get(['id', 'name', 'email', 'helpdesk_agent', 'helpdesk_admin']),
|
||||
'projects' => $this->orderedProjects(),
|
||||
'boardOwners' => User::query()->where(static function ($query): void {
|
||||
$query->where('helpdesk_agent', true)->orWhere('helpdesk_admin', true);
|
||||
})->orderBy('name')->get(['id', 'name', 'email']),
|
||||
'boards' => KanbanBoard::query()
|
||||
->with(['statuses', 'owner:id,name,email'])
|
||||
->withCount('tickets')
|
||||
->orderBy('sort_order')
|
||||
->orderBy('name')
|
||||
->paginate(10, ['*'], 'boardsPage'),
|
||||
'repositories' => GitRepository::query()
|
||||
->with(['project'])
|
||||
->withCount(['commits', 'webhookLogs'])
|
||||
->orderBy('name')
|
||||
->paginate(10, ['*'], 'gitPage'),
|
||||
'workflowTemplates' => WorkflowTemplate::query()
|
||||
->orderBy('event')
|
||||
->orderBy('name')
|
||||
->paginate(10, ['*'], 'workflowPage'),
|
||||
'cannedResponses' => CannedResponse::query()
|
||||
->with(['category', 'team'])
|
||||
->orderBy('sort_order')
|
||||
->orderBy('name')
|
||||
->paginate(10, ['*'], 'cannedPage'),
|
||||
'slaPolicies' => SlaPolicy::query()
|
||||
->with(['priority', 'category'])
|
||||
->orderByDesc('is_default')
|
||||
->orderBy('name')
|
||||
->paginate(10, ['*'], 'slaPage'),
|
||||
'automationRules' => AutomationRule::query()
|
||||
->orderBy('sort_order')
|
||||
->orderBy('name')
|
||||
->paginate(10, ['*'], 'rulesPage'),
|
||||
'products' => Product::query()
|
||||
->withCount('tickets')
|
||||
->orderBy('name')
|
||||
->paginate(10, ['*'], 'productsPage'),
|
||||
'tags' => Tag::query()
|
||||
->orderBy('name')
|
||||
->paginate(10, ['*'], 'tagsPage'),
|
||||
'checklistTemplates' => ChecklistTemplate::query()
|
||||
->orderBy('name')
|
||||
->paginate(10, ['*'], 'checksPage'),
|
||||
'colourOptions' => Color::options(),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Modules\Helpdesk\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
final class LegacyCategory extends Model
|
||||
{
|
||||
protected $table = 'helpdesk_legacy_categories';
|
||||
|
||||
protected $guarded = [];
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Modules\Helpdesk\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
final class LegacyComment extends Model
|
||||
{
|
||||
protected $table = 'helpdesk_legacy_comments';
|
||||
|
||||
protected $guarded = [];
|
||||
|
||||
protected $casts = ['legacy_created_at' => 'datetime', 'legacy_updated_at' => 'datetime'];
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Modules\Helpdesk\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
|
||||
final class LegacyTicket extends Model
|
||||
{
|
||||
protected $table = 'helpdesk_legacy_tickets';
|
||||
|
||||
protected $guarded = [];
|
||||
|
||||
protected $casts = ['legacy_data' => 'array', 'legacy_created_at' => 'datetime', 'legacy_updated_at' => 'datetime', 'completed_at' => 'datetime', 'archived_at' => 'datetime'];
|
||||
|
||||
public function comments(): HasMany
|
||||
{
|
||||
return $this->hasMany(LegacyComment::class, 'legacy_ticket_id', 'legacy_id')->orderBy('legacy_created_at');
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,6 @@ declare(strict_types=1);
|
||||
namespace Modules\Helpdesk\Models;
|
||||
|
||||
use App\Models\User;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
|
||||
@@ -62,7 +62,6 @@ final class Ticket extends Model
|
||||
return $this->belongsTo(User::class, 'user_id');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Compatibility alias for the requester.
|
||||
*
|
||||
|
||||
@@ -1439,3 +1439,72 @@ html:not(.dark) .helpdesk-ticket-form select:-webkit-autofill:focus {
|
||||
html:not(.dark) .hd-helpdesk-surface {
|
||||
color: #1f2937;
|
||||
}
|
||||
|
||||
/* Professional theme contract: readable contrast in both application modes. */
|
||||
html:not(.dark) .hd-helpdesk-surface {
|
||||
color: #18181b !important;
|
||||
}
|
||||
html:not(.dark) .hd-helpdesk-surface :is(.text-zinc-100,.text-zinc-200,.text-zinc-300,.text-zinc-400,.text-zinc-500,.text-zinc-600,.text-zinc-700,.text-zinc-900) {
|
||||
color: #3f3f46 !important;
|
||||
}
|
||||
html:not(.dark) .hd-helpdesk-surface :is(h1,h2,h3,h4,.font-semibold,.font-bold,.font-black):not(.hd-btn):not([class*="text-white"]) {
|
||||
color: #18181b;
|
||||
}
|
||||
html:not(.dark) .hd-helpdesk-surface .text-blue-100\/90,
|
||||
html:not(.dark) .hd-helpdesk-surface .text-blue-100,
|
||||
html:not(.dark) .hd-helpdesk-surface .text-blue-200,
|
||||
html:not(.dark) .hd-helpdesk-surface .text-amber-100\/85,
|
||||
html:not(.dark) .hd-helpdesk-surface .text-amber-100,
|
||||
html:not(.dark) .hd-helpdesk-surface .text-amber-200 {
|
||||
color: #475569 !important;
|
||||
}
|
||||
|
||||
/* Heroes are light in light mode and intentionally dark in dark mode. */
|
||||
html:not(.dark) .hd-helpdesk-surface :is(.hd-page-hero,.hd-settings-hero-inner) {
|
||||
background: linear-gradient(135deg,#ffffff 0%,#f8fafc 55%,#eef4ff 100%) !important;
|
||||
color: #18181b !important;
|
||||
}
|
||||
html.dark .hd-helpdesk-surface :is(.hd-page-hero,.hd-settings-hero-inner) {
|
||||
background: linear-gradient(135deg,#020617 0%,#0f172a 55%,#172554 100%) !important;
|
||||
color: #f8fafc !important;
|
||||
}
|
||||
html:not(.dark) .hd-helpdesk-surface :is(.hd-page-hero,.hd-settings-hero-inner) :is(h1,h2,h3) { color:#18181b !important; }
|
||||
html:not(.dark) .hd-helpdesk-surface :is(.hd-page-hero,.hd-settings-hero-inner) p { color:#475569 !important; }
|
||||
html.dark .hd-helpdesk-surface :is(.hd-page-hero,.hd-settings-hero-inner) :is(h1,h2,h3) { color:#f8fafc !important; }
|
||||
html.dark .hd-helpdesk-surface :is(.hd-page-hero,.hd-settings-hero-inner) p { color:#cbd5e1 !important; }
|
||||
|
||||
/* Search/filter surface follows the switch instead of remaining black. */
|
||||
html:not(.dark) .hd-helpdesk-surface .hd-filter-panel {
|
||||
background:#ffffff !important; border-color:#d4d4d8 !important; color:#18181b !important;
|
||||
}
|
||||
html.dark .hd-helpdesk-surface .hd-filter-panel {
|
||||
background:#18181b !important; border-color:#3f3f46 !important; color:#f4f4f5 !important;
|
||||
}
|
||||
html:not(.dark) .hd-ticket-search,
|
||||
html:not(.dark) .hd-ticket-search-wrap { background:#fff !important; color:#18181b !important; border-color:#cbd5e1 !important; }
|
||||
html:not(.dark) .hd-ticket-search::placeholder { color:#71717a !important; opacity:1; }
|
||||
html:not(.dark) .hd-ticket-search-icon { color:#52525b !important; }
|
||||
html.dark .hd-ticket-search,
|
||||
html.dark .hd-ticket-search-wrap { background:#09090b !important; color:#f4f4f5 !important; border-color:#3f3f46 !important; }
|
||||
html.dark .hd-ticket-search::placeholder { color:#a1a1aa !important; opacity:1; }
|
||||
html.dark .hd-ticket-search-icon { color:#a1a1aa !important; }
|
||||
|
||||
/* Tables: body copy must never fade into its background. */
|
||||
html:not(.dark) .hd-helpdesk-surface table tbody { color:#27272a !important; }
|
||||
html:not(.dark) .hd-helpdesk-surface table tbody :is(.text-zinc-500,.text-zinc-600,.text-zinc-700) { color:#52525b !important; }
|
||||
html:not(.dark) .hd-helpdesk-surface table tbody :is(.font-medium,.font-semibold) { color:#18181b !important; }
|
||||
html.dark .hd-helpdesk-surface table tbody { color:#e4e4e7 !important; }
|
||||
html.dark .hd-helpdesk-surface table tbody :is(.text-zinc-400,.text-zinc-500,.text-zinc-600,.text-zinc-700) { color:#a1a1aa !important; }
|
||||
html.dark .hd-helpdesk-surface table tbody :is(.font-medium,.font-semibold) { color:#f4f4f5 !important; }
|
||||
|
||||
/* Settings navigation cards use dark copy on translucent pastel cards in light mode. */
|
||||
.hd-settings-section-card { border-color:var(--hd-card-border) !important; background:var(--hd-card-bg) !important; }
|
||||
html:not(.dark) .hd-settings-section-card { color:#18181b !important; box-shadow:0 8px 20px rgba(15,23,42,.08) !important; }
|
||||
html:not(.dark) .hd-settings-section-card.is-active { color:#fff !important; background:var(--hd-card-active) !important; }
|
||||
html.dark .hd-settings-section-card { color:#f8fafc !important; }
|
||||
html.dark .hd-settings-section-card.is-active { background:var(--hd-card-active) !important; }
|
||||
.hd-settings-section-card > div:first-child { opacity:.82 !important; }
|
||||
|
||||
/* Muted text remains secondary, but readable. */
|
||||
html:not(.dark) .hd-helpdesk-surface .hd-muted { color:#52525b !important; }
|
||||
html.dark .hd-helpdesk-surface .hd-muted { color:#a1a1aa !important; }
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
<x-layouts::app :title="__('Legacy Categories')">
|
||||
<div class="hd-helpdesk-surface hd-mobile-ready space-y-6">
|
||||
<div class="overflow-hidden rounded-3xl border border-zinc-200 bg-white shadow-sm dark:border-zinc-700 dark:bg-zinc-900"><div class="bg-gradient-to-br from-slate-950 via-slate-900 to-blue-950 px-6 py-7 text-white"><p class="text-xs font-semibold uppercase tracking-[0.28em] text-blue-200">Legacy System</p><h1 class="mt-2 text-3xl font-semibold tracking-tight">Legacy Categories</h1><p class="mt-2 text-sm text-blue-100/90">Categories retained from the previous Helpdesk.</p></div></div>
|
||||
<div class="overflow-hidden rounded-2xl border border-zinc-200 bg-white shadow-sm dark:border-zinc-700 dark:bg-zinc-900"><table class="w-full text-left text-sm"><thead class="border-b border-zinc-200 bg-zinc-50 text-xs uppercase text-zinc-500 dark:border-zinc-700 dark:bg-zinc-800/60"><tr><th class="px-5 py-3">Category</th><th class="px-5 py-3">Legacy ID</th><th class="px-5 py-3 text-right">Tickets</th></tr></thead><tbody class="divide-y divide-zinc-200 dark:divide-zinc-800">@forelse($categories as $category)<tr><td class="px-5 py-4"><a class="font-semibold text-blue-600 hover:underline" href="{{ route('helpdesk.legacy.tickets', ['category' => $category->legacy_id]) }}" wire:navigate>{{ $category->name }}</a></td><td class="px-5 py-4 text-zinc-500">{{ $category->legacy_id }}</td><td class="px-5 py-4 text-right">{{ $category->ticket_count }}</td></tr>@empty<tr><td colspan="3" class="px-5 py-10 text-center text-zinc-500">No legacy categories have been imported.</td></tr>@endforelse</tbody></table>@if($categories->hasPages())<div class="border-t border-zinc-200 p-4 dark:border-zinc-700">{{ $categories->links() }}</div>@endif</div>
|
||||
</div>
|
||||
</x-layouts::app>
|
||||
@@ -0,0 +1,6 @@
|
||||
<x-layouts::app :title="$ticket->reference ?: 'Legacy Ticket #'.$ticket->legacy_id">
|
||||
<div class="hd-helpdesk-surface hd-mobile-ready space-y-6">
|
||||
<div class="overflow-hidden rounded-3xl border border-zinc-200 bg-white shadow-sm dark:border-zinc-700 dark:bg-zinc-900"><div class="bg-gradient-to-br from-slate-950 via-slate-900 to-blue-950 px-6 py-7 text-white"><div class="flex items-start justify-between gap-4"><div><p class="text-xs font-semibold uppercase tracking-[0.28em] text-blue-200">Legacy System · Read only</p><h1 class="mt-2 text-3xl font-semibold tracking-tight">{{ $ticket->subject }}</h1><p class="mt-2 text-sm text-blue-100/90">{{ $ticket->reference ?: 'Legacy ticket #'.$ticket->legacy_id }}</p></div><a href="{{ route('helpdesk.legacy.tickets') }}" wire:navigate class="hd-btn hd-btn-blue"><i class="fa-solid fa-arrow-left"></i><span>Legacy Tickets</span></a></div></div></div>
|
||||
<div class="grid gap-6 xl:grid-cols-[1fr_320px]"><div class="space-y-6"><section class="rounded-2xl border border-zinc-200 bg-white p-6 shadow-sm dark:border-zinc-700 dark:bg-zinc-900"><h2 class="mb-4 text-lg font-semibold">Original request</h2><div class="prose max-w-none dark:prose-invert">{!! $ticket->html_content ?: nl2br(e($ticket->content ?: 'No content recorded.')) !!}</div></section>@if($ticket->comments->isNotEmpty())<section class="rounded-2xl border border-zinc-200 bg-white p-6 shadow-sm dark:border-zinc-700 dark:bg-zinc-900"><h2 class="mb-4 text-lg font-semibold">Comments</h2><div class="space-y-4">@foreach($ticket->comments as $comment)<article class="rounded-xl border border-zinc-200 p-4 dark:border-zinc-700"><div class="mb-2 flex justify-between text-xs text-zinc-500"><strong>{{ $comment->author_name ?: 'Legacy user' }}</strong><span>{{ $comment->legacy_created_at?->format('d M Y H:i') }}</span></div><div class="prose max-w-none text-sm dark:prose-invert">{!! $comment->html_content ?: nl2br(e($comment->content ?: '')) !!}</div></article>@endforeach</div></section>@endif</div><aside><div class="rounded-2xl border border-zinc-200 bg-white p-5 shadow-sm dark:border-zinc-700 dark:bg-zinc-900"><h2 class="mb-4 font-semibold">Legacy details</h2><dl class="space-y-3 text-sm">@foreach(['Category'=>$ticket->category_name,'Status'=>$ticket->status_name,'Priority'=>$ticket->priority_name,'Requester'=>$ticket->requester_name,'Agent'=>$ticket->agent_name,'Project'=>$ticket->project_name] as $label=>$value)<div><dt class="text-xs uppercase tracking-wide text-zinc-500">{{ $label }}</dt><dd class="mt-1 font-medium">{{ $value ?: '—' }}</dd></div>@endforeach<div><dt class="text-xs uppercase tracking-wide text-zinc-500">Created</dt><dd class="mt-1 font-medium">{{ $ticket->legacy_created_at?->format('d M Y H:i') ?: '—' }}</dd></div></dl></div></aside></div>
|
||||
</div>
|
||||
</x-layouts::app>
|
||||
@@ -0,0 +1,78 @@
|
||||
<x-layouts::app :title="__('Legacy Tickets')">
|
||||
<div class="hd-helpdesk-surface hd-mobile-ready space-y-6">
|
||||
<div class="overflow-hidden rounded-3xl border border-zinc-200 bg-white shadow-sm dark:border-zinc-700 dark:bg-zinc-900">
|
||||
<div class="bg-gradient-to-br from-slate-950 via-slate-900 to-blue-950 px-6 py-7 text-white">
|
||||
<p class="text-xs font-semibold uppercase tracking-[0.28em] text-blue-200">Legacy System</p>
|
||||
<h1 class="mt-2 text-3xl font-semibold tracking-tight">Legacy Tickets</h1>
|
||||
<p class="mt-2 text-sm text-blue-100/90">Historical tickets from the previous Helpdesk. These records are read-only.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="rounded-2xl border border-zinc-200 bg-white p-4 shadow-sm dark:border-zinc-700 dark:bg-zinc-900">
|
||||
<form class="grid gap-3 md:grid-cols-[1fr_260px_auto]" method="GET">
|
||||
<input class="hd-ticket-search" type="search" name="search" value="{{ $search }}" placeholder="Search reference, subject or requester">
|
||||
<select class="hd-select" name="category"><option value="">All legacy categories</option>@foreach($categories as $category)<option value="{{ $category->legacy_id }}" @selected($selectedCategory === $category->legacy_id)>{{ $category->name }}</option>@endforeach</select>
|
||||
<button class="hd-btn hd-btn-blue" type="submit"><i class="fa-solid fa-magnifying-glass"></i><span>Search</span></button>
|
||||
</form>
|
||||
</div>
|
||||
<div class="overflow-hidden rounded-2xl border border-zinc-200 bg-white shadow-sm dark:border-zinc-700 dark:bg-zinc-900">
|
||||
<div class="overflow-x-auto"><table class="w-full text-left text-sm"><thead class="border-b border-zinc-200 bg-zinc-50 text-xs uppercase text-zinc-500 dark:border-zinc-700 dark:bg-zinc-800/60"><tr><th class="px-5 py-3">Reference</th><th class="px-5 py-3">Subject</th><th class="px-5 py-3">Category</th><th class="px-5 py-3">Status</th><th class="px-5 py-3">Requester</th><th class="px-5 py-3">Created</th></tr></thead><tbody class="divide-y divide-zinc-200 dark:divide-zinc-800">@forelse($tickets as $ticket)
|
||||
<tr class="transition-colors dark:hover:bg-zinc-800/30">
|
||||
<td class="px-5 py-4"><a class="font-semibold text-blue-600 hover:underline" href="{{ route('helpdesk.legacy.tickets.show', $ticket) }}" wire:navigate>{{ $ticket->reference ?: '#'.$ticket->legacy_id }}</a></td><td class="px-5 py-4 font-medium">{{ $ticket->subject }}</td><td class="px-5 py-4">{{ $ticket->category_name ?: '—' }}</td><td class="px-5 py-4">{{ $ticket->status_name ?: '—' }}</td><td class="px-5 py-4">{{ $ticket->requester_name ?: '—' }}</td><td class="px-5 py-4 text-zinc-500">{{ $ticket->legacy_created_at?->format('d M Y H:i') ?: '—' }}</td></tr>@empty<tr><td class="px-5 py-10 text-center text-zinc-500" colspan="6">No legacy tickets have been imported.</td></tr>@endforelse</tbody></table></div>
|
||||
@if($tickets->hasPages())
|
||||
<div class="flex items-center justify-between border-t border-zinc-800 px-5 py-4">
|
||||
|
||||
{{-- Previous --}}
|
||||
@if($tickets->onFirstPage())
|
||||
<span
|
||||
class="inline-flex cursor-not-allowed items-center rounded-lg border border-zinc-700 bg-zinc-900 px-4 py-2 text-sm font-medium text-zinc-600"
|
||||
>
|
||||
<i class="fa-solid fa-chevron-left mr-2 text-xs"></i>
|
||||
Previous
|
||||
</span>
|
||||
@else
|
||||
<a
|
||||
href="{{ $tickets->previousPageUrl() }}"
|
||||
class="inline-flex items-center rounded-lg border border-zinc-700 bg-zinc-900 px-4 py-2 text-sm font-medium text-zinc-300 transition hover:border-zinc-600 hover:bg-zinc-800 hover:text-white"
|
||||
wire:navigate
|
||||
>
|
||||
<i class="fa-solid fa-chevron-left mr-2 text-xs"></i>
|
||||
Previous
|
||||
</a>
|
||||
@endif
|
||||
|
||||
{{-- Page information --}}
|
||||
<div class="text-sm text-zinc-500">
|
||||
Page
|
||||
<span class="font-semibold text-zinc-300">
|
||||
{{ $tickets->currentPage() }}
|
||||
</span>
|
||||
of
|
||||
<span class="font-semibold text-zinc-300">
|
||||
{{ $tickets->lastPage() }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{{-- Next --}}
|
||||
@if($tickets->hasMorePages())
|
||||
<a
|
||||
href="{{ $tickets->nextPageUrl() }}"
|
||||
class="inline-flex items-center rounded-lg border border-zinc-700 bg-zinc-900 px-4 py-2 text-sm font-medium text-zinc-300 transition hover:border-zinc-600 hover:bg-zinc-800 hover:text-white"
|
||||
wire:navigate
|
||||
>
|
||||
Next
|
||||
<i class="fa-solid fa-chevron-right ml-2 text-xs"></i>
|
||||
</a>
|
||||
@else
|
||||
<span
|
||||
class="inline-flex cursor-not-allowed items-center rounded-lg border border-zinc-700 bg-zinc-900 px-4 py-2 text-sm font-medium text-zinc-600"
|
||||
>
|
||||
Next
|
||||
<i class="fa-solid fa-chevron-right ml-2 text-xs"></i>
|
||||
</span>
|
||||
@endif
|
||||
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</x-layouts::app>
|
||||
@@ -5,6 +5,7 @@ declare(strict_types=1);
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Modules\Helpdesk\Http\Controllers\AttachmentDownloadController;
|
||||
use Modules\Helpdesk\Http\Controllers\HelpdeskController;
|
||||
use Modules\Helpdesk\Http\Controllers\LegacySystemController;
|
||||
use Modules\Helpdesk\Http\Controllers\TicketAttachmentStoreController;
|
||||
use Modules\Helpdesk\Http\Controllers\TicketBoardController;
|
||||
use Modules\Helpdesk\Http\Controllers\TicketCommentDeleteController;
|
||||
@@ -28,6 +29,15 @@ Route::get('/', HelpdeskController::class)->name('index');
|
||||
Route::get('/settings', SettingsManager::class)->name('settings');
|
||||
Route::get('/kanban', KanbanBoard::class)->name('kanban');
|
||||
|
||||
if (config('helpdesk.legacy.enabled', false)) {
|
||||
Route::get('/legacy/tickets', [LegacySystemController::class, 'tickets'])
|
||||
->name('legacy.tickets');
|
||||
Route::get('/legacy/tickets/{ticket}', [LegacySystemController::class, 'show'])
|
||||
->name('legacy.tickets.show');
|
||||
Route::get('/legacy/categories', [LegacySystemController::class, 'categories'])
|
||||
->name('legacy.categories');
|
||||
}
|
||||
|
||||
Route::get('/tickets', TicketIndex::class)->name('tickets.index');
|
||||
Route::get('/tickets/archived', ArchivedTicketIndex::class)->name('tickets.archived');
|
||||
Route::post('/tickets', TicketStoreController::class)->name('tickets.store');
|
||||
|
||||
@@ -11,7 +11,6 @@ use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Str;
|
||||
use RuntimeException;
|
||||
use Throwable;
|
||||
|
||||
final class HelpdeskSyncService
|
||||
{
|
||||
@@ -262,7 +261,7 @@ final class HelpdeskSyncService
|
||||
}
|
||||
|
||||
/**
|
||||
* @param list<string> $tables
|
||||
* @param list<string> $tables
|
||||
* @return list<string>
|
||||
*/
|
||||
private function existingTables(array $tables): array
|
||||
@@ -293,7 +292,7 @@ final class HelpdeskSyncService
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, list<array<string, mixed>>> $tables
|
||||
* @param array<string, list<array<string, mixed>>> $tables
|
||||
* @return list<array<string, mixed>>
|
||||
*/
|
||||
private function exportUsers(array $tables): array
|
||||
@@ -357,7 +356,7 @@ final class HelpdeskSyncService
|
||||
}
|
||||
|
||||
/**
|
||||
* @param list<array<string, mixed>> $users
|
||||
* @param list<array<string, mixed>> $users
|
||||
* @return array<int, int>
|
||||
*/
|
||||
private function importUsers(array $users): array
|
||||
@@ -436,8 +435,8 @@ final class HelpdeskSyncService
|
||||
}
|
||||
|
||||
/**
|
||||
* @param list<array<string, mixed>> $rows
|
||||
* @param array<int, int> $userMap
|
||||
* @param list<array<string, mixed>> $rows
|
||||
* @param array<int, int> $userMap
|
||||
*/
|
||||
private function importTable(string $table, array $rows, array $userMap, bool $mirror): void
|
||||
{
|
||||
@@ -481,8 +480,8 @@ final class HelpdeskSyncService
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $row
|
||||
* @param array<int, int> $userMap
|
||||
* @param array<string, mixed> $row
|
||||
* @param array<int, int> $userMap
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
private function remapUserColumns(array $row, array $userMap): array
|
||||
@@ -503,7 +502,7 @@ final class HelpdeskSyncService
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $row
|
||||
* @param array<string, mixed> $row
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
private function compositeKey(string $table, array $row): array
|
||||
@@ -533,7 +532,7 @@ final class HelpdeskSyncService
|
||||
}
|
||||
|
||||
/**
|
||||
* @param list<array<string, mixed>> $attachments
|
||||
* @param list<array<string, mixed>> $attachments
|
||||
* @return list<array<string, mixed>>
|
||||
*/
|
||||
private function exportAttachmentFiles(array $attachments): array
|
||||
@@ -569,7 +568,7 @@ final class HelpdeskSyncService
|
||||
}
|
||||
|
||||
/**
|
||||
* @param list<array<string, mixed>> $files
|
||||
* @param list<array<string, mixed>> $files
|
||||
*/
|
||||
private function importAttachmentFiles(array $files): int
|
||||
{
|
||||
|
||||
@@ -120,7 +120,7 @@ final class UserController extends Controller
|
||||
public function createRole(): View
|
||||
{
|
||||
return view('modules.user-management.role-form', [
|
||||
'role' => new Role(),
|
||||
'role' => new Role,
|
||||
'permissions' => Permission::query()->orderBy('name')->get(),
|
||||
]);
|
||||
}
|
||||
@@ -165,7 +165,7 @@ final class UserController extends Controller
|
||||
|
||||
public function createPermission(): View
|
||||
{
|
||||
return view('modules.user-management.permission-form', ['permission' => new Permission()]);
|
||||
return view('modules.user-management.permission-form', ['permission' => new Permission]);
|
||||
}
|
||||
|
||||
public function storePermission(Request $request): RedirectResponse
|
||||
|
||||
@@ -18,5 +18,4 @@ class Appearance extends Component
|
||||
resource_path('themes/backend/views/livewire/settings/appearance.blade.php')
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
namespace App\Livewire\Settings;
|
||||
|
||||
use Illuminate\Contracts\View\View;
|
||||
use App\Concerns\PasswordValidationRules;
|
||||
use App\Livewire\Actions\Logout;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Livewire\Component;
|
||||
|
||||
@@ -27,11 +27,11 @@ class DeleteUserForm extends Component
|
||||
|
||||
$this->redirect('/', navigate: true);
|
||||
}
|
||||
|
||||
public function render(): View
|
||||
{
|
||||
return view()->file(
|
||||
resource_path('themes/backend/views/livewire/settings/delete-user-form.blade.php')
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
|
||||
namespace App\Livewire\Settings;
|
||||
|
||||
use Illuminate\Contracts\View\View;
|
||||
use App\Concerns\ProfileValidationRules;
|
||||
use Flux\Flux;
|
||||
use Illuminate\Contracts\Auth\MustVerifyEmail;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Livewire\Attributes\Layout;
|
||||
use Livewire\Attributes\Computed;
|
||||
use Livewire\Attributes\Layout;
|
||||
use Livewire\Attributes\Title;
|
||||
use Livewire\Component;
|
||||
|
||||
@@ -83,6 +83,7 @@ class Profile extends Component
|
||||
|
||||
return ! $user instanceof MustVerifyEmail || $user->hasVerifiedEmail();
|
||||
}
|
||||
|
||||
#[Layout('layouts.app')]
|
||||
public function render(): View
|
||||
{
|
||||
@@ -90,5 +91,4 @@ class Profile extends Component
|
||||
resource_path('themes/backend/views/livewire/settings/profile.blade.php')
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
|
||||
namespace App\Livewire\Settings;
|
||||
|
||||
use Illuminate\Contracts\View\View;
|
||||
use App\Concerns\PasswordValidationRules;
|
||||
use Exception;
|
||||
use Flux\Flux;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Laravel\Fortify\Actions\ConfirmTwoFactorAuthentication;
|
||||
@@ -14,8 +14,8 @@ use Laravel\Fortify\Actions\EnableTwoFactorAuthentication;
|
||||
use Laravel\Fortify\Features;
|
||||
use Laravel\Fortify\Fortify;
|
||||
use Laravel\Passkeys\Actions\DeletePasskey;
|
||||
use Livewire\Attributes\Layout;
|
||||
use Livewire\Attributes\Computed;
|
||||
use Livewire\Attributes\Layout;
|
||||
use Livewire\Attributes\Locked;
|
||||
use Livewire\Attributes\Title;
|
||||
use Livewire\Attributes\Validate;
|
||||
@@ -311,6 +311,7 @@ class Security extends Component
|
||||
'buttonText' => __('Continue'),
|
||||
];
|
||||
}
|
||||
|
||||
#[Layout('layouts.app')]
|
||||
public function render(): View
|
||||
{
|
||||
@@ -318,5 +319,4 @@ class Security extends Component
|
||||
resource_path('themes/backend/views/livewire/settings/security.blade.php')
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
namespace App\Livewire\Settings\TwoFactor;
|
||||
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Exception;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Laravel\Fortify\Actions\GenerateNewRecoveryCodes;
|
||||
use Livewire\Attributes\Locked;
|
||||
use Livewire\Component;
|
||||
@@ -49,11 +49,11 @@ class RecoveryCodes extends Component
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function render(): View
|
||||
{
|
||||
return view()->file(
|
||||
resource_path('themes/backend/views/livewire/settings/two-factor/recovery-codes.blade.php')
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
-3
@@ -6,6 +6,7 @@ use Database\Factories\UserFactory;
|
||||
use Illuminate\Database\Eloquent\Attributes\Fillable;
|
||||
use Illuminate\Database\Eloquent\Attributes\Hidden;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
use Illuminate\Support\Carbon;
|
||||
@@ -14,7 +15,6 @@ use Laravel\Fortify\Contracts\PasskeyUser;
|
||||
use Laravel\Fortify\PasskeyAuthenticatable;
|
||||
use Laravel\Fortify\TwoFactorAuthenticatable;
|
||||
use Modules\UserManagement\Models\Role;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
@@ -50,8 +50,6 @@ class User extends Authenticatable implements PasskeyUser
|
||||
: $initials;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function gravatarUrl(int $size = 160): string
|
||||
{
|
||||
$email = strtolower(trim((string) $this->email));
|
||||
|
||||
+14
-1
@@ -83,7 +83,20 @@ return [
|
||||
Mysql::ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
|
||||
]) : [],
|
||||
],
|
||||
|
||||
'helpdesk_legacy' => [
|
||||
'driver' => 'mysql',
|
||||
'host' => env('LEGACY_DB_HOST', '127.0.0.1'),
|
||||
'port' => env('LEGACY_DB_PORT', '3306'),
|
||||
'database' => env('LEGACY_DB_DATABASE'),
|
||||
'username' => env('LEGACY_DB_USERNAME'),
|
||||
'password' => env('LEGACY_DB_PASSWORD'),
|
||||
'unix_socket' => env('LEGACY_DB_SOCKET', ''),
|
||||
'charset' => 'utf8mb4',
|
||||
'collation' => 'utf8mb4_unicode_ci',
|
||||
'prefix' => '',
|
||||
'strict' => true,
|
||||
'engine' => null,
|
||||
],
|
||||
'pgsql' => [
|
||||
'driver' => 'pgsql',
|
||||
'url' => env('DB_URL'),
|
||||
|
||||
+7
-1
@@ -23,11 +23,17 @@ host('main')
|
||||
->set('deploy_path', '/var/www/helpdesk');
|
||||
|
||||
host('develop')
|
||||
->set('hostname', 'helpdesk.mlba.dev')
|
||||
->set('hostname', 'helpdesk.mpba.dev')
|
||||
->set('remote_user', 'mag')
|
||||
->set('branch', 'develop')
|
||||
->set('deploy_path', '/var/www/helpdesk_dev');
|
||||
|
||||
host('mpba')
|
||||
->set('hostname', 'helpdesk.mpba.dev')
|
||||
->set('remote_user', 'mag')
|
||||
->set('branch', 'main')
|
||||
->set('deploy_path', '/var/www/helpdesk_mpba');
|
||||
|
||||
/*
|
||||
* Install the root npm tree, then every module that owns its own lock file,
|
||||
* then run ONE root Vite build. Because Vite is compiling a module source file,
|
||||
|
||||
@@ -1303,6 +1303,13 @@ span.flatpickr-weekday {
|
||||
.hd-shell-main { min-height:100vh; margin-left:var(--hd-sidebar-width); padding:calc(var(--hd-topbar-height) + 28px) 30px 34px; background:radial-gradient(circle at 75% 0,rgba(37,99,235,.07),transparent 35%),#0b0e13; transition:margin-left .08s linear; }
|
||||
.hd-sidebar-resizing,.hd-sidebar-resizing * { cursor:col-resize!important; user-select:none!important; }
|
||||
|
||||
|
||||
/* Consistent application icons */
|
||||
.hd-svg-icon { width:20px; height:20px; flex:0 0 20px; display:block; fill:currentColor; }
|
||||
.hd-icon-outline { fill:none; stroke:currentColor; stroke-width:1.8; stroke-linecap:round; stroke-linejoin:round; }
|
||||
.hd-range-select .hd-svg-icon { width:19px; height:19px; flex-basis:19px; color:#94a3b8; }
|
||||
.hd-metric-icon .hd-svg-icon { width:25px; height:25px; flex-basis:25px; }
|
||||
|
||||
/* ===== Dashboard ========================================================= */
|
||||
.hd-dashboard { max-width:1600px; margin:0 auto; }
|
||||
.hd-dashboard-heading { display:flex; align-items:center; justify-content:space-between; gap:18px; }
|
||||
@@ -2469,3 +2476,123 @@ html:not(.dark) .hd-appearance-choice.is-active { background: #fff; color: #1118
|
||||
.hd-account-settings-form { max-width: none; }
|
||||
.hd-ios12 .hd-settings-section-card { width: calc(50% - 8px) !important; min-width: 0 !important; }
|
||||
}
|
||||
|
||||
/* Legacy ticket table hover */
|
||||
.legacy-tickets-table tbody tr {
|
||||
transition: background-color 0.15s ease;
|
||||
}
|
||||
|
||||
.legacy-tickets-table tbody tr:hover,
|
||||
.legacy-tickets-table tbody tr:hover > td {
|
||||
background-color: rgba(255, 255, 255, 0.035) !important;
|
||||
color: inherit !important;
|
||||
}
|
||||
|
||||
.legacy-tickets-table tbody tr:hover td,
|
||||
.legacy-tickets-table tbody tr:hover td:not(:first-child) {
|
||||
color: var(--hd-text-primary, #e5e7eb) !important;
|
||||
}
|
||||
|
||||
.legacy-tickets-table tbody tr:hover a {
|
||||
color: #3b82f6 !important;
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
LIGHT APPEARANCE — COMPLETE MODULE SURFACE OVERRIDES
|
||||
Keep semantic/action colours, but remove hard-coded dark chrome.
|
||||
============================================================ */
|
||||
html:not(.dark) .hd-page-hero {
|
||||
background: linear-gradient(115deg,#ffffff,#eef4ff) !important;
|
||||
border-color:#d8dee7 !important;
|
||||
box-shadow:0 1px 2px rgba(15,23,42,.06) !important;
|
||||
}
|
||||
html:not(.dark) .hd-page-hero h1 { color:#111827 !important; }
|
||||
html:not(.dark) .hd-page-hero p { color:#667085 !important; }
|
||||
html:not(.dark) .hd-eyebrow { color:#41658f !important; }
|
||||
html:not(.dark) .hd-panel,
|
||||
html:not(.dark) .helpdesk-kanban-column,
|
||||
html:not(.dark) .hd-dashboard-card,
|
||||
html:not(.dark) .hd-role-card {
|
||||
background:#ffffff !important;
|
||||
border-color:#d8dee7 !important;
|
||||
color:#1f2937 !important;
|
||||
}
|
||||
html:not(.dark) .hd-toolbar,
|
||||
html:not(.dark) .hd-dashboard-card>header,
|
||||
html:not(.dark) .hd-latest-list>a,
|
||||
html:not(.dark) .hd-requester-list>div,
|
||||
html:not(.dark) .hd-table th,
|
||||
html:not(.dark) .hd-table td {
|
||||
border-color:#e2e8f0 !important;
|
||||
}
|
||||
html:not(.dark) .hd-toolbar { background:#f8fafc !important; }
|
||||
html:not(.dark) .hd-search-field {
|
||||
background:#ffffff !important;
|
||||
border-color:#cfd6e1 !important;
|
||||
color:#667085 !important;
|
||||
}
|
||||
html:not(.dark) .hd-search-field input { color:#1f2937 !important; }
|
||||
html:not(.dark) .hd-table th { background:#f3f5f8 !important; color:#667085 !important; }
|
||||
html:not(.dark) .hd-table td { background:#ffffff !important; color:#1f2937 !important; }
|
||||
html:not(.dark) .hd-table tbody tr:hover td { background:#f8fafc !important; }
|
||||
html:not(.dark) .hd-action:not(.hd-action-blue):not(.hd-action-green):not(.hd-action-red) {
|
||||
background:#ffffff !important; border-color:#cfd6e1 !important; color:#1f2937 !important;
|
||||
}
|
||||
html:not(.dark) .hd-role-card h2,
|
||||
html:not(.dark) .hd-role-card strong,
|
||||
html:not(.dark) .hd-dashboard-card>header h2 { color:#111827 !important; }
|
||||
html:not(.dark) .hd-role-card p,
|
||||
html:not(.dark) .hd-dashboard-card>header span,
|
||||
html:not(.dark) .hd-dashboard-card>header a,
|
||||
html:not(.dark) .hd-requester-list em,
|
||||
html:not(.dark) .hd-empty { color:#667085 !important; }
|
||||
html:not(.dark) .hd-metric-card {
|
||||
background:linear-gradient(145deg,#ffffff,#f8fafc) !important;
|
||||
border-color:#d8dee7 !important;
|
||||
box-shadow:0 8px 20px rgba(15,23,42,.07) !important;
|
||||
}
|
||||
html:not(.dark) .hd-donut:after { background:#ffffff !important; }
|
||||
html:not(.dark) .hd-donut span,
|
||||
html:not(.dark) .hd-priority-legend strong { color:#111827 !important; }
|
||||
html:not(.dark) .hd-priority-legend>div,
|
||||
html:not(.dark) .hd-latest-list>a { color:#374151 !important; }
|
||||
html:not(.dark) .hd-latest-list>a:hover { background:#f8fafc !important; }
|
||||
html:not(.dark) .hd-chart-grid-lines line { stroke:#d8dee7 !important; }
|
||||
html:not(.dark) .hd-form-grid .hd-field span { color:#374151 !important; }
|
||||
html:not(.dark) .hd-field input {
|
||||
background:#ffffff !important; color:#1f2937 !important; border-color:#cfd6e1 !important;
|
||||
}
|
||||
html:not(.dark) .hd-role-options label { background:#ffffff !important; border-color:#d8dee7 !important; }
|
||||
html:not(.dark) .hd-role-options small { color:#667085 !important; }
|
||||
html:not(.dark) .hd-kanban-drag-handle {
|
||||
background:#f3f5f8 !important; border-color:#d8dee7 !important; color:#667085 !important;
|
||||
}
|
||||
html:not(.dark) .hd-kanban-drag-handle:hover { background:#e9eef5 !important; color:#111827 !important; }
|
||||
|
||||
/* Tailwind utility surfaces used directly by Helpdesk Blade views. */
|
||||
html:not(.dark) .bg-black,
|
||||
html:not(.dark) .bg-slate-950,
|
||||
html:not(.dark) .bg-slate-900,
|
||||
html:not(.dark) .bg-slate-800,
|
||||
html:not(.dark) .bg-slate-700,
|
||||
html:not(.dark) .bg-slate-600,
|
||||
html:not(.dark) .bg-neutral-950,
|
||||
html:not(.dark) .bg-neutral-900,
|
||||
html:not(.dark) .bg-neutral-800 {
|
||||
background-color:#ffffff !important;
|
||||
}
|
||||
html:not(.dark) [class*="bg-slate-950/"],
|
||||
html:not(.dark) [class*="bg-slate-900/"],
|
||||
html:not(.dark) [class*="bg-black/"] { background-color:#ffffff !important; }
|
||||
html:not(.dark) [class*="border-slate-"],
|
||||
html:not(.dark) [class*="border-neutral-"] { border-color:#d8dee7 !important; }
|
||||
html:not(.dark) [class*="text-slate-100"],
|
||||
html:not(.dark) [class*="text-slate-200"],
|
||||
html:not(.dark) [class*="text-neutral-100"],
|
||||
html:not(.dark) [class*="text-neutral-200"] { color:#1f2937 !important; }
|
||||
html:not(.dark) [class*="text-slate-300"],
|
||||
html:not(.dark) [class*="text-neutral-300"] { color:#374151 !important; }
|
||||
html:not(.dark) [class*="text-slate-400"],
|
||||
html:not(.dark) [class*="text-slate-500"],
|
||||
html:not(.dark) [class*="text-neutral-400"],
|
||||
html:not(.dark) [class*="text-neutral-500"] { color:#667085 !important; }
|
||||
|
||||
@@ -143,6 +143,12 @@
|
||||
@if(Route::has('helpdesk.kanban'))<a class="hd-nav-link hd-nav-link--kanban {{ request()->routeIs('helpdesk.kanban') ? 'is-active' : '' }}" href="{{ route('helpdesk.kanban') }}" wire:navigate><svg class="hd-svg-icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M3 4h18v16H3V4zm2 2v12h6V6H5zm8 0v12h6V6h-6z"/></svg><span>Kanban</span></a>@endif
|
||||
@if(Route::has('helpdesk.settings'))<a class="hd-nav-link hd-nav-link--settings {{ request()->routeIs('helpdesk.settings*') ? 'is-active' : '' }}" href="{{ route('helpdesk.settings') }}" wire:navigate><svg class="hd-svg-icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M10.7 2h2.6l.6 2.3c.5.2 1 .5 1.5.9l2.3-.7 1.3 2.3-1.7 1.6c.1.5.2 1.1.2 1.6s-.1 1.1-.2 1.6l1.7 1.6-1.3 2.3-2.3-.7c-.5.4-1 .7-1.5.9l-.6 2.3h-2.6l-.6-2.3c-.5-.2-1-.5-1.5-.9l-2.3.7L5 13.2l1.7-1.6A6 6 0 0 1 6.5 10c0-.5.1-1.1.2-1.6L5 6.8l1.3-2.3 2.3.7c.5-.4 1-.7 1.5-.9L10.7 2zM12 7a3 3 0 1 0 0 6 3 3 0 0 0 0-6z"/></svg><span>Settings</span></a>@endif
|
||||
</div>
|
||||
@if(config('helpdesk.legacy.enabled', false) && Route::has('helpdesk.legacy.tickets'))
|
||||
<div class="hd-nav-section"><div class="hd-nav-heading">Legacy System</div>
|
||||
<a class="hd-nav-link {{ request()->routeIs('helpdesk.legacy.tickets*') ? 'is-active' : '' }}" style="--hd-nav-accent:#64748b;--hd-nav-accent-rgb:100,116,139" href="{{ route('helpdesk.legacy.tickets') }}" wire:navigate><i class="fa-solid fa-clock-rotate-left" aria-hidden="true"></i><span>Legacy Tickets</span></a>
|
||||
<a class="hd-nav-link {{ request()->routeIs('helpdesk.legacy.categories') ? 'is-active' : '' }}" style="--hd-nav-accent:#64748b;--hd-nav-accent-rgb:100,116,139" href="{{ route('helpdesk.legacy.categories') }}" wire:navigate><i class="fa-solid fa-folder-tree" aria-hidden="true"></i><span>Legacy Categories</span></a>
|
||||
</div>
|
||||
@endif
|
||||
@if(Route::has('documentation.index') || Route::has('documentation.documents.index'))
|
||||
<div class="hd-nav-section"><div class="hd-nav-heading">Documentation</div>
|
||||
<a class="hd-nav-link hd-nav-link--documents {{ request()->routeIs('documentation.documents.*') || request()->routeIs('documentation.index') ? 'is-active' : '' }}" href="{{ Route::has('documentation.documents.index') ? route('documentation.documents.index') : route('documentation.index') }}" wire:navigate><svg class="hd-svg-icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M6 2h8l4 4v16H6V2zm7 1.8V7h3.2L13 3.8zM9 11v1.5h6V11H9zm0 3.5V16h6v-1.5H9z"/></svg><span>Documents</span></a>
|
||||
|
||||
@@ -143,6 +143,12 @@
|
||||
@if(Route::has('helpdesk.kanban'))<a class="hd-nav-link hd-nav-link--kanban {{ request()->routeIs('helpdesk.kanban') ? 'is-active' : '' }}" href="{{ route('helpdesk.kanban') }}" wire:navigate><svg class="hd-svg-icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M3 4h18v16H3V4zm2 2v12h6V6H5zm8 0v12h6V6h-6z"/></svg><span>Kanban</span></a>@endif
|
||||
@if(Route::has('helpdesk.settings'))<a class="hd-nav-link hd-nav-link--settings {{ request()->routeIs('helpdesk.settings*') ? 'is-active' : '' }}" href="{{ route('helpdesk.settings') }}" wire:navigate><svg class="hd-svg-icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M10.7 2h2.6l.6 2.3c.5.2 1 .5 1.5.9l2.3-.7 1.3 2.3-1.7 1.6c.1.5.2 1.1.2 1.6s-.1 1.1-.2 1.6l1.7 1.6-1.3 2.3-2.3-.7c-.5.4-1 .7-1.5.9l-.6 2.3h-2.6l-.6-2.3c-.5-.2-1-.5-1.5-.9l-2.3.7L5 13.2l1.7-1.6A6 6 0 0 1 6.5 10c0-.5.1-1.1.2-1.6L5 6.8l1.3-2.3 2.3.7c.5-.4 1-.7 1.5-.9L10.7 2zM12 7a3 3 0 1 0 0 6 3 3 0 0 0 0-6z"/></svg><span>Settings</span></a>@endif
|
||||
</div>
|
||||
@if(config('helpdesk.legacy.enabled', false) && Route::has('helpdesk.legacy.tickets'))
|
||||
<div class="hd-nav-section"><div class="hd-nav-heading">Legacy System</div>
|
||||
<a class="hd-nav-link {{ request()->routeIs('helpdesk.legacy.tickets*') ? 'is-active' : '' }}" style="--hd-nav-accent:#64748b;--hd-nav-accent-rgb:100,116,139" href="{{ route('helpdesk.legacy.tickets') }}" wire:navigate><i class="fa-solid fa-clock-rotate-left" aria-hidden="true"></i><span>Legacy Tickets</span></a>
|
||||
<a class="hd-nav-link {{ request()->routeIs('helpdesk.legacy.categories') ? 'is-active' : '' }}" style="--hd-nav-accent:#64748b;--hd-nav-accent-rgb:100,116,139" href="{{ route('helpdesk.legacy.categories') }}" wire:navigate><i class="fa-solid fa-folder-tree" aria-hidden="true"></i><span>Legacy Categories</span></a>
|
||||
</div>
|
||||
@endif
|
||||
@if(Route::has('documentation.index') || Route::has('documentation.documents.index'))
|
||||
<div class="hd-nav-section"><div class="hd-nav-heading">Documentation</div>
|
||||
<a class="hd-nav-link hd-nav-link--documents {{ request()->routeIs('documentation.documents.*') || request()->routeIs('documentation.index') ? 'is-active' : '' }}" href="{{ Route::has('documentation.documents.index') ? route('documentation.documents.index') : route('documentation.index') }}" wire:navigate><svg class="hd-svg-icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M6 2h8l4 4v16H6V2zm7 1.8V7h3.2L13 3.8zM9 11v1.5h6V11H9zm0 3.5V16h6v-1.5H9z"/></svg><span>Documents</span></a>
|
||||
|
||||
@@ -95,14 +95,14 @@
|
||||
|
||||
@if(Route::has('helpdesk.settings'))
|
||||
<a href="{{ route('helpdesk.settings') }}" wire:navigate role="menuitem">
|
||||
<svg class="hd-svg-icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M10.7 2h2.6l.6 2.3c.5.2 1 .5 1.5.9l2.3-.7 1.3 2.3-1.7 1.6c.1.5.2 1.1.2 1.6s-.1 1.1-.2 1.6l1.7 1.6-1.3 2.3-2.3-.7c-.5.4-1 .7-1.5.9l-.6 2.3h-2.6l-.6-2.3c-.5-.2-1-.5-1.5-.9l-2.3.7L5 13.2l1.7-1.6A6 6 0 0 1 6.5 10c0-.5.1-1.1.2-1.6L5 6.8l1.3-2.3 2.3.7c.5-.4 1-.7 1.5-.9L10.7 2zM12 7a3 3 0 1 0 0 6 3 3 0 0 0 0-6z"/></svg>
|
||||
<i class="fa-solid fa-gear" aria-hidden="true"></i>
|
||||
<span>Helpdesk Settings</span>
|
||||
</a>
|
||||
@endif
|
||||
|
||||
@if($isAdmin)
|
||||
<a href="{{ url('/admin/users') }}" wire:navigate role="menuitem">
|
||||
<svg class="hd-svg-icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M9 11a4 4 0 1 0 0-8 4 4 0 0 0 0 8zm6-1a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM2 20c0-4 3-7 7-7s7 3 7 7H2zm13.5-6.3c3.6.3 6.5 2.8 6.5 6.3h-4c0-2.4-.9-4.6-2.5-6.3z"/></svg>
|
||||
<i class="fa-solid fa-users" aria-hidden="true"></i>
|
||||
<span>User Management</span>
|
||||
</a>
|
||||
@endif
|
||||
@@ -132,27 +132,63 @@
|
||||
href="{{ route('dashboard') }}"
|
||||
wire:navigate
|
||||
>
|
||||
<svg class="hd-svg-icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M12 3 2.5 11h2.2v9h5.6v-5.5h3.4V20h5.6v-9h2.2L12 3z"/></svg>
|
||||
<i class="fa-solid fa-gauge-high" aria-hidden="true"></i>
|
||||
<span>Dashboard</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="hd-nav-section"><div class="hd-nav-heading">Helpdesk</div>
|
||||
@if(Route::has('helpdesk.tickets.index'))<a class="hd-nav-link hd-nav-link--tickets {{ request()->routeIs('helpdesk.tickets.index', 'helpdesk.tickets.create', 'helpdesk.tickets.show', 'helpdesk.tickets.edit') ? 'is-active' : '' }}" href="{{ route('helpdesk.tickets.index') }}" wire:navigate><svg class="hd-svg-icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M3 6.5h18v4a2 2 0 0 0 0 4v4H3v-4a2 2 0 0 0 0-4v-4zm7 2v8h1.5v-8H10z"/></svg><span>Tickets</span></a>@endif
|
||||
@if(Route::has('helpdesk.tickets.archived'))<a class="hd-nav-link {{ request()->routeIs('helpdesk.tickets.archived') ? 'is-active' : '' }}" style="--hd-nav-accent:#f59e0b;--hd-nav-accent-rgb:245,158,11" href="{{ route('helpdesk.tickets.archived') }}" wire:navigate><svg class="hd-svg-icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M3 4h18v4H3V4zm1 5h16v11H4V9zm5 3v2h6v-2H9z"/></svg><span>Archive</span></a>@endif
|
||||
@if(Route::has('helpdesk.kanban'))<a class="hd-nav-link hd-nav-link--kanban {{ request()->routeIs('helpdesk.kanban') ? 'is-active' : '' }}" href="{{ route('helpdesk.kanban') }}" wire:navigate><svg class="hd-svg-icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M3 4h18v16H3V4zm2 2v12h6V6H5zm8 0v12h6V6h-6z"/></svg><span>Kanban</span></a>@endif
|
||||
@if(Route::has('helpdesk.settings'))<a class="hd-nav-link hd-nav-link--settings {{ request()->routeIs('helpdesk.settings*') ? 'is-active' : '' }}" href="{{ route('helpdesk.settings') }}" wire:navigate><svg class="hd-svg-icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M10.7 2h2.6l.6 2.3c.5.2 1 .5 1.5.9l2.3-.7 1.3 2.3-1.7 1.6c.1.5.2 1.1.2 1.6s-.1 1.1-.2 1.6l1.7 1.6-1.3 2.3-2.3-.7c-.5.4-1 .7-1.5.9l-.6 2.3h-2.6l-.6-2.3c-.5-.2-1-.5-1.5-.9l-2.3.7L5 13.2l1.7-1.6A6 6 0 0 1 6.5 10c0-.5.1-1.1.2-1.6L5 6.8l1.3-2.3 2.3.7c.5-.4 1-.7 1.5-.9L10.7 2zM12 7a3 3 0 1 0 0 6 3 3 0 0 0 0-6z"/></svg><span>Settings</span></a>@endif
|
||||
@if(Route::has('helpdesk.tickets.index'))<a class="hd-nav-link hd-nav-link--tickets {{ request()->routeIs('helpdesk.tickets.index', 'helpdesk.tickets.create', 'helpdesk.tickets.show', 'helpdesk.tickets.edit') ? 'is-active' : '' }}" href="{{ route('helpdesk.tickets.index') }}" wire:navigate><i class="fa-solid fa-ticket" aria-hidden="true"></i><span>Tickets</span></a>@endif
|
||||
@if(Route::has('helpdesk.tickets.archived'))<a class="hd-nav-link {{ request()->routeIs('helpdesk.tickets.archived') ? 'is-active' : '' }}" style="--hd-nav-accent:#f59e0b;--hd-nav-accent-rgb:245,158,11" href="{{ route('helpdesk.tickets.archived') }}" wire:navigate><i class="fa-solid fa-box-archive" aria-hidden="true"></i><span>Archive</span></a>@endif
|
||||
@if(Route::has('helpdesk.kanban'))<a class="hd-nav-link hd-nav-link--kanban {{ request()->routeIs('helpdesk.kanban') ? 'is-active' : '' }}" href="{{ route('helpdesk.kanban') }}" wire:navigate><i class="fa-solid fa-table-columns" aria-hidden="true"></i><span>Kanban</span></a>@endif
|
||||
@if(Route::has('helpdesk.settings'))<a class="hd-nav-link hd-nav-link--settings {{ request()->routeIs('helpdesk.settings*') ? 'is-active' : '' }}" href="{{ route('helpdesk.settings') }}" wire:navigate><i class="fa-solid fa-gear" aria-hidden="true"></i><span>Settings</span></a>@endif
|
||||
</div>
|
||||
@if(config('helpdesk.legacy.enabled', false) && Route::has('helpdesk.legacy.tickets'))
|
||||
<div class="hd-nav-section">
|
||||
<div class="hd-nav-heading">Legacy System</div>
|
||||
|
||||
<a
|
||||
class="hd-nav-link {{ request()->routeIs('helpdesk.legacy.tickets*') ? 'is-active' : '' }}"
|
||||
style="--hd-nav-accent:#64748b;--hd-nav-accent-rgb:100,116,139"
|
||||
href="{{ route('helpdesk.legacy.tickets') }}"
|
||||
wire:navigate
|
||||
>
|
||||
<i class="fa-solid fa-clock-rotate-left" aria-hidden="true"></i>
|
||||
<span>Legacy Tickets</span>
|
||||
</a>
|
||||
|
||||
<a
|
||||
class="hd-nav-link {{ request()->routeIs('helpdesk.legacy.categories') ? 'is-active' : '' }}"
|
||||
style="--hd-nav-accent:#64748b;--hd-nav-accent-rgb:100,116,139"
|
||||
href="{{ route('helpdesk.legacy.categories') }}"
|
||||
wire:navigate
|
||||
>
|
||||
<i class="fa-solid fa-folder-tree" aria-hidden="true"></i>
|
||||
<span>Legacy Categories</span>
|
||||
</a>
|
||||
|
||||
<a
|
||||
class="hd-nav-link"
|
||||
style="--hd-nav-accent:#64748b;--hd-nav-accent-rgb:100,116,139"
|
||||
href="https://helpdesk.old.mpba.dev"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<i class="fa-solid fa-arrow-up-right-from-square" aria-hidden="true"></i>
|
||||
<span>Old Helpdesk</span>
|
||||
</a>
|
||||
</div>
|
||||
@endif
|
||||
@if(Route::has('documentation.index') || Route::has('documentation.documents.index'))
|
||||
<div class="hd-nav-section"><div class="hd-nav-heading">Documentation</div>
|
||||
<a class="hd-nav-link hd-nav-link--documents {{ request()->routeIs('documentation.documents.*') || request()->routeIs('documentation.index') ? 'is-active' : '' }}" href="{{ Route::has('documentation.documents.index') ? route('documentation.documents.index') : route('documentation.index') }}" wire:navigate><svg class="hd-svg-icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M6 2h8l4 4v16H6V2zm7 1.8V7h3.2L13 3.8zM9 11v1.5h6V11H9zm0 3.5V16h6v-1.5H9z"/></svg><span>Documents</span></a>
|
||||
@if(Route::has('documentation.categories.index'))<a class="hd-nav-link hd-nav-link--categories {{ request()->routeIs('documentation.categories.*') ? 'is-active' : '' }}" href="{{ route('documentation.categories.index') }}" wire:navigate><svg class="hd-svg-icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M2.5 5h7l2 2h10v12h-19V5z"/></svg><span>Categories</span></a>@endif
|
||||
<a class="hd-nav-link hd-nav-link--documents {{ request()->routeIs('documentation.documents.*') || request()->routeIs('documentation.index') ? 'is-active' : '' }}" href="{{ Route::has('documentation.documents.index') ? route('documentation.documents.index') : route('documentation.index') }}" wire:navigate><i class="fa-solid fa-file-lines" aria-hidden="true"></i><span>Documents</span></a>
|
||||
@if(Route::has('documentation.categories.index'))<a class="hd-nav-link hd-nav-link--categories {{ request()->routeIs('documentation.categories.*') ? 'is-active' : '' }}" href="{{ route('documentation.categories.index') }}" wire:navigate><i class="fa-solid fa-folder" aria-hidden="true"></i><span>Categories</span></a>@endif
|
||||
</div>
|
||||
@endif
|
||||
@if($isAdmin && Route::has('user-management.index'))
|
||||
<div class="hd-nav-section"><div class="hd-nav-heading">Users</div>
|
||||
<a class="hd-nav-link hd-nav-link--users {{ request()->routeIs('user-management.index') || request()->routeIs('user-management.create') || request()->routeIs('user-management.edit') ? 'is-active' : '' }}" href="{{ route('user-management.index') }}" wire:navigate><svg class="hd-svg-icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M9 11a4 4 0 1 0 0-8 4 4 0 0 0 0 8zm6-1a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM2 20c0-4 3-7 7-7s7 3 7 7H2zm13.5-6.3c3.6.3 6.5 2.8 6.5 6.3h-4c0-2.4-.9-4.6-2.5-6.3z"/></svg><span>Users</span></a>
|
||||
<a class="hd-nav-link hd-nav-link--roles {{ request()->routeIs('user-management.roles') ? 'is-active' : '' }}" href="{{ route('user-management.roles') }}" wire:navigate><svg class="hd-svg-icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M12 2 4 5v6c0 5.1 3.4 9.4 8 11 4.6-1.6 8-5.9 8-11V5l-8-3zm0 3v14.8C8.7 18.3 6 14.9 6 11V6.4L12 4.2V5z"/></svg><span>Roles & Permissions</span></a>
|
||||
<a class="hd-nav-link hd-nav-link--users {{ request()->routeIs('user-management.index') || request()->routeIs('user-management.create') || request()->routeIs('user-management.edit') ? 'is-active' : '' }}" href="{{ route('user-management.index') }}" wire:navigate><i class="fa-solid fa-users" aria-hidden="true"></i><span>Users</span></a>
|
||||
<a class="hd-nav-link hd-nav-link--roles {{ request()->routeIs('user-management.roles') ? 'is-active' : '' }}" href="{{ route('user-management.roles') }}" wire:navigate><i class="fa-solid fa-shield-halved" aria-hidden="true"></i><span>Roles & Permissions</span></a>
|
||||
</div>
|
||||
@endif
|
||||
</nav>
|
||||
|
||||
@@ -3,36 +3,48 @@
|
||||
|
||||
<flux:heading class="sr-only">{{ __('Appearance settings') }}</flux:heading>
|
||||
|
||||
<x-settings.layout :heading="__('Appearance')" :subheading=" __('Update the appearance settings for your account')">
|
||||
<div class="hd-appearance-switch" role="group" aria-label="{{ __('Appearance') }}">
|
||||
<button type="button" data-hd-appearance-value="light" onclick="if(window.hdSetAppearance){window.hdSetAppearance('light')}" class="hd-appearance-choice">
|
||||
<i class="fa-regular fa-sun" aria-hidden="true"></i><span>{{ __('Light') }}</span>
|
||||
<x-settings.layout
|
||||
:heading="__('Appearance')"
|
||||
:subheading="__('Update the appearance settings for your account')"
|
||||
>
|
||||
<div
|
||||
class="hd-appearance-switch"
|
||||
role="group"
|
||||
aria-label="{{ __('Appearance') }}"
|
||||
x-data
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
class="hd-appearance-choice"
|
||||
:class="{ 'is-active': $flux.appearance === 'light' }"
|
||||
:aria-pressed="$flux.appearance === 'light'"
|
||||
@click="$flux.appearance = 'light'"
|
||||
>
|
||||
<i class="fa-regular fa-sun" aria-hidden="true"></i>
|
||||
<span>{{ __('Light') }}</span>
|
||||
</button>
|
||||
<button type="button" data-hd-appearance-value="dark" onclick="if(window.hdSetAppearance){window.hdSetAppearance('dark')}" class="hd-appearance-choice">
|
||||
<i class="fa-regular fa-moon" aria-hidden="true"></i><span>{{ __('Dark') }}</span>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
class="hd-appearance-choice"
|
||||
:class="{ 'is-active': $flux.appearance === 'dark' }"
|
||||
:aria-pressed="$flux.appearance === 'dark'"
|
||||
@click="$flux.appearance = 'dark'"
|
||||
>
|
||||
<i class="fa-regular fa-moon" aria-hidden="true"></i>
|
||||
<span>{{ __('Dark') }}</span>
|
||||
</button>
|
||||
<button type="button" data-hd-appearance-value="system" onclick="if(window.hdSetAppearance){window.hdSetAppearance('system')}" class="hd-appearance-choice">
|
||||
<i class="fa-solid fa-desktop" aria-hidden="true"></i><span>{{ __('System') }}</span>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
class="hd-appearance-choice"
|
||||
:class="{ 'is-active': $flux.appearance === 'system' }"
|
||||
:aria-pressed="$flux.appearance === 'system'"
|
||||
@click="$flux.appearance = 'system'"
|
||||
>
|
||||
<i class="fa-solid fa-desktop" aria-hidden="true"></i>
|
||||
<span>{{ __('System') }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<script>
|
||||
(function () {
|
||||
function sync() {
|
||||
var value = document.documentElement.getAttribute('data-hd-appearance') || 'system';
|
||||
var buttons = document.querySelectorAll('[data-hd-appearance-value]');
|
||||
for (var i = 0; i < buttons.length; i++) {
|
||||
if (buttons[i].getAttribute('data-hd-appearance-value') === value) buttons[i].classList.add('is-active');
|
||||
else buttons[i].classList.remove('is-active');
|
||||
}
|
||||
}
|
||||
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', sync, false); else sync();
|
||||
document.addEventListener('click', function (event) {
|
||||
var target = event.target;
|
||||
while (target && target !== document && !target.getAttribute('data-hd-appearance-value')) target = target.parentNode;
|
||||
if (target && target.getAttribute) setTimeout(sync, 0);
|
||||
}, false);
|
||||
document.addEventListener('livewire:navigated', sync, false);
|
||||
}());
|
||||
</script>
|
||||
</x-settings.layout>
|
||||
</section>
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
<div class="hd-helpdesk-surface hd-mobile-ready space-y-6" dusk="helpdesk-ticket-archive">
|
||||
<section class="overflow-hidden rounded-3xl border border-zinc-200 bg-white shadow-sm dark:border-zinc-700 dark:bg-zinc-900">
|
||||
<div class="bg-gradient-to-br from-slate-950 via-slate-900 to-amber-950 px-6 py-7 text-white">
|
||||
<div class="hd-page-hero bg-gradient-to-br from-slate-950 via-slate-900 to-amber-950 px-6 py-7 text-white">
|
||||
<div class="flex flex-col gap-5 lg:flex-row lg:items-center lg:justify-between">
|
||||
<div>
|
||||
<p class="text-xs font-semibold uppercase tracking-[0.28em] text-amber-200">Ticket archive</p>
|
||||
@@ -16,7 +16,7 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="rounded-2xl border border-zinc-200 bg-white p-4 shadow-sm dark:border-zinc-700 dark:bg-zinc-900">
|
||||
<section class="hd-filter-panel rounded-2xl border border-zinc-200 bg-white p-4 shadow-sm dark:border-zinc-700 dark:bg-zinc-900">
|
||||
<div class="hd-ticket-search-wrap max-w-2xl">
|
||||
<i class="fa-solid fa-magnifying-glass hd-ticket-search-icon" aria-hidden="true"></i>
|
||||
<input type="search" class="hd-ticket-search" wire:model.live.debounce.350ms="search"
|
||||
|
||||
@@ -22,14 +22,14 @@
|
||||
<div class="hd-dashboard space-y-5" dusk="helpdesk-dashboard-widget">
|
||||
<section class="hd-dashboard-heading">
|
||||
<div><h1>Dashboard</h1><p>Overview of your helpdesk system</p></div>
|
||||
<label class="hd-range-select"><svg class="hd-svg-icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M5 3h2v2h10V3h2v2h2v16H3V5h2V3zm0 6v10h14V9H5z"/></svg><select wire:model.live="days"><option value="7">Last 7 days</option><option value="14">Last 14 days</option><option value="30">Last 30 days</option></select></label>
|
||||
<label class="hd-range-select"><svg class="hd-svg-icon hd-icon-outline" viewBox="0 0 24 24" aria-hidden="true"><rect x="3" y="5" width="18" height="16" rx="2"/><path d="M16 3v4M8 3v4M3 10h18"/></svg><select wire:model.live="days"><option value="7">Last 7 days</option><option value="14">Last 14 days</option><option value="30">Last 30 days</option></select></label>
|
||||
</section>
|
||||
|
||||
<div class="hd-metric-grid">
|
||||
<article class="hd-metric-card hd-metric-blue"><span class="hd-metric-icon"><svg class="hd-svg-icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M9 2h6l1 2h3v18H5V4h3l1-2zm1 2-.5 1h5L14 4h-4zM8 9v2h8V9H8zm0 4v2h8v-2H8z"/></svg></span><div><small>Total Tickets</small><strong>{{ $totalCount }}</strong><em>All visible tickets</em></div></article>
|
||||
<article class="hd-metric-card hd-metric-green"><span class="hd-metric-icon"><svg class="hd-svg-icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M12 2a10 10 0 1 0 0 20 10 10 0 0 0 0-20zm-1.2 14.2-4-4 1.4-1.4 2.6 2.6 5-5 1.4 1.4-6.4 6.4z"/></svg></span><div><small>Resolved</small><strong>{{ $closedCount }}</strong><em>Completed workload</em></div></article>
|
||||
<article class="hd-metric-card hd-metric-amber"><span class="hd-metric-icon"><svg class="hd-svg-icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M12 2a10 10 0 1 0 0 20 10 10 0 0 0 0-20zm1 5v4.6l3.2 2-1 1.7-4.2-2.6V7h2z"/></svg></span><div><small>In Progress</small><strong>{{ $inProgressCount }}</strong><em>Actively being worked</em></div></article>
|
||||
<article class="hd-metric-card hd-metric-red"><span class="hd-metric-icon"><svg class="hd-svg-icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M12 2a10 10 0 1 0 0 20 10 10 0 0 0 0-20zm-1 5h2v7h-2V7zm0 9h2v2h-2v-2z"/></svg></span><div><small>Open</small><strong>{{ $openCount }}</strong><em>Awaiting resolution</em></div></article>
|
||||
<article class="hd-metric-card hd-metric-blue"><span class="hd-metric-icon"><svg class="hd-svg-icon hd-icon-outline" viewBox="0 0 24 24" aria-hidden="true"><path d="M9 5h6M9 3h6v4H9z"/><rect x="5" y="5" width="14" height="16" rx="2"/><path d="M9 11h6M9 15h6"/></svg></span><div><small>Total Tickets</small><strong>{{ $totalCount }}</strong><em>All visible tickets</em></div></article>
|
||||
<article class="hd-metric-card hd-metric-green"><span class="hd-metric-icon"><svg class="hd-svg-icon hd-icon-outline" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="9"/><path d="m8 12 2.6 2.6L16.5 9"/></svg></span><div><small>Resolved</small><strong>{{ $closedCount }}</strong><em>Completed workload</em></div></article>
|
||||
<article class="hd-metric-card hd-metric-amber"><span class="hd-metric-icon"><svg class="hd-svg-icon hd-icon-outline" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3.5 2"/></svg></span><div><small>In Progress</small><strong>{{ $inProgressCount }}</strong><em>Actively being worked</em></div></article>
|
||||
<article class="hd-metric-card hd-metric-red"><span class="hd-metric-icon"><svg class="hd-svg-icon hd-icon-outline" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="9"/><path d="M12 7v6M12 17h.01"/></svg></span><div><small>Open</small><strong>{{ $openCount }}</strong><em>Awaiting resolution</em></div></article>
|
||||
</div>
|
||||
|
||||
<div class="hd-dashboard-grid">
|
||||
|
||||
+4
-13
@@ -77,22 +77,13 @@
|
||||
default => ['border' => '#71717a', 'bg' => 'rgba(63, 63, 70, .22)', 'active' => '#3f3f46'],
|
||||
};
|
||||
|
||||
$sectionStyle =
|
||||
$section === $key
|
||||
? 'border-color: ' .
|
||||
$sectionPalette['border'] .
|
||||
'; background-color: ' .
|
||||
$sectionPalette['active'] .
|
||||
'; color: #ffffff; box-shadow: 0 16px 36px rgba(0,0,0,.32);'
|
||||
: 'border-color: ' .
|
||||
$sectionPalette['border'] .
|
||||
'; background-color: ' .
|
||||
$sectionPalette['bg'] .
|
||||
'; color: #ffffff; box-shadow: 0 10px 24px rgba(0,0,0,.20);';
|
||||
$sectionStyle = '--hd-card-border: ' . $sectionPalette['border'] .
|
||||
'; --hd-card-bg: ' . $sectionPalette['bg'] .
|
||||
'; --hd-card-active: ' . $sectionPalette['active'] . ';';
|
||||
@endphp
|
||||
<a href="{{ route('helpdesk.settings', ['section' => $key]) }}"
|
||||
dusk="helpdesk-settings-section-{{ $key }}"
|
||||
class="hd-settings-section-card rounded-xl border px-3 py-2 text-left shadow-sm transition hover:-translate-y-0.5"
|
||||
class="hd-settings-section-card {{ $section === $key ? 'is-active' : '' }} rounded-xl border px-3 py-2 text-left shadow-sm transition hover:-translate-y-0.5"
|
||||
style="{{ $sectionStyle }}">
|
||||
<div class="text-xs font-semibold uppercase tracking-wide opacity-70">{{ $item['label'] }}</div>
|
||||
<div class="mt-0.5 text-xl font-semibold">{{ $item['count'] }}</div>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div class="hd-helpdesk-surface hd-mobile-ready space-y-6" dusk="helpdesk-ticket-index">
|
||||
<div
|
||||
class="overflow-hidden rounded-3xl border border-zinc-200 bg-white shadow-sm dark:border-zinc-700 dark:bg-zinc-900">
|
||||
<div class="bg-gradient-to-br from-slate-950 via-slate-900 to-blue-950 px-6 py-7 text-white">
|
||||
<div class="hd-page-hero bg-gradient-to-br from-slate-950 via-slate-900 to-blue-950 px-6 py-7 text-white">
|
||||
<div class="flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between">
|
||||
<div>
|
||||
<p class="text-xs font-semibold uppercase tracking-[0.28em] text-blue-200">Ticket management</p>
|
||||
@@ -27,7 +27,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="rounded-2xl border border-zinc-200 bg-white p-4 shadow-sm dark:border-zinc-700 dark:bg-zinc-900">
|
||||
<div class="hd-filter-panel rounded-2xl border border-zinc-200 bg-white p-4 shadow-sm dark:border-zinc-700 dark:bg-zinc-900">
|
||||
<div class="grid gap-4 md:grid-cols-4">
|
||||
<div class="hd-ticket-search-wrap">
|
||||
<i class="fa-solid fa-magnifying-glass hd-ticket-search-icon" aria-hidden="true"></i>
|
||||
|
||||
@@ -15,30 +15,11 @@
|
||||
(function () {
|
||||
var ua = navigator.userAgent || '';
|
||||
var isIOS12 = /(iPad|iPhone|iPod).*OS 12[_\.]/.test(ua);
|
||||
|
||||
if (isIOS12) {
|
||||
document.documentElement.className += (document.documentElement.className ? ' ' : '') + 'hd-ios12';
|
||||
document.documentElement.className +=
|
||||
(document.documentElement.className ? ' ' : '') + 'hd-ios12';
|
||||
}
|
||||
|
||||
if (!isIOS12) return;
|
||||
|
||||
function applyAppearance(value) {
|
||||
var dark = value === 'dark' || (value === 'system' && window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches);
|
||||
if (dark) document.documentElement.classList.add('dark');
|
||||
else document.documentElement.classList.remove('dark');
|
||||
document.documentElement.setAttribute('data-hd-appearance', value);
|
||||
}
|
||||
|
||||
var stored = 'system';
|
||||
try { stored = localStorage.getItem('flux.appearance') || localStorage.getItem('appearance') || 'system'; } catch (e) {}
|
||||
applyAppearance(stored);
|
||||
|
||||
window.hdSetAppearance = function (value) {
|
||||
try {
|
||||
localStorage.setItem('flux.appearance', value);
|
||||
localStorage.setItem('appearance', value);
|
||||
} catch (e) {}
|
||||
applyAppearance(value);
|
||||
};
|
||||
}());
|
||||
</script>
|
||||
<title>{{ filled($title ?? null) ? $title.' - '.config('app.name', 'Laravel') : config('app.name', 'Laravel') }}</title>
|
||||
|
||||
@@ -1,347 +0,0 @@
|
||||
[2026-09-07 16:52:18] local.ERROR: TypeError: Module name, 'axios' does not resolve to a valid URL. null 0 0 TypeError Module name, 'axios' does not resolve to a valid URL. {"url":"https://helpdesk.vm/dashboard","user_agent":"Mozilla/5.0 (iPhone; CPU iPhone OS 27_0_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/152.0.7977.64 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:52:17.758Z"}
|
||||
[2026-09-07 16:52:18] local.ERROR: TypeError: Module name, 'axios' does not resolve to a valid URL. null 0 0 TypeError Module name, 'axios' does not resolve to a valid URL. {"url":"https://helpdesk.vm/dashboard","user_agent":"Mozilla/5.0 (iPhone; CPU iPhone OS 27_0_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/152.0.7977.64 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:52:17.758Z"}
|
||||
[2026-09-07 16:52:42] local.ERROR: TypeError: Module name, 'axios' does not resolve to a valid URL. null 0 0 TypeError Module name, 'axios' does not resolve to a valid URL. {"url":"https://helpdesk.vm/dashboard","user_agent":"Mozilla/5.0 (iPhone; CPU iPhone OS 27_0_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/152.0.7977.64 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:52:42.335Z"}
|
||||
[2026-09-07 16:52:42] local.ERROR: TypeError: Module name, 'axios' does not resolve to a valid URL. null 0 0 TypeError Module name, 'axios' does not resolve to a valid URL. {"url":"https://helpdesk.vm/dashboard","user_agent":"Mozilla/5.0 (iPhone; CPU iPhone OS 27_0_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/152.0.7977.64 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:52:42.335Z"}
|
||||
[2026-09-07 16:52:52] local.ERROR: TypeError: Module name, 'axios' does not resolve to a valid URL. null 0 0 TypeError Module name, 'axios' does not resolve to a valid URL. {"url":"https://helpdesk.vm/dashboard","user_agent":"Mozilla/5.0 (iPhone; CPU iPhone OS 27_0_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/152.0.7977.64 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:52:52.668Z"}
|
||||
[2026-09-07 16:52:52] local.ERROR: TypeError: Module name, 'axios' does not resolve to a valid URL. null 0 0 TypeError Module name, 'axios' does not resolve to a valid URL. {"url":"https://helpdesk.vm/dashboard","user_agent":"Mozilla/5.0 (iPhone; CPU iPhone OS 27_0_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/152.0.7977.64 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:52:52.668Z"}
|
||||
[2026-09-07 16:54:24] local.ERROR: SyntaxError: Unexpected token ';'. Expected an opening '(' before a method's parameter list. https://helpdesk.vm/flux/flux.js?id=6710af97 1 0 SyntaxError Unexpected token ';'. Expected an opening '(' before a method's parameter list. {"url":"https://helpdesk.vm/dashboard","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:54:24.476Z"}
|
||||
[2026-09-07 16:54:24] local.ERROR: SyntaxError: Unexpected token ';'. Expected an opening '(' before a method's parameter list. https://helpdesk.vm/flux/flux.js?id=6710af97 1 0 SyntaxError Unexpected token ';'. Expected an opening '(' before a method's parameter list. {"url":"https://helpdesk.vm/dashboard","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:54:24.477Z"}
|
||||
[2026-09-07 16:54:24] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/_debugbar/assets?type=js&mtime=1785738196 390 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/dashboard","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:54:24.498Z"}
|
||||
[2026-09-07 16:54:24] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/_debugbar/assets?type=js&mtime=1785738196 390 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/dashboard","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:54:24.499Z"}
|
||||
[2026-09-07 16:54:24] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/livewire-b2431d8a/livewire.js?id=26bbdf42 386 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/dashboard","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:54:24.504Z"}
|
||||
[2026-09-07 16:54:24] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/livewire-b2431d8a/livewire.js?id=26bbdf42 386 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/dashboard","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:54:24.504Z"}
|
||||
[2026-09-07 16:54:24] local.ERROR: ReferenceError: Can't find variable: PhpDebugBar https://helpdesk.vm/dashboard 565 36 ReferenceError Can't find variable: PhpDebugBar renderDebugbar@https://helpdesk.vm/dashboard:565:36
|
||||
[native code]
|
||||
promiseReactionJob@[native code] {"url":"https://helpdesk.vm/dashboard","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:54:24.627Z"}
|
||||
[2026-09-07 16:54:24] local.ERROR: ReferenceError: Can't find variable: PhpDebugBar https://helpdesk.vm/dashboard 565 36 ReferenceError Can't find variable: PhpDebugBar renderDebugbar@https://helpdesk.vm/dashboard:565:36
|
||||
[native code]
|
||||
promiseReactionJob@[native code] {"url":"https://helpdesk.vm/dashboard","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:54:24.627Z"}
|
||||
[2026-09-07 16:54:38] local.ERROR: SyntaxError: Unexpected token ';'. Expected an opening '(' before a method's parameter list. https://helpdesk.vm/flux/flux.js?id=6710af97 1 0 SyntaxError Unexpected token ';'. Expected an opening '(' before a method's parameter list. {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:54:37.989Z"}
|
||||
[2026-09-07 16:54:38] local.ERROR: ReferenceError: Can't find variable: PhpDebugBar https://helpdesk.vm/settings/profile 760 36 ReferenceError Can't find variable: PhpDebugBar renderDebugbar@https://helpdesk.vm/settings/profile:760:36
|
||||
[native code]
|
||||
promiseReactionJob@[native code] {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:54:38.186Z"}
|
||||
[2026-09-07 16:54:38] local.ERROR: SyntaxError: Unexpected token ';'. Expected an opening '(' before a method's parameter list. https://helpdesk.vm/flux/flux.js?id=6710af97 1 0 SyntaxError Unexpected token ';'. Expected an opening '(' before a method's parameter list. {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:54:37.990Z"}
|
||||
[2026-09-07 16:54:38] local.ERROR: ReferenceError: Can't find variable: PhpDebugBar https://helpdesk.vm/settings/profile 760 36 ReferenceError Can't find variable: PhpDebugBar renderDebugbar@https://helpdesk.vm/settings/profile:760:36
|
||||
[native code]
|
||||
promiseReactionJob@[native code] {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:54:38.187Z"}
|
||||
[2026-09-07 16:54:38] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/_debugbar/assets?type=js&mtime=1785738196 390 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:54:38.006Z"}
|
||||
[2026-09-07 16:54:38] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/_debugbar/assets?type=js&mtime=1785738196 390 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:54:38.006Z"}
|
||||
[2026-09-07 16:54:38] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/livewire-b2431d8a/livewire.js?id=26bbdf42 386 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:54:38.012Z"}
|
||||
[2026-09-07 16:54:38] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/livewire-b2431d8a/livewire.js?id=26bbdf42 386 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:54:38.012Z"}
|
||||
[2026-09-07 16:54:43] local.ERROR: SyntaxError: Unexpected token ';'. Expected an opening '(' before a method's parameter list. https://helpdesk.vm/flux/flux.js?id=6710af97 1 0 SyntaxError Unexpected token ';'. Expected an opening '(' before a method's parameter list. {"url":"https://helpdesk.vm/settings/appearance","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:54:43.345Z"}
|
||||
[2026-09-07 16:54:43] local.ERROR: SyntaxError: Unexpected token ';'. Expected an opening '(' before a method's parameter list. https://helpdesk.vm/flux/flux.js?id=6710af97 1 0 SyntaxError Unexpected token ';'. Expected an opening '(' before a method's parameter list. {"url":"https://helpdesk.vm/settings/appearance","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:54:43.346Z"}
|
||||
[2026-09-07 16:54:43] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/_debugbar/assets?type=js&mtime=1785738196 390 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/settings/appearance","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:54:43.364Z"}
|
||||
[2026-09-07 16:54:43] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/_debugbar/assets?type=js&mtime=1785738196 390 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/settings/appearance","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:54:43.364Z"}
|
||||
[2026-09-07 16:54:43] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/livewire-b2431d8a/livewire.js?id=26bbdf42 386 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/settings/appearance","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:54:43.367Z"}
|
||||
[2026-09-07 16:54:43] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/livewire-b2431d8a/livewire.js?id=26bbdf42 386 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/settings/appearance","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:54:43.367Z"}
|
||||
[2026-09-07 16:54:43] local.ERROR: ReferenceError: Can't find variable: PhpDebugBar https://helpdesk.vm/settings/appearance 597 36 ReferenceError Can't find variable: PhpDebugBar renderDebugbar@https://helpdesk.vm/settings/appearance:597:36
|
||||
[native code]
|
||||
promiseReactionJob@[native code] {"url":"https://helpdesk.vm/settings/appearance","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:54:43.438Z"}
|
||||
[2026-09-07 16:54:43] local.ERROR: ReferenceError: Can't find variable: PhpDebugBar https://helpdesk.vm/settings/appearance 597 36 ReferenceError Can't find variable: PhpDebugBar renderDebugbar@https://helpdesk.vm/settings/appearance:597:36
|
||||
[native code]
|
||||
promiseReactionJob@[native code] {"url":"https://helpdesk.vm/settings/appearance","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:54:43.438Z"}
|
||||
[2026-09-07 16:54:49] local.ERROR: SyntaxError: Unexpected token ';'. Expected an opening '(' before a method's parameter list. https://helpdesk.vm/flux/flux.js?id=6710af97 1 0 SyntaxError Unexpected token ';'. Expected an opening '(' before a method's parameter list. {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:54:48.962Z"}
|
||||
[2026-09-07 16:54:49] local.ERROR: SyntaxError: Unexpected token ';'. Expected an opening '(' before a method's parameter list. https://helpdesk.vm/flux/flux.js?id=6710af97 1 0 SyntaxError Unexpected token ';'. Expected an opening '(' before a method's parameter list. {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:54:48.962Z"}
|
||||
[2026-09-07 16:54:49] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/_debugbar/assets?type=js&mtime=1785738196 390 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:54:48.976Z"}
|
||||
[2026-09-07 16:54:49] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/_debugbar/assets?type=js&mtime=1785738196 390 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:54:48.976Z"}
|
||||
[2026-09-07 16:54:49] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/livewire-b2431d8a/livewire.js?id=26bbdf42 386 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:54:48.980Z"}
|
||||
[2026-09-07 16:54:49] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/livewire-b2431d8a/livewire.js?id=26bbdf42 386 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:54:48.980Z"}
|
||||
[2026-09-07 16:54:49] local.ERROR: ReferenceError: Can't find variable: PhpDebugBar https://helpdesk.vm/settings/profile 760 36 ReferenceError Can't find variable: PhpDebugBar renderDebugbar@https://helpdesk.vm/settings/profile:760:36
|
||||
[native code]
|
||||
promiseReactionJob@[native code] {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:54:49.109Z"}
|
||||
[2026-09-07 16:54:49] local.ERROR: ReferenceError: Can't find variable: PhpDebugBar https://helpdesk.vm/settings/profile 760 36 ReferenceError Can't find variable: PhpDebugBar renderDebugbar@https://helpdesk.vm/settings/profile:760:36
|
||||
[native code]
|
||||
promiseReactionJob@[native code] {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:54:49.109Z"}
|
||||
[2026-09-07 16:54:51] local.ERROR: SyntaxError: Unexpected token ';'. Expected an opening '(' before a method's parameter list. https://helpdesk.vm/flux/flux.js?id=6710af97 1 0 SyntaxError Unexpected token ';'. Expected an opening '(' before a method's parameter list. {"url":"https://helpdesk.vm/dashboard","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:54:50.959Z"}
|
||||
[2026-09-07 16:54:51] local.ERROR: SyntaxError: Unexpected token ';'. Expected an opening '(' before a method's parameter list. https://helpdesk.vm/flux/flux.js?id=6710af97 1 0 SyntaxError Unexpected token ';'. Expected an opening '(' before a method's parameter list. {"url":"https://helpdesk.vm/dashboard","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:54:50.959Z"}
|
||||
[2026-09-07 16:54:51] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/_debugbar/assets?type=js&mtime=1785738196 390 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/dashboard","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:54:50.975Z"}
|
||||
[2026-09-07 16:54:51] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/_debugbar/assets?type=js&mtime=1785738196 390 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/dashboard","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:54:50.976Z"}
|
||||
[2026-09-07 16:54:51] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/livewire-b2431d8a/livewire.js?id=26bbdf42 386 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/dashboard","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:54:50.980Z"}
|
||||
[2026-09-07 16:54:51] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/livewire-b2431d8a/livewire.js?id=26bbdf42 386 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/dashboard","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:54:50.980Z"}
|
||||
[2026-09-07 16:54:51] local.ERROR: ReferenceError: Can't find variable: PhpDebugBar https://helpdesk.vm/dashboard 565 36 ReferenceError Can't find variable: PhpDebugBar renderDebugbar@https://helpdesk.vm/dashboard:565:36 {"url":"https://helpdesk.vm/dashboard","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:54:50.986Z"}
|
||||
[2026-09-07 16:54:51] local.ERROR: ReferenceError: Can't find variable: PhpDebugBar https://helpdesk.vm/dashboard 565 36 ReferenceError Can't find variable: PhpDebugBar renderDebugbar@https://helpdesk.vm/dashboard:565:36 {"url":"https://helpdesk.vm/dashboard","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:54:50.986Z"}
|
||||
[2026-09-07 16:56:16] local.ERROR: SyntaxError: Unexpected token ';'. Expected an opening '(' before a method's parameter list. https://helpdesk.vm/flux/flux.js?id=6710af97 1 0 SyntaxError Unexpected token ';'. Expected an opening '(' before a method's parameter list. {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:56:15.695Z"}
|
||||
[2026-09-07 16:56:16] local.ERROR: SyntaxError: Unexpected token ';'. Expected an opening '(' before a method's parameter list. https://helpdesk.vm/flux/flux.js?id=6710af97 1 0 SyntaxError Unexpected token ';'. Expected an opening '(' before a method's parameter list. {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:56:15.696Z"}
|
||||
[2026-09-07 16:56:16] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/_debugbar/assets?type=js&mtime=1785738196 390 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:56:15.712Z"}
|
||||
[2026-09-07 16:56:16] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/_debugbar/assets?type=js&mtime=1785738196 390 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:56:15.712Z"}
|
||||
[2026-09-07 16:56:16] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/livewire-b2431d8a/livewire.js?id=26bbdf42 386 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:56:15.716Z"}
|
||||
[2026-09-07 16:56:16] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/livewire-b2431d8a/livewire.js?id=26bbdf42 386 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:56:15.716Z"}
|
||||
[2026-09-07 16:56:16] local.ERROR: ReferenceError: Can't find variable: PhpDebugBar https://helpdesk.vm/settings/profile 760 36 ReferenceError Can't find variable: PhpDebugBar renderDebugbar@https://helpdesk.vm/settings/profile:760:36
|
||||
[native code]
|
||||
promiseReactionJob@[native code] {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:56:15.851Z"}
|
||||
[2026-09-07 16:56:16] local.ERROR: ReferenceError: Can't find variable: PhpDebugBar https://helpdesk.vm/settings/profile 760 36 ReferenceError Can't find variable: PhpDebugBar renderDebugbar@https://helpdesk.vm/settings/profile:760:36
|
||||
[native code]
|
||||
promiseReactionJob@[native code] {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:56:15.852Z"}
|
||||
[2026-09-07 16:56:24] local.ERROR: SyntaxError: Unexpected token ';'. Expected an opening '(' before a method's parameter list. https://helpdesk.vm/flux/flux.js?id=6710af97 1 0 SyntaxError Unexpected token ';'. Expected an opening '(' before a method's parameter list. {"url":"https://helpdesk.vm/user/confirm-password","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:56:23.927Z"}
|
||||
[2026-09-07 16:56:24] local.ERROR: SyntaxError: Unexpected token ';'. Expected an opening '(' before a method's parameter list. https://helpdesk.vm/flux/flux.js?id=6710af97 1 0 SyntaxError Unexpected token ';'. Expected an opening '(' before a method's parameter list. {"url":"https://helpdesk.vm/user/confirm-password","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:56:23.928Z"}
|
||||
[2026-09-07 16:56:24] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/_debugbar/assets?type=js&mtime=1785738196 390 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/user/confirm-password","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:56:23.943Z"}
|
||||
[2026-09-07 16:56:24] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/_debugbar/assets?type=js&mtime=1785738196 390 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/user/confirm-password","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:56:23.943Z"}
|
||||
[2026-09-07 16:56:24] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/livewire-b2431d8a/livewire.js?id=26bbdf42 386 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/user/confirm-password","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:56:23.947Z"}
|
||||
[2026-09-07 16:56:24] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/livewire-b2431d8a/livewire.js?id=26bbdf42 386 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/user/confirm-password","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:56:23.947Z"}
|
||||
[2026-09-07 16:56:24] local.ERROR: ReferenceError: Can't find variable: PhpDebugBar https://helpdesk.vm/user/confirm-password 565 36 ReferenceError Can't find variable: PhpDebugBar renderDebugbar@https://helpdesk.vm/user/confirm-password:565:36
|
||||
[native code]
|
||||
promiseReactionJob@[native code] {"url":"https://helpdesk.vm/user/confirm-password","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:56:23.990Z"}
|
||||
[2026-09-07 16:56:24] local.ERROR: ReferenceError: Can't find variable: PhpDebugBar https://helpdesk.vm/user/confirm-password 565 36 ReferenceError Can't find variable: PhpDebugBar renderDebugbar@https://helpdesk.vm/user/confirm-password:565:36
|
||||
[native code]
|
||||
promiseReactionJob@[native code] {"url":"https://helpdesk.vm/user/confirm-password","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:56:23.990Z"}
|
||||
[2026-09-07 16:56:35] local.ERROR: SyntaxError: Unexpected token ';'. Expected an opening '(' before a method's parameter list. https://helpdesk.vm/flux/flux.js?id=6710af97 1 0 SyntaxError Unexpected token ';'. Expected an opening '(' before a method's parameter list. {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:56:34.769Z"}
|
||||
[2026-09-07 16:56:35] local.ERROR: SyntaxError: Unexpected token ';'. Expected an opening '(' before a method's parameter list. https://helpdesk.vm/flux/flux.js?id=6710af97 1 0 SyntaxError Unexpected token ';'. Expected an opening '(' before a method's parameter list. {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:56:34.769Z"}
|
||||
[2026-09-07 16:56:35] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/_debugbar/assets?type=js&mtime=1785738196 390 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:56:34.783Z"}
|
||||
[2026-09-07 16:56:35] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/_debugbar/assets?type=js&mtime=1785738196 390 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:56:34.783Z"}
|
||||
[2026-09-07 16:56:35] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/livewire-b2431d8a/livewire.js?id=26bbdf42 386 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:56:34.787Z"}
|
||||
[2026-09-07 16:56:35] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/livewire-b2431d8a/livewire.js?id=26bbdf42 386 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:56:34.787Z"}
|
||||
[2026-09-07 16:56:35] local.ERROR: ReferenceError: Can't find variable: PhpDebugBar https://helpdesk.vm/settings/profile 760 36 ReferenceError Can't find variable: PhpDebugBar renderDebugbar@https://helpdesk.vm/settings/profile:760:36 {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:56:34.795Z"}
|
||||
[2026-09-07 16:56:35] local.ERROR: ReferenceError: Can't find variable: PhpDebugBar https://helpdesk.vm/settings/profile 760 36 ReferenceError Can't find variable: PhpDebugBar renderDebugbar@https://helpdesk.vm/settings/profile:760:36 {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:56:34.795Z"}
|
||||
[2026-09-07 16:56:37] local.ERROR: SyntaxError: Unexpected token ';'. Expected an opening '(' before a method's parameter list. https://helpdesk.vm/flux/flux.js?id=6710af97 1 0 SyntaxError Unexpected token ';'. Expected an opening '(' before a method's parameter list. {"url":"https://helpdesk.vm/settings/appearance","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:56:36.879Z"}
|
||||
[2026-09-07 16:56:37] local.ERROR: SyntaxError: Unexpected token ';'. Expected an opening '(' before a method's parameter list. https://helpdesk.vm/flux/flux.js?id=6710af97 1 0 SyntaxError Unexpected token ';'. Expected an opening '(' before a method's parameter list. {"url":"https://helpdesk.vm/settings/appearance","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:56:36.879Z"}
|
||||
[2026-09-07 16:56:37] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/_debugbar/assets?type=js&mtime=1785738196 390 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/settings/appearance","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:56:36.897Z"}
|
||||
[2026-09-07 16:56:37] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/_debugbar/assets?type=js&mtime=1785738196 390 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/settings/appearance","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:56:36.897Z"}
|
||||
[2026-09-07 16:56:37] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/livewire-b2431d8a/livewire.js?id=26bbdf42 386 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/settings/appearance","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:56:36.901Z"}
|
||||
[2026-09-07 16:56:37] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/livewire-b2431d8a/livewire.js?id=26bbdf42 386 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/settings/appearance","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:56:36.901Z"}
|
||||
[2026-09-07 16:56:37] local.ERROR: ReferenceError: Can't find variable: PhpDebugBar https://helpdesk.vm/settings/appearance 597 36 ReferenceError Can't find variable: PhpDebugBar renderDebugbar@https://helpdesk.vm/settings/appearance:597:36
|
||||
[native code]
|
||||
promiseReactionJob@[native code] {"url":"https://helpdesk.vm/settings/appearance","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:56:37.006Z"}
|
||||
[2026-09-07 16:56:37] local.ERROR: ReferenceError: Can't find variable: PhpDebugBar https://helpdesk.vm/settings/appearance 597 36 ReferenceError Can't find variable: PhpDebugBar renderDebugbar@https://helpdesk.vm/settings/appearance:597:36
|
||||
[native code]
|
||||
promiseReactionJob@[native code] {"url":"https://helpdesk.vm/settings/appearance","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T16:56:37.006Z"}
|
||||
[2026-09-07 17:04:44] local.ERROR: SyntaxError: Unexpected token ';'. Expected an opening '(' before a method's parameter list. https://helpdesk.vm/flux/flux.js?id=6710af97 1 0 SyntaxError Unexpected token ';'. Expected an opening '(' before a method's parameter list. {"url":"https://helpdesk.vm/settings/appearance","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:04:44.289Z"}
|
||||
[2026-09-07 17:04:44] local.ERROR: SyntaxError: Unexpected token ';'. Expected an opening '(' before a method's parameter list. https://helpdesk.vm/flux/flux.js?id=6710af97 1 0 SyntaxError Unexpected token ';'. Expected an opening '(' before a method's parameter list. {"url":"https://helpdesk.vm/settings/appearance","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:04:44.289Z"}
|
||||
[2026-09-07 17:04:44] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/_debugbar/assets?type=js&mtime=1785738196 390 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/settings/appearance","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:04:44.309Z"}
|
||||
[2026-09-07 17:04:44] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/_debugbar/assets?type=js&mtime=1785738196 390 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/settings/appearance","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:04:44.309Z"}
|
||||
[2026-09-07 17:04:44] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/livewire-b2431d8a/livewire.js?id=26bbdf42 386 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/settings/appearance","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:04:44.312Z"}
|
||||
[2026-09-07 17:04:44] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/livewire-b2431d8a/livewire.js?id=26bbdf42 386 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/settings/appearance","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:04:44.313Z"}
|
||||
[2026-09-07 17:04:44] local.ERROR: ReferenceError: Can't find variable: PhpDebugBar https://helpdesk.vm/settings/appearance 616 36 ReferenceError Can't find variable: PhpDebugBar renderDebugbar@https://helpdesk.vm/settings/appearance:616:36
|
||||
[native code]
|
||||
promiseReactionJob@[native code] {"url":"https://helpdesk.vm/settings/appearance","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:04:44.442Z"}
|
||||
[2026-09-07 17:04:44] local.ERROR: ReferenceError: Can't find variable: PhpDebugBar https://helpdesk.vm/settings/appearance 616 36 ReferenceError Can't find variable: PhpDebugBar renderDebugbar@https://helpdesk.vm/settings/appearance:616:36
|
||||
[native code]
|
||||
promiseReactionJob@[native code] {"url":"https://helpdesk.vm/settings/appearance","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:04:44.442Z"}
|
||||
[2026-09-07 17:04:48] local.ERROR: SyntaxError: Unexpected token ';'. Expected an opening '(' before a method's parameter list. https://helpdesk.vm/flux/flux.js?id=6710af97 1 0 SyntaxError Unexpected token ';'. Expected an opening '(' before a method's parameter list. {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:04:47.864Z"}
|
||||
[2026-09-07 17:04:48] local.ERROR: SyntaxError: Unexpected token ';'. Expected an opening '(' before a method's parameter list. https://helpdesk.vm/flux/flux.js?id=6710af97 1 0 SyntaxError Unexpected token ';'. Expected an opening '(' before a method's parameter list. {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:04:47.864Z"}
|
||||
[2026-09-07 17:04:48] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/_debugbar/assets?type=js&mtime=1785738196 390 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:04:47.882Z"}
|
||||
[2026-09-07 17:04:48] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/_debugbar/assets?type=js&mtime=1785738196 390 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:04:47.882Z"}
|
||||
[2026-09-07 17:04:48] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/livewire-b2431d8a/livewire.js?id=26bbdf42 386 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:04:47.887Z"}
|
||||
[2026-09-07 17:04:48] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/livewire-b2431d8a/livewire.js?id=26bbdf42 386 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:04:47.887Z"}
|
||||
[2026-09-07 17:04:48] local.ERROR: ReferenceError: Can't find variable: PhpDebugBar https://helpdesk.vm/settings/profile 642 36 ReferenceError Can't find variable: PhpDebugBar renderDebugbar@https://helpdesk.vm/settings/profile:642:36
|
||||
[native code]
|
||||
promiseReactionJob@[native code] {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:04:47.979Z"}
|
||||
[2026-09-07 17:04:48] local.ERROR: ReferenceError: Can't find variable: PhpDebugBar https://helpdesk.vm/settings/profile 642 36 ReferenceError Can't find variable: PhpDebugBar renderDebugbar@https://helpdesk.vm/settings/profile:642:36
|
||||
[native code]
|
||||
promiseReactionJob@[native code] {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:04:47.980Z"}
|
||||
[2026-09-07 17:04:50] local.ERROR: SyntaxError: Unexpected token ';'. Expected an opening '(' before a method's parameter list. https://helpdesk.vm/flux/flux.js?id=6710af97 1 0 SyntaxError Unexpected token ';'. Expected an opening '(' before a method's parameter list. {"url":"https://helpdesk.vm/user/confirm-password","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:04:50.347Z"}
|
||||
[2026-09-07 17:04:50] local.ERROR: SyntaxError: Unexpected token ';'. Expected an opening '(' before a method's parameter list. https://helpdesk.vm/flux/flux.js?id=6710af97 1 0 SyntaxError Unexpected token ';'. Expected an opening '(' before a method's parameter list. {"url":"https://helpdesk.vm/user/confirm-password","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:04:50.347Z"}
|
||||
[2026-09-07 17:04:50] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/_debugbar/assets?type=js&mtime=1785738196 390 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/user/confirm-password","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:04:50.370Z"}
|
||||
[2026-09-07 17:04:50] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/_debugbar/assets?type=js&mtime=1785738196 390 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/user/confirm-password","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:04:50.370Z"}
|
||||
[2026-09-07 17:04:50] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/livewire-b2431d8a/livewire.js?id=26bbdf42 386 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/user/confirm-password","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:04:50.375Z"}
|
||||
[2026-09-07 17:04:50] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/livewire-b2431d8a/livewire.js?id=26bbdf42 386 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/user/confirm-password","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:04:50.375Z"}
|
||||
[2026-09-07 17:04:50] local.ERROR: ReferenceError: Can't find variable: PhpDebugBar https://helpdesk.vm/user/confirm-password 616 36 ReferenceError Can't find variable: PhpDebugBar renderDebugbar@https://helpdesk.vm/user/confirm-password:616:36
|
||||
[native code]
|
||||
promiseReactionJob@[native code] {"url":"https://helpdesk.vm/user/confirm-password","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:04:50.415Z"}
|
||||
[2026-09-07 17:04:50] local.ERROR: ReferenceError: Can't find variable: PhpDebugBar https://helpdesk.vm/user/confirm-password 616 36 ReferenceError Can't find variable: PhpDebugBar renderDebugbar@https://helpdesk.vm/user/confirm-password:616:36
|
||||
[native code]
|
||||
promiseReactionJob@[native code] {"url":"https://helpdesk.vm/user/confirm-password","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:04:50.415Z"}
|
||||
[2026-09-07 17:04:52] local.ERROR: SyntaxError: Unexpected token ';'. Expected an opening '(' before a method's parameter list. https://helpdesk.vm/flux/flux.js?id=6710af97 1 0 SyntaxError Unexpected token ';'. Expected an opening '(' before a method's parameter list. {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:04:52.456Z"}
|
||||
[2026-09-07 17:04:52] local.ERROR: SyntaxError: Unexpected token ';'. Expected an opening '(' before a method's parameter list. https://helpdesk.vm/flux/flux.js?id=6710af97 1 0 SyntaxError Unexpected token ';'. Expected an opening '(' before a method's parameter list. {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:04:52.456Z"}
|
||||
[2026-09-07 17:04:52] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/_debugbar/assets?type=js&mtime=1785738196 390 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:04:52.470Z"}
|
||||
[2026-09-07 17:04:52] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/_debugbar/assets?type=js&mtime=1785738196 390 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:04:52.470Z"}
|
||||
[2026-09-07 17:04:52] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/livewire-b2431d8a/livewire.js?id=26bbdf42 386 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:04:52.474Z"}
|
||||
[2026-09-07 17:04:52] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/livewire-b2431d8a/livewire.js?id=26bbdf42 386 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:04:52.474Z"}
|
||||
[2026-09-07 17:04:52] local.ERROR: ReferenceError: Can't find variable: PhpDebugBar https://helpdesk.vm/settings/profile 642 36 ReferenceError Can't find variable: PhpDebugBar renderDebugbar@https://helpdesk.vm/settings/profile:642:36 {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:04:52.479Z"}
|
||||
[2026-09-07 17:04:52] local.ERROR: ReferenceError: Can't find variable: PhpDebugBar https://helpdesk.vm/settings/profile 642 36 ReferenceError Can't find variable: PhpDebugBar renderDebugbar@https://helpdesk.vm/settings/profile:642:36 {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:04:52.479Z"}
|
||||
[2026-09-07 17:04:54] local.ERROR: SyntaxError: Unexpected token ';'. Expected an opening '(' before a method's parameter list. https://helpdesk.vm/flux/flux.js?id=6710af97 1 0 SyntaxError Unexpected token ';'. Expected an opening '(' before a method's parameter list. {"url":"https://helpdesk.vm/settings/appearance","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:04:53.875Z"}
|
||||
[2026-09-07 17:04:54] local.ERROR: SyntaxError: Unexpected token ';'. Expected an opening '(' before a method's parameter list. https://helpdesk.vm/flux/flux.js?id=6710af97 1 0 SyntaxError Unexpected token ';'. Expected an opening '(' before a method's parameter list. {"url":"https://helpdesk.vm/settings/appearance","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:04:53.875Z"}
|
||||
[2026-09-07 17:04:54] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/_debugbar/assets?type=js&mtime=1785738196 390 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/settings/appearance","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:04:53.890Z"}
|
||||
[2026-09-07 17:04:54] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/_debugbar/assets?type=js&mtime=1785738196 390 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/settings/appearance","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:04:53.890Z"}
|
||||
[2026-09-07 17:04:54] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/livewire-b2431d8a/livewire.js?id=26bbdf42 386 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/settings/appearance","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:04:53.893Z"}
|
||||
[2026-09-07 17:04:54] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/livewire-b2431d8a/livewire.js?id=26bbdf42 386 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/settings/appearance","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:04:53.893Z"}
|
||||
[2026-09-07 17:04:54] local.ERROR: ReferenceError: Can't find variable: PhpDebugBar https://helpdesk.vm/settings/appearance 616 36 ReferenceError Can't find variable: PhpDebugBar renderDebugbar@https://helpdesk.vm/settings/appearance:616:36
|
||||
[native code]
|
||||
promiseReactionJob@[native code] {"url":"https://helpdesk.vm/settings/appearance","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:04:53.971Z"}
|
||||
[2026-09-07 17:04:54] local.ERROR: ReferenceError: Can't find variable: PhpDebugBar https://helpdesk.vm/settings/appearance 616 36 ReferenceError Can't find variable: PhpDebugBar renderDebugbar@https://helpdesk.vm/settings/appearance:616:36
|
||||
[native code]
|
||||
promiseReactionJob@[native code] {"url":"https://helpdesk.vm/settings/appearance","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:04:53.971Z"}
|
||||
[2026-09-07 17:05:00] local.ERROR: SyntaxError: Unexpected token ';'. Expected an opening '(' before a method's parameter list. https://helpdesk.vm/flux/flux.js?id=6710af97 1 0 SyntaxError Unexpected token ';'. Expected an opening '(' before a method's parameter list. {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:05:00.341Z"}
|
||||
[2026-09-07 17:05:00] local.ERROR: SyntaxError: Unexpected token ';'. Expected an opening '(' before a method's parameter list. https://helpdesk.vm/flux/flux.js?id=6710af97 1 0 SyntaxError Unexpected token ';'. Expected an opening '(' before a method's parameter list. {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:05:00.341Z"}
|
||||
[2026-09-07 17:05:00] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/_debugbar/assets?type=js&mtime=1785738196 390 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:05:00.358Z"}
|
||||
[2026-09-07 17:05:00] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/_debugbar/assets?type=js&mtime=1785738196 390 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:05:00.358Z"}
|
||||
[2026-09-07 17:05:00] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/livewire-b2431d8a/livewire.js?id=26bbdf42 386 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:05:00.362Z"}
|
||||
[2026-09-07 17:05:00] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/livewire-b2431d8a/livewire.js?id=26bbdf42 386 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:05:00.362Z"}
|
||||
[2026-09-07 17:05:00] local.ERROR: ReferenceError: Can't find variable: PhpDebugBar https://helpdesk.vm/settings/profile 642 36 ReferenceError Can't find variable: PhpDebugBar renderDebugbar@https://helpdesk.vm/settings/profile:642:36
|
||||
[native code]
|
||||
promiseReactionJob@[native code] {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:05:00.453Z"}
|
||||
[2026-09-07 17:05:00] local.ERROR: ReferenceError: Can't find variable: PhpDebugBar https://helpdesk.vm/settings/profile 642 36 ReferenceError Can't find variable: PhpDebugBar renderDebugbar@https://helpdesk.vm/settings/profile:642:36
|
||||
[native code]
|
||||
promiseReactionJob@[native code] {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:05:00.453Z"}
|
||||
[2026-09-07 17:05:42] local.ERROR: SyntaxError: Unexpected token ';'. Expected an opening '(' before a method's parameter list. https://helpdesk.vm/flux/flux.js?id=6710af97 1 0 SyntaxError Unexpected token ';'. Expected an opening '(' before a method's parameter list. {"url":"https://helpdesk.vm/admin/users","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:05:41.615Z"}
|
||||
[2026-09-07 17:05:42] local.ERROR: SyntaxError: Unexpected token ';'. Expected an opening '(' before a method's parameter list. https://helpdesk.vm/flux/flux.js?id=6710af97 1 0 SyntaxError Unexpected token ';'. Expected an opening '(' before a method's parameter list. {"url":"https://helpdesk.vm/admin/users","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:05:41.615Z"}
|
||||
[2026-09-07 17:05:42] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/_debugbar/assets?type=js&mtime=1785738196 390 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/admin/users","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:05:41.632Z"}
|
||||
[2026-09-07 17:05:42] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/_debugbar/assets?type=js&mtime=1785738196 390 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/admin/users","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:05:41.633Z"}
|
||||
[2026-09-07 17:05:42] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/livewire-b2431d8a/livewire.js?id=26bbdf42 386 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/admin/users","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:05:41.637Z"}
|
||||
[2026-09-07 17:05:42] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/livewire-b2431d8a/livewire.js?id=26bbdf42 386 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/admin/users","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:05:41.637Z"}
|
||||
[2026-09-07 17:05:42] local.ERROR: ReferenceError: Can't find variable: PhpDebugBar https://helpdesk.vm/admin/users 646 36 ReferenceError Can't find variable: PhpDebugBar renderDebugbar@https://helpdesk.vm/admin/users:646:36
|
||||
[native code]
|
||||
promiseReactionJob@[native code] {"url":"https://helpdesk.vm/admin/users","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:05:41.760Z"}
|
||||
[2026-09-07 17:05:42] local.ERROR: ReferenceError: Can't find variable: PhpDebugBar https://helpdesk.vm/admin/users 646 36 ReferenceError Can't find variable: PhpDebugBar renderDebugbar@https://helpdesk.vm/admin/users:646:36
|
||||
[native code]
|
||||
promiseReactionJob@[native code] {"url":"https://helpdesk.vm/admin/users","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:05:41.760Z"}
|
||||
[2026-09-07 17:05:49] local.ERROR: SyntaxError: Unexpected token ';'. Expected an opening '(' before a method's parameter list. https://helpdesk.vm/flux/flux.js?id=6710af97 1 0 SyntaxError Unexpected token ';'. Expected an opening '(' before a method's parameter list. {"url":"https://helpdesk.vm/admin/helpdesk/settings","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:05:48.712Z"}
|
||||
[2026-09-07 17:05:49] local.ERROR: SyntaxError: Unexpected token ';'. Expected an opening '(' before a method's parameter list. https://helpdesk.vm/flux/flux.js?id=6710af97 1 0 SyntaxError Unexpected token ';'. Expected an opening '(' before a method's parameter list. {"url":"https://helpdesk.vm/admin/helpdesk/settings","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:05:48.712Z"}
|
||||
[2026-09-07 17:05:49] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/_debugbar/assets?type=js&mtime=1785738196 390 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/admin/helpdesk/settings","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:05:48.727Z"}
|
||||
[2026-09-07 17:05:49] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/_debugbar/assets?type=js&mtime=1785738196 390 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/admin/helpdesk/settings","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:05:48.727Z"}
|
||||
[2026-09-07 17:05:49] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/livewire-b2431d8a/livewire.js?id=26bbdf42 386 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/admin/helpdesk/settings","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:05:48.737Z"}
|
||||
[2026-09-07 17:05:49] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/livewire-b2431d8a/livewire.js?id=26bbdf42 386 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/admin/helpdesk/settings","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:05:48.737Z"}
|
||||
[2026-09-07 17:05:49] local.ERROR: ReferenceError: Can't find variable: PhpDebugBar https://helpdesk.vm/admin/helpdesk/settings 1367 36 ReferenceError Can't find variable: PhpDebugBar renderDebugbar@https://helpdesk.vm/admin/helpdesk/settings:1367:36
|
||||
[native code]
|
||||
promiseReactionJob@[native code] {"url":"https://helpdesk.vm/admin/helpdesk/settings","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:05:48.848Z"}
|
||||
[2026-09-07 17:05:49] local.ERROR: ReferenceError: Can't find variable: PhpDebugBar https://helpdesk.vm/admin/helpdesk/settings 1367 36 ReferenceError Can't find variable: PhpDebugBar renderDebugbar@https://helpdesk.vm/admin/helpdesk/settings:1367:36
|
||||
[native code]
|
||||
promiseReactionJob@[native code] {"url":"https://helpdesk.vm/admin/helpdesk/settings","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:05:48.848Z"}
|
||||
[2026-09-07 17:05:51] local.ERROR: SyntaxError: Unexpected token ';'. Expected an opening '(' before a method's parameter list. https://helpdesk.vm/flux/flux.js?id=6710af97 1 0 SyntaxError Unexpected token ';'. Expected an opening '(' before a method's parameter list. {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:05:51.308Z"}
|
||||
[2026-09-07 17:05:51] local.ERROR: SyntaxError: Unexpected token ';'. Expected an opening '(' before a method's parameter list. https://helpdesk.vm/flux/flux.js?id=6710af97 1 0 SyntaxError Unexpected token ';'. Expected an opening '(' before a method's parameter list. {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:05:51.308Z"}
|
||||
[2026-09-07 17:05:51] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/_debugbar/assets?type=js&mtime=1785738196 390 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:05:51.325Z"}
|
||||
[2026-09-07 17:05:51] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/_debugbar/assets?type=js&mtime=1785738196 390 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:05:51.325Z"}
|
||||
[2026-09-07 17:05:51] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/livewire-b2431d8a/livewire.js?id=26bbdf42 386 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:05:51.328Z"}
|
||||
[2026-09-07 17:05:51] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/livewire-b2431d8a/livewire.js?id=26bbdf42 386 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:05:51.329Z"}
|
||||
[2026-09-07 17:05:51] local.ERROR: ReferenceError: Can't find variable: PhpDebugBar https://helpdesk.vm/settings/profile 642 36 ReferenceError Can't find variable: PhpDebugBar renderDebugbar@https://helpdesk.vm/settings/profile:642:36 {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:05:51.333Z"}
|
||||
[2026-09-07 17:05:51] local.ERROR: ReferenceError: Can't find variable: PhpDebugBar https://helpdesk.vm/settings/profile 642 36 ReferenceError Can't find variable: PhpDebugBar renderDebugbar@https://helpdesk.vm/settings/profile:642:36 {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:05:51.333Z"}
|
||||
[2026-09-07 17:07:27] local.INFO: Helpdesk module assets loaded {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPhone; CPU iPhone OS 27_0_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/152.0.7977.64 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:07:27.046Z"}
|
||||
[2026-09-07 17:07:39] local.INFO: Helpdesk module assets loaded {"url":"https://helpdesk.vm/settings/security","user_agent":"Mozilla/5.0 (iPhone; CPU iPhone OS 27_0_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/152.0.7977.64 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:07:38.997Z"}
|
||||
[2026-09-07 17:08:12] local.INFO: Helpdesk module assets loaded {"url":"https://helpdesk.vm/dashboard","user_agent":"Mozilla/5.0 (iPhone; CPU iPhone OS 27_0_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/152.0.7977.64 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:08:12.505Z"}
|
||||
[2026-09-07 17:09:28] local.ERROR: SyntaxError: Unexpected token ';'. Expected an opening '(' before a method's parameter list. https://helpdesk.vm/flux/flux.js?id=6710af97 1 0 SyntaxError Unexpected token ';'. Expected an opening '(' before a method's parameter list. {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:09:28.116Z"}
|
||||
[2026-09-07 17:09:28] local.ERROR: SyntaxError: Unexpected token ';'. Expected an opening '(' before a method's parameter list. https://helpdesk.vm/flux/flux.js?id=6710af97 1 0 SyntaxError Unexpected token ';'. Expected an opening '(' before a method's parameter list. {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:09:28.116Z"}
|
||||
[2026-09-07 17:09:28] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/_debugbar/assets?type=js&mtime=1785738196 390 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:09:28.138Z"}
|
||||
[2026-09-07 17:09:28] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/_debugbar/assets?type=js&mtime=1785738196 390 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:09:28.138Z"}
|
||||
[2026-09-07 17:09:28] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/livewire-b2431d8a/livewire.js?id=26bbdf42 386 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:09:28.143Z"}
|
||||
[2026-09-07 17:09:28] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/livewire-b2431d8a/livewire.js?id=26bbdf42 386 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:09:28.143Z"}
|
||||
[2026-09-07 17:09:28] local.ERROR: ReferenceError: Can't find variable: PhpDebugBar https://helpdesk.vm/settings/profile 811 36 ReferenceError Can't find variable: PhpDebugBar renderDebugbar@https://helpdesk.vm/settings/profile:811:36
|
||||
[native code]
|
||||
promiseReactionJob@[native code] {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:09:28.226Z"}
|
||||
[2026-09-07 17:09:28] local.ERROR: ReferenceError: Can't find variable: PhpDebugBar https://helpdesk.vm/settings/profile 811 36 ReferenceError Can't find variable: PhpDebugBar renderDebugbar@https://helpdesk.vm/settings/profile:811:36
|
||||
[native code]
|
||||
promiseReactionJob@[native code] {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:09:28.226Z"}
|
||||
[2026-09-07 17:09:31] local.ERROR: SyntaxError: Unexpected token ';'. Expected an opening '(' before a method's parameter list. https://helpdesk.vm/flux/flux.js?id=6710af97 1 0 SyntaxError Unexpected token ';'. Expected an opening '(' before a method's parameter list. {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:09:31.205Z"}
|
||||
[2026-09-07 17:09:31] local.ERROR: SyntaxError: Unexpected token ';'. Expected an opening '(' before a method's parameter list. https://helpdesk.vm/flux/flux.js?id=6710af97 1 0 SyntaxError Unexpected token ';'. Expected an opening '(' before a method's parameter list. {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:09:31.206Z"}
|
||||
[2026-09-07 17:09:31] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/_debugbar/assets?type=js&mtime=1785738196 390 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:09:31.219Z"}
|
||||
[2026-09-07 17:09:31] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/_debugbar/assets?type=js&mtime=1785738196 390 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:09:31.219Z"}
|
||||
[2026-09-07 17:09:31] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/livewire-b2431d8a/livewire.js?id=26bbdf42 386 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:09:31.223Z"}
|
||||
[2026-09-07 17:09:31] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/livewire-b2431d8a/livewire.js?id=26bbdf42 386 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:09:31.223Z"}
|
||||
[2026-09-07 17:09:31] local.ERROR: ReferenceError: Can't find variable: PhpDebugBar https://helpdesk.vm/settings/profile 811 36 ReferenceError Can't find variable: PhpDebugBar renderDebugbar@https://helpdesk.vm/settings/profile:811:36
|
||||
[native code]
|
||||
promiseReactionJob@[native code] {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:09:31.289Z"}
|
||||
[2026-09-07 17:09:31] local.ERROR: ReferenceError: Can't find variable: PhpDebugBar https://helpdesk.vm/settings/profile 811 36 ReferenceError Can't find variable: PhpDebugBar renderDebugbar@https://helpdesk.vm/settings/profile:811:36
|
||||
[native code]
|
||||
promiseReactionJob@[native code] {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:09:31.290Z"}
|
||||
[2026-09-07 17:09:33] local.ERROR: SyntaxError: Unexpected token ';'. Expected an opening '(' before a method's parameter list. https://helpdesk.vm/flux/flux.js?id=6710af97 1 0 SyntaxError Unexpected token ';'. Expected an opening '(' before a method's parameter list. {"url":"https://helpdesk.vm/user/confirm-password","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:09:33.154Z"}
|
||||
[2026-09-07 17:09:33] local.ERROR: SyntaxError: Unexpected token ';'. Expected an opening '(' before a method's parameter list. https://helpdesk.vm/flux/flux.js?id=6710af97 1 0 SyntaxError Unexpected token ';'. Expected an opening '(' before a method's parameter list. {"url":"https://helpdesk.vm/user/confirm-password","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:09:33.154Z"}
|
||||
[2026-09-07 17:09:33] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/_debugbar/assets?type=js&mtime=1785738196 390 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/user/confirm-password","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:09:33.169Z"}
|
||||
[2026-09-07 17:09:33] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/_debugbar/assets?type=js&mtime=1785738196 390 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/user/confirm-password","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:09:33.169Z"}
|
||||
[2026-09-07 17:09:33] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/livewire-b2431d8a/livewire.js?id=26bbdf42 386 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/user/confirm-password","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:09:33.175Z"}
|
||||
[2026-09-07 17:09:33] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/livewire-b2431d8a/livewire.js?id=26bbdf42 386 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/user/confirm-password","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:09:33.176Z"}
|
||||
[2026-09-07 17:09:33] local.ERROR: ReferenceError: Can't find variable: PhpDebugBar https://helpdesk.vm/user/confirm-password 616 36 ReferenceError Can't find variable: PhpDebugBar renderDebugbar@https://helpdesk.vm/user/confirm-password:616:36
|
||||
[native code]
|
||||
promiseReactionJob@[native code] {"url":"https://helpdesk.vm/user/confirm-password","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:09:33.222Z"}
|
||||
[2026-09-07 17:09:33] local.ERROR: ReferenceError: Can't find variable: PhpDebugBar https://helpdesk.vm/user/confirm-password 616 36 ReferenceError Can't find variable: PhpDebugBar renderDebugbar@https://helpdesk.vm/user/confirm-password:616:36
|
||||
[native code]
|
||||
promiseReactionJob@[native code] {"url":"https://helpdesk.vm/user/confirm-password","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:09:33.222Z"}
|
||||
[2026-09-07 17:09:48] local.ERROR: SyntaxError: Unexpected token ';'. Expected an opening '(' before a method's parameter list. https://helpdesk.vm/flux/flux.js?id=6710af97 1 0 SyntaxError Unexpected token ';'. Expected an opening '(' before a method's parameter list. {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:09:47.676Z"}
|
||||
[2026-09-07 17:09:48] local.ERROR: SyntaxError: Unexpected token ';'. Expected an opening '(' before a method's parameter list. https://helpdesk.vm/flux/flux.js?id=6710af97 1 0 SyntaxError Unexpected token ';'. Expected an opening '(' before a method's parameter list. {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:09:47.676Z"}
|
||||
[2026-09-07 17:09:48] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/_debugbar/assets?type=js&mtime=1785738196 390 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:09:47.690Z"}
|
||||
[2026-09-07 17:09:48] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/_debugbar/assets?type=js&mtime=1785738196 390 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:09:47.690Z"}
|
||||
[2026-09-07 17:09:48] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/livewire-b2431d8a/livewire.js?id=26bbdf42 386 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:09:47.694Z"}
|
||||
[2026-09-07 17:09:48] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/livewire-b2431d8a/livewire.js?id=26bbdf42 386 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:09:47.694Z"}
|
||||
[2026-09-07 17:09:48] local.ERROR: ReferenceError: Can't find variable: PhpDebugBar https://helpdesk.vm/settings/profile 811 36 ReferenceError Can't find variable: PhpDebugBar renderDebugbar@https://helpdesk.vm/settings/profile:811:36 {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:09:47.699Z"}
|
||||
[2026-09-07 17:09:48] local.ERROR: ReferenceError: Can't find variable: PhpDebugBar https://helpdesk.vm/settings/profile 811 36 ReferenceError Can't find variable: PhpDebugBar renderDebugbar@https://helpdesk.vm/settings/profile:811:36 {"url":"https://helpdesk.vm/settings/profile","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:09:47.699Z"}
|
||||
[2026-09-07 17:09:52] local.ERROR: SyntaxError: Unexpected token ';'. Expected an opening '(' before a method's parameter list. https://helpdesk.vm/flux/flux.js?id=6710af97 1 0 SyntaxError Unexpected token ';'. Expected an opening '(' before a method's parameter list. {"url":"https://helpdesk.vm/admin/helpdesk/settings","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:09:51.704Z"}
|
||||
[2026-09-07 17:09:52] local.ERROR: SyntaxError: Unexpected token ';'. Expected an opening '(' before a method's parameter list. https://helpdesk.vm/flux/flux.js?id=6710af97 1 0 SyntaxError Unexpected token ';'. Expected an opening '(' before a method's parameter list. {"url":"https://helpdesk.vm/admin/helpdesk/settings","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:09:51.704Z"}
|
||||
[2026-09-07 17:09:52] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/_debugbar/assets?type=js&mtime=1785738196 390 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/admin/helpdesk/settings","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:09:51.718Z"}
|
||||
[2026-09-07 17:09:52] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/_debugbar/assets?type=js&mtime=1785738196 390 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/admin/helpdesk/settings","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:09:51.718Z"}
|
||||
[2026-09-07 17:09:52] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/livewire-b2431d8a/livewire.js?id=26bbdf42 386 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/admin/helpdesk/settings","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:09:51.735Z"}
|
||||
[2026-09-07 17:09:52] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/livewire-b2431d8a/livewire.js?id=26bbdf42 386 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/admin/helpdesk/settings","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:09:51.735Z"}
|
||||
[2026-09-07 17:09:52] local.ERROR: ReferenceError: Can't find variable: PhpDebugBar https://helpdesk.vm/admin/helpdesk/settings 1367 36 ReferenceError Can't find variable: PhpDebugBar renderDebugbar@https://helpdesk.vm/admin/helpdesk/settings:1367:36
|
||||
[native code]
|
||||
promiseReactionJob@[native code] {"url":"https://helpdesk.vm/admin/helpdesk/settings","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:09:51.827Z"}
|
||||
[2026-09-07 17:09:52] local.ERROR: ReferenceError: Can't find variable: PhpDebugBar https://helpdesk.vm/admin/helpdesk/settings 1367 36 ReferenceError Can't find variable: PhpDebugBar renderDebugbar@https://helpdesk.vm/admin/helpdesk/settings:1367:36
|
||||
[native code]
|
||||
promiseReactionJob@[native code] {"url":"https://helpdesk.vm/admin/helpdesk/settings","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-07T17:09:51.828Z"}
|
||||
[2026-09-08 08:32:38] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/login 295 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/login","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-08T08:32:37.779Z"}
|
||||
[2026-09-08 08:32:38] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/login 295 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/login","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-08T08:32:37.780Z"}
|
||||
[2026-09-08 08:32:38] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/_debugbar/assets?type=js&mtime=1785738196 390 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/login","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-08T08:32:37.806Z"}
|
||||
[2026-09-08 08:32:38] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/_debugbar/assets?type=js&mtime=1785738196 390 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/login","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-08T08:32:37.806Z"}
|
||||
[2026-09-08 08:32:38] local.ERROR: ReferenceError: Can't find variable: PhpDebugBar https://helpdesk.vm/login 322 36 ReferenceError Can't find variable: PhpDebugBar renderDebugbar@https://helpdesk.vm/login:322:36
|
||||
[native code]
|
||||
promiseReactionJob@[native code] {"url":"https://helpdesk.vm/login","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-08T08:32:37.896Z"}
|
||||
[2026-09-08 08:32:38] local.ERROR: ReferenceError: Can't find variable: PhpDebugBar https://helpdesk.vm/login 322 36 ReferenceError Can't find variable: PhpDebugBar renderDebugbar@https://helpdesk.vm/login:322:36
|
||||
[native code]
|
||||
promiseReactionJob@[native code] {"url":"https://helpdesk.vm/login","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-08T08:32:37.896Z"}
|
||||
[2026-09-08 08:32:46] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/login 295 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/login","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-08T08:32:46.394Z"}
|
||||
[2026-09-08 08:32:46] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/login 295 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/login","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-08T08:32:46.395Z"}
|
||||
[2026-09-08 08:32:46] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/_debugbar/assets?type=js&mtime=1785738196 390 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/login","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-08T08:32:46.413Z"}
|
||||
[2026-09-08 08:32:46] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/_debugbar/assets?type=js&mtime=1785738196 390 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/login","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-08T08:32:46.413Z"}
|
||||
[2026-09-08 08:32:46] local.ERROR: ReferenceError: Can't find variable: PhpDebugBar https://helpdesk.vm/login 322 36 ReferenceError Can't find variable: PhpDebugBar renderDebugbar@https://helpdesk.vm/login:322:36
|
||||
[native code]
|
||||
promiseReactionJob@[native code] {"url":"https://helpdesk.vm/login","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-08T08:32:46.461Z"}
|
||||
[2026-09-08 08:32:46] local.ERROR: ReferenceError: Can't find variable: PhpDebugBar https://helpdesk.vm/login 322 36 ReferenceError Can't find variable: PhpDebugBar renderDebugbar@https://helpdesk.vm/login:322:36
|
||||
[native code]
|
||||
promiseReactionJob@[native code] {"url":"https://helpdesk.vm/login","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-08T08:32:46.461Z"}
|
||||
[2026-09-08 08:32:51] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/login 295 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/login","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-08T08:32:50.887Z"}
|
||||
[2026-09-08 08:32:51] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/login 295 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/login","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-08T08:32:50.887Z"}
|
||||
[2026-09-08 08:32:51] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/_debugbar/assets?type=js&mtime=1785738196 390 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/login","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-08T08:32:50.906Z"}
|
||||
[2026-09-08 08:32:51] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/_debugbar/assets?type=js&mtime=1785738196 390 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/login","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-08T08:32:50.906Z"}
|
||||
[2026-09-08 08:32:51] local.ERROR: ReferenceError: Can't find variable: PhpDebugBar https://helpdesk.vm/login 322 36 ReferenceError Can't find variable: PhpDebugBar renderDebugbar@https://helpdesk.vm/login:322:36
|
||||
[native code]
|
||||
promiseReactionJob@[native code] {"url":"https://helpdesk.vm/login","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-08T08:32:50.964Z"}
|
||||
[2026-09-08 08:32:51] local.ERROR: ReferenceError: Can't find variable: PhpDebugBar https://helpdesk.vm/login 322 36 ReferenceError Can't find variable: PhpDebugBar renderDebugbar@https://helpdesk.vm/login:322:36
|
||||
[native code]
|
||||
promiseReactionJob@[native code] {"url":"https://helpdesk.vm/login","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-08T08:32:50.964Z"}
|
||||
[2026-09-08 08:33:09] local.ERROR: SyntaxError: Unexpected token ';'. Expected an opening '(' before a method's parameter list. https://helpdesk.vm/flux/flux.js?id=6710af97 1 0 SyntaxError Unexpected token ';'. Expected an opening '(' before a method's parameter list. {"url":"https://helpdesk.vm/admin/helpdesk/settings","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-08T08:33:09.086Z"}
|
||||
[2026-09-08 08:33:09] local.ERROR: SyntaxError: Unexpected token ';'. Expected an opening '(' before a method's parameter list. https://helpdesk.vm/flux/flux.js?id=6710af97 1 0 SyntaxError Unexpected token ';'. Expected an opening '(' before a method's parameter list. {"url":"https://helpdesk.vm/admin/helpdesk/settings","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-08T08:33:09.086Z"}
|
||||
[2026-09-08 08:33:09] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/_debugbar/assets?type=js&mtime=1785738196 390 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/admin/helpdesk/settings","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-08T08:33:09.100Z"}
|
||||
[2026-09-08 08:33:09] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/_debugbar/assets?type=js&mtime=1785738196 390 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/admin/helpdesk/settings","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-08T08:33:09.101Z"}
|
||||
[2026-09-08 08:33:09] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/livewire-b2431d8a/livewire.js?id=26bbdf42 386 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/admin/helpdesk/settings","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-08T08:33:09.112Z"}
|
||||
[2026-09-08 08:33:09] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/livewire-b2431d8a/livewire.js?id=26bbdf42 386 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/admin/helpdesk/settings","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-08T08:33:09.113Z"}
|
||||
[2026-09-08 08:33:09] local.ERROR: ReferenceError: Can't find variable: PhpDebugBar https://helpdesk.vm/admin/helpdesk/settings 1338 36 ReferenceError Can't find variable: PhpDebugBar renderDebugbar@https://helpdesk.vm/admin/helpdesk/settings:1338:36
|
||||
[native code]
|
||||
promiseReactionJob@[native code] {"url":"https://helpdesk.vm/admin/helpdesk/settings","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-08T08:33:09.179Z"}
|
||||
[2026-09-08 08:33:09] local.ERROR: ReferenceError: Can't find variable: PhpDebugBar https://helpdesk.vm/admin/helpdesk/settings 1338 36 ReferenceError Can't find variable: PhpDebugBar renderDebugbar@https://helpdesk.vm/admin/helpdesk/settings:1338:36
|
||||
[native code]
|
||||
promiseReactionJob@[native code] {"url":"https://helpdesk.vm/admin/helpdesk/settings","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-08T08:33:09.179Z"}
|
||||
[2026-09-08 08:33:18] local.ERROR: SyntaxError: Unexpected token ';'. Expected an opening '(' before a method's parameter list. https://helpdesk.vm/flux/flux.js?id=6710af97 1 0 SyntaxError Unexpected token ';'. Expected an opening '(' before a method's parameter list. {"url":"https://helpdesk.vm/admin/helpdesk/kanban","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-08T08:33:17.974Z"}
|
||||
[2026-09-08 08:33:18] local.ERROR: SyntaxError: Unexpected token ';'. Expected an opening '(' before a method's parameter list. https://helpdesk.vm/flux/flux.js?id=6710af97 1 0 SyntaxError Unexpected token ';'. Expected an opening '(' before a method's parameter list. {"url":"https://helpdesk.vm/admin/helpdesk/kanban","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-08T08:33:17.974Z"}
|
||||
[2026-09-08 08:33:18] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/_debugbar/assets?type=js&mtime=1785738196 390 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/admin/helpdesk/kanban","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-08T08:33:17.990Z"}
|
||||
[2026-09-08 08:33:18] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/_debugbar/assets?type=js&mtime=1785738196 390 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/admin/helpdesk/kanban","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-08T08:33:17.990Z"}
|
||||
[2026-09-08 08:33:18] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/livewire-b2431d8a/livewire.js?id=26bbdf42 386 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/admin/helpdesk/kanban","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-08T08:33:17.996Z"}
|
||||
[2026-09-08 08:33:18] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/livewire-b2431d8a/livewire.js?id=26bbdf42 386 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/admin/helpdesk/kanban","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-08T08:33:17.996Z"}
|
||||
[2026-09-08 08:33:18] local.ERROR: ReferenceError: Can't find variable: PhpDebugBar https://helpdesk.vm/admin/helpdesk/kanban 1179 36 ReferenceError Can't find variable: PhpDebugBar renderDebugbar@https://helpdesk.vm/admin/helpdesk/kanban:1179:36
|
||||
[native code]
|
||||
promiseReactionJob@[native code] {"url":"https://helpdesk.vm/admin/helpdesk/kanban","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-08T08:33:18.071Z"}
|
||||
[2026-09-08 08:33:18] local.ERROR: ReferenceError: Can't find variable: PhpDebugBar https://helpdesk.vm/admin/helpdesk/kanban 1179 36 ReferenceError Can't find variable: PhpDebugBar renderDebugbar@https://helpdesk.vm/admin/helpdesk/kanban:1179:36
|
||||
[native code]
|
||||
promiseReactionJob@[native code] {"url":"https://helpdesk.vm/admin/helpdesk/kanban","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-08T08:33:18.071Z"}
|
||||
[2026-09-08 08:33:22] local.ERROR: SyntaxError: Unexpected token ';'. Expected an opening '(' before a method's parameter list. https://helpdesk.vm/flux/flux.js?id=6710af97 1 0 SyntaxError Unexpected token ';'. Expected an opening '(' before a method's parameter list. {"url":"https://helpdesk.vm/admin/helpdesk/tickets/archived","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-08T08:33:22.646Z"}
|
||||
[2026-09-08 08:33:22] local.ERROR: SyntaxError: Unexpected token ';'. Expected an opening '(' before a method's parameter list. https://helpdesk.vm/flux/flux.js?id=6710af97 1 0 SyntaxError Unexpected token ';'. Expected an opening '(' before a method's parameter list. {"url":"https://helpdesk.vm/admin/helpdesk/tickets/archived","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-08T08:33:22.647Z"}
|
||||
[2026-09-08 08:33:22] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/_debugbar/assets?type=js&mtime=1785738196 390 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/admin/helpdesk/tickets/archived","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-08T08:33:22.660Z"}
|
||||
[2026-09-08 08:33:22] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/_debugbar/assets?type=js&mtime=1785738196 390 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/admin/helpdesk/tickets/archived","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-08T08:33:22.660Z"}
|
||||
[2026-09-08 08:33:22] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/livewire-b2431d8a/livewire.js?id=26bbdf42 386 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/admin/helpdesk/tickets/archived","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-08T08:33:22.664Z"}
|
||||
[2026-09-08 08:33:22] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/livewire-b2431d8a/livewire.js?id=26bbdf42 386 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/admin/helpdesk/tickets/archived","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-08T08:33:22.664Z"}
|
||||
[2026-09-08 08:33:22] local.ERROR: ReferenceError: Can't find variable: PhpDebugBar https://helpdesk.vm/admin/helpdesk/tickets/archived 677 36 ReferenceError Can't find variable: PhpDebugBar renderDebugbar@https://helpdesk.vm/admin/helpdesk/tickets/archived:677:36 {"url":"https://helpdesk.vm/admin/helpdesk/tickets/archived","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-08T08:33:22.671Z"}
|
||||
[2026-09-08 08:33:22] local.ERROR: ReferenceError: Can't find variable: PhpDebugBar https://helpdesk.vm/admin/helpdesk/tickets/archived 677 36 ReferenceError Can't find variable: PhpDebugBar renderDebugbar@https://helpdesk.vm/admin/helpdesk/tickets/archived:677:36 {"url":"https://helpdesk.vm/admin/helpdesk/tickets/archived","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-08T08:33:22.671Z"}
|
||||
[2026-09-08 08:33:24] local.ERROR: SyntaxError: Unexpected token ';'. Expected an opening '(' before a method's parameter list. https://helpdesk.vm/flux/flux.js?id=6710af97 1 0 SyntaxError Unexpected token ';'. Expected an opening '(' before a method's parameter list. {"url":"https://helpdesk.vm/admin/helpdesk/tickets","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-08T08:33:24.481Z"}
|
||||
[2026-09-08 08:33:24] local.ERROR: SyntaxError: Unexpected token ';'. Expected an opening '(' before a method's parameter list. https://helpdesk.vm/flux/flux.js?id=6710af97 1 0 SyntaxError Unexpected token ';'. Expected an opening '(' before a method's parameter list. {"url":"https://helpdesk.vm/admin/helpdesk/tickets","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-08T08:33:24.481Z"}
|
||||
[2026-09-08 08:33:24] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/_debugbar/assets?type=js&mtime=1785738196 390 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/admin/helpdesk/tickets","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-08T08:33:24.496Z"}
|
||||
[2026-09-08 08:33:24] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/_debugbar/assets?type=js&mtime=1785738196 390 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/admin/helpdesk/tickets","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-08T08:33:24.496Z"}
|
||||
[2026-09-08 08:33:24] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/livewire-b2431d8a/livewire.js?id=26bbdf42 386 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/admin/helpdesk/tickets","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-08T08:33:24.500Z"}
|
||||
[2026-09-08 08:33:24] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/livewire-b2431d8a/livewire.js?id=26bbdf42 386 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/admin/helpdesk/tickets","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-08T08:33:24.501Z"}
|
||||
[2026-09-08 08:33:24] local.ERROR: ReferenceError: Can't find variable: PhpDebugBar https://helpdesk.vm/admin/helpdesk/tickets 681 36 ReferenceError Can't find variable: PhpDebugBar renderDebugbar@https://helpdesk.vm/admin/helpdesk/tickets:681:36 {"url":"https://helpdesk.vm/admin/helpdesk/tickets","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-08T08:33:24.506Z"}
|
||||
[2026-09-08 08:33:24] local.ERROR: ReferenceError: Can't find variable: PhpDebugBar https://helpdesk.vm/admin/helpdesk/tickets 681 36 ReferenceError Can't find variable: PhpDebugBar renderDebugbar@https://helpdesk.vm/admin/helpdesk/tickets:681:36 {"url":"https://helpdesk.vm/admin/helpdesk/tickets","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-08T08:33:24.506Z"}
|
||||
[2026-09-08 08:33:26] local.ERROR: SyntaxError: Unexpected token ';'. Expected an opening '(' before a method's parameter list. https://helpdesk.vm/flux/flux.js?id=6710af97 1 0 SyntaxError Unexpected token ';'. Expected an opening '(' before a method's parameter list. {"url":"https://helpdesk.vm/dashboard","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-08T08:33:26.114Z"}
|
||||
[2026-09-08 08:33:26] local.ERROR: SyntaxError: Unexpected token ';'. Expected an opening '(' before a method's parameter list. https://helpdesk.vm/flux/flux.js?id=6710af97 1 0 SyntaxError Unexpected token ';'. Expected an opening '(' before a method's parameter list. {"url":"https://helpdesk.vm/dashboard","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-08T08:33:26.114Z"}
|
||||
[2026-09-08 08:33:26] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/_debugbar/assets?type=js&mtime=1785738196 390 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/dashboard","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-08T08:33:26.129Z"}
|
||||
[2026-09-08 08:33:26] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/_debugbar/assets?type=js&mtime=1785738196 390 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/dashboard","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-08T08:33:26.130Z"}
|
||||
[2026-09-08 08:33:26] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/livewire-b2431d8a/livewire.js?id=26bbdf42 386 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/dashboard","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-08T08:33:26.135Z"}
|
||||
[2026-09-08 08:33:26] local.ERROR: SyntaxError: Unexpected token '.' https://helpdesk.vm/livewire-b2431d8a/livewire.js?id=26bbdf42 386 0 SyntaxError Unexpected token '.' {"url":"https://helpdesk.vm/dashboard","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-08T08:33:26.135Z"}
|
||||
[2026-09-08 08:33:26] local.ERROR: ReferenceError: Can't find variable: PhpDebugBar https://helpdesk.vm/dashboard 587 36 ReferenceError Can't find variable: PhpDebugBar renderDebugbar@https://helpdesk.vm/dashboard:587:36
|
||||
[native code]
|
||||
promiseReactionJob@[native code] {"url":"https://helpdesk.vm/dashboard","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-08T08:33:26.195Z"}
|
||||
[2026-09-08 08:33:26] local.ERROR: ReferenceError: Can't find variable: PhpDebugBar https://helpdesk.vm/dashboard 587 36 ReferenceError Can't find variable: PhpDebugBar renderDebugbar@https://helpdesk.vm/dashboard:587:36
|
||||
[native code]
|
||||
promiseReactionJob@[native code] {"url":"https://helpdesk.vm/dashboard","user_agent":"Mozilla/5.0 (iPad; CPU OS 12_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/92.0.4515.90 Mobile/15E148 Safari/604.1","timestamp":"2026-09-08T08:33:26.195Z"}
|
||||
Reference in New Issue
Block a user