diff --git a/CloudVeilManager/app/Http/Controllers/Admin/AppUserActivationCrudController.php b/CloudVeilManager/app/Http/Controllers/Admin/AppUserActivationCrudController.php
index 322a941..9a24ffe 100644
--- a/CloudVeilManager/app/Http/Controllers/Admin/AppUserActivationCrudController.php
+++ b/CloudVeilManager/app/Http/Controllers/Admin/AppUserActivationCrudController.php
@@ -4,6 +4,8 @@
use Backpack\CRUD\app\Http\Controllers\CrudController;
use Backpack\CRUD\app\Library\CrudPanel\CrudPanelFacade as CRUD;
+use App\Models\User;
+use App\Models\SystemPlatform;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
@@ -23,7 +25,7 @@ class AppUserActivationCrudController extends CrudController
}
- /**
+ /**
* Configure the CrudPanel object. Apply settings to all operations.
*
* @return void
@@ -45,67 +47,56 @@ protected function setupListOperation()
{
$this->crud->setColumns([
[
- 'label' => 'User',
- 'type' => 'select',
- 'name' => 'user_id',
- 'attribute' => 'name',
- 'key' => 'user_name',
+ 'label' => 'Device',
+ 'type' => 'custom_html',
+ 'name' => 'device',
+ 'value' => function ($entry) {
+ $friendlyName = $entry->friendly_name ?: '-';
+ $deviceId = $entry->device_id ?: '-';
+ return '
' . e($friendlyName) . '
' . e($deviceId) . '
';
+ },
+ 'escaped' => false,
'priority' => 1
],
[
- 'label' => 'E-Mail',
- 'type' => 'select',
+ 'label' => 'User',
+ 'type' => 'custom_html',
'name' => 'user_id',
- 'attribute' => 'email',
- 'key' => 'user_email',
- 'priority' => 2
- ],
- [
- 'label' => 'Device ID',
- 'type' => 'text',
- 'name' => 'device_id',
- 'priority' => 1
- ],
- [
- 'label' => 'IP Address',
- 'type' => 'text',
- 'name' => 'ip_address',
+ 'value' => function ($entry) {
+ $user = $entry->user;
+ if (!$user) {
+ return '-';
+ }
+ return '' . e($user->name) . '
' . e($user->email) . '
';
+ },
+ 'escaped' => false,
'priority' => 1
],
[
- 'label' => 'Bypass',
- 'type' => 'text',
- 'name' => 'bypass_formatted',
+ 'label' => 'Group',
+ 'type' => 'select',
+ 'name' => 'group_id',
+ 'attribute' => 'name',
+ 'entity' => 'group',
+ 'key' => 'group_name',
'priority' => 1
],
[
'label' => 'Version',
- 'type' => 'text',
- 'name' => 'app_version',
- 'priority' => 1
- ],
- [
- 'label' => 'Updated at',
- 'type' => 'datetime',
- 'name' => 'updated_at',
- 'priority' => 1
- ],
- [
- 'label' => 'OS',
- 'type' => 'text',
- 'name' => 'os_formatted',
+ 'type' => 'custom_html',
+ 'name' => 'version',
+ 'value' => function ($entry) {
+ $appVersion = $entry->app_version ?: '-';
+ $osFormatted = $entry->os_formatted ?: '-';
+ return '' . e($appVersion) . '
' . e($osFormatted) . '
';
+ },
+ 'escaped' => false,
'priority' => 1,
- 'orderable' => true,
+ 'orderable' => true,
'orderLogic' => function ($query, $column, $columnDirection) {
return $query->orderBy('platform_name', $columnDirection);
}
],
- [
- 'label' => 'Friendly Name',
- 'type' => 'text',
- 'name' => 'friendly_name',
- 'priority' => 2
- ],
[
'label' => 'Identifier',
'type' => 'hidden',
@@ -113,6 +104,59 @@ protected function setupListOperation()
'searchLogic' => 'text'
]
]);
+
+ // Platform filter
+ CRUD::filter('platform_name')
+ ->type('dropdown')
+ ->label('Platform')
+ ->values([
+ SystemPlatform::PLATFORM_WIN => 'Windows',
+ SystemPlatform::PLATFORM_OSX => 'macOS',
+ ])
+ ->whenActive(function ($value) {
+ CRUD::addClause('where', 'platform_name', $value);
+ });
+
+ // App Version filter
+ CRUD::filter('app_version')
+ ->type('text')
+ ->label('App Version')
+ ->whenActive(function ($value) {
+ CRUD::addClause('where', 'app_version', 'LIKE', "%{$value}%");
+ });
+
+ // User filter
+ CRUD::filter('user_id')
+ ->type('select2')
+ ->label('User')
+ ->values(function () {
+ return User::all()->pluck('name', 'id')->toArray();
+ })
+ ->whenActive(function ($value) {
+ CRUD::addClause('where', 'user_id', $value);
+ });
+
+ // Last Sync Time filter
+ CRUD::filter('last_sync_time')
+ ->type('date_range')
+ ->label('Last Sync Time')
+ ->whenActive(function ($value) {
+ $dates = json_decode($value);
+ if ($dates->from) {
+ CRUD::addClause('where', 'last_sync_time', '>=', $dates->from);
+ }
+ if ($dates->to) {
+ CRUD::addClause('where', 'last_sync_time', '<=', $dates->to . ' 23:59:59');
+ }
+ });
+
+ // OS Version filter
+ CRUD::filter('os_version')
+ ->type('text')
+ ->label('OS Version')
+ ->whenActive(function ($value) {
+ CRUD::addClause('where', 'os_version', 'LIKE', "%{$value}%");
+ });
}
/**
@@ -123,10 +167,10 @@ protected function setupListOperation()
*/
protected function setupCreateOperation()
{
- CRUD::setValidation([
- ]);
+ CRUD::setValidation([]);
- $this->crud->addFields([
+ $this->crud->addFields(
+ [
[
'label' => 'User Name',
'type' => 'select',
diff --git a/CloudVeilManager/app/Http/Controllers/Admin/UserCrudController.php b/CloudVeilManager/app/Http/Controllers/Admin/UserCrudController.php
index 104c4cd..4aaaa47 100644
--- a/CloudVeilManager/app/Http/Controllers/Admin/UserCrudController.php
+++ b/CloudVeilManager/app/Http/Controllers/Admin/UserCrudController.php
@@ -61,8 +61,13 @@ protected function setupListOperation()
],
[
'label' => 'License Used',
- 'type' => 'datetime',
- 'name' => 'updated_at'
+ 'type' => 'text',
+ 'name' => 'license_used',
+ 'value' => function ($entry) {
+ $used = $entry->activations_used ?? 0;
+ $allowed = $entry->activations_allowed ?? 0;
+ return $used . ' of ' . $allowed;
+ }
],
[
'label' => 'Active',
@@ -106,12 +111,13 @@ protected function setupFields($fromEdit = true)
}
CRUD::setValidation($validationRules);
- $this->crud->addFields([
+ $this->crud->addFields(
+ [
[
'type' => 'custom_html',
'name' => 'activations',
'value' => '
- Show Activations
+ Show Activations
',
'tab' => 'Information',
],
@@ -119,37 +125,30 @@ protected function setupFields($fromEdit = true)
'label' => 'User Full Name',
'type' => 'text',
'name' => 'name',
- 'tab' => 'Information'
+ 'tab' => 'Information',
+ 'wrapper' => ['class' => 'form-group col-md-5'],
],
[
'label' => 'User E-Mail',
'type' => 'text',
'name' => 'email',
- 'tab' => 'Information'
+ 'tab' => 'Information',
+ 'wrapper' => ['class' => 'form-group col-md-5'],
],
[
'label' => 'Enabled',
'type' => 'switch',
'name' => 'is_enabled',
- 'tab' => 'Information'
- ],
- [
- 'label' => 'Customer ID',
- 'type' => 'number',
- 'name' => 'customer_id',
- 'tab' => 'Information'
- ],
- [
- 'label' => 'Password',
- 'type' => 'password',
- 'name' => 'password',
'tab' => 'Information',
- 'wrapper' => ['class' => 'form-group col-md-6'],
+ 'wrapper' => ['class' => 'form-group col-md-2 d-flex pt-3'],
],
[
- 'label' => 'Password Confirm',
- 'type' => 'password',
- 'name' => 'password_verify',
+ 'label' => 'Group',
+ 'type' => 'select2',
+ 'entity' => 'group',
+ 'model' => 'App\Models\Group',
+ 'name' => 'group',
+ 'attribute' => 'name',
'tab' => 'Information',
'wrapper' => ['class' => 'form-group col-md-6'],
],
@@ -157,16 +156,8 @@ protected function setupFields($fromEdit = true)
'label' => 'Activations Allowed',
'type' => 'number',
'name' => 'activations_allowed',
- 'tab' => 'Information'
- ],
- [
- 'label' => 'Group',
- 'type' => 'select2',
- 'entity' => 'group',
- 'model' => 'App\Models\Group',
- 'name' => 'group',
- 'attribute' => 'name',
- 'tab' => 'Information'
+ 'tab' => 'Information',
+ 'wrapper' => ['class' => 'form-group col-md-6'],
],
[
'label' => 'Roles',
@@ -175,21 +166,29 @@ protected function setupFields($fromEdit = true)
'model' => 'App\Models\Role',
'attribute' => 'display_name',
'name' => 'roles',
- 'tab' => 'Information'
+ 'tab' => 'Information',
+ 'wrapper' => ['class' => 'form-group col-md-6'],
],
[
- 'label' => 'Relaxed Policy Passcode',
+ 'label' => 'Password',
'type' => 'password',
+ 'name' => 'password',
+ 'tab' => 'Information',
+ 'wrapper' => ['class' => 'form-group col-md-6'],
+ ],
+ [
+ 'label' => 'Relaxed Policy Passcode',
+ 'type' => 'password_revealable',
'name' => 'relaxed_policy_passcode',
'tab' => 'Information',
- 'wrapper' => ['class' => 'form-group col-md-8'],
+ 'wrapper' => ['class' => 'form-group col-md-6'],
],
[
'label' => 'Enable Relaxed Policy Passcode',
'type' => 'switch',
'name' => 'enable_relaxed_policy_passcode',
'tab' => 'Information',
- 'wrapper' => ['class' => 'form-group col-md-2 d-flex pt-3'],
+ 'wrapper' => ['class' => 'form-group col-md-6 d-flex pt-3'],
],
[
'name' => 'BypassesPermitted',
@@ -334,7 +333,8 @@ protected function setupUpdateOperation()
$this->setupFields(true);
}
- protected function setupCreateOperation() {
+ protected function setupCreateOperation()
+ {
$this->setupFields(false);
}
diff --git a/CloudVeilManager/config/backpack/ui.php b/CloudVeilManager/config/backpack/ui.php
index ccd73d2..0d35c87 100644
--- a/CloudVeilManager/config/backpack/ui.php
+++ b/CloudVeilManager/config/backpack/ui.php
@@ -115,6 +115,8 @@
// JS files that are loaded in all pages, using Laravel's asset() helper
'scripts' => [
+ // Bootstrap 5 JavaScript - required for dropdowns and collapses
+ 'https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js',
// 'js/example.js',
// 'https://cdn.jsdelivr.net/npm/vue@2.4.4/dist/vue.min.js',
// 'https://cdn.jsdelivr.net/npm/react@16/umd/react.production.min.js',
diff --git a/CloudVeilManager/resources/js/bootstrap.js b/CloudVeilManager/resources/js/bootstrap.js
index 4d73ffb..f22804c 100644
--- a/CloudVeilManager/resources/js/bootstrap.js
+++ b/CloudVeilManager/resources/js/bootstrap.js
@@ -1,4 +1,6 @@
-import 'bootstrap';
+// Bootstrap is loaded via CDN in config/backpack/ui.php
+// This ensures window.bootstrap is available globally for Backpack's JavaScript
+// import 'bootstrap';
/**
* We'll load the axios HTTP library which allows us to easily issue requests
diff --git a/CloudVeilManager/resources/views/vendor/backpack/crud/fields/password_revealable.blade.php b/CloudVeilManager/resources/views/vendor/backpack/crud/fields/password_revealable.blade.php
new file mode 100644
index 0000000..444e786
--- /dev/null
+++ b/CloudVeilManager/resources/views/vendor/backpack/crud/fields/password_revealable.blade.php
@@ -0,0 +1,73 @@
+{{-- password_revealable --}}
+
+@php
+ $field['value'] = old_empty_or_null($field['name'], '') ?? ($field['value'] ?? ($field['default'] ?? ''));
+ // autocomplete off, if not otherwise specified
+ if (!isset($field['attributes']['autocomplete'])) {
+ $field['attributes']['autocomplete'] = "off";
+ }
+@endphp
+
+@include('crud::fields.inc.wrapper_start')
+ {!! $field['label'] !!}
+ @include('crud::fields.inc.translatable_icon')
+
+
+
+ {{-- HINT --}}
+ @if (isset($field['hint']))
+ {!! $field['hint'] !!}
+ @endif
+@include('crud::fields.inc.wrapper_end')
+
+{{-- FIELD JS - will be loaded in the after_scripts section --}}
+@push('crud_fields_scripts')
+
+@endpush
+