diff --git a/modules/backend/ServiceProvider.php b/modules/backend/ServiceProvider.php index c81552de9d..8d352d294d 100644 --- a/modules/backend/ServiceProvider.php +++ b/modules/backend/ServiceProvider.php @@ -1,13 +1,19 @@ registerMailer(); $this->registerAssetBundles(); $this->registerBackendPermissions(); + $this->registerBackendUserEvents(); /* * Backend specific @@ -207,6 +214,28 @@ protected function registerBackendPermissions() }); } + /** + * Register the backend user events + */ + protected function registerBackendUserEvents() + { + Event::listen('backend.user.login', function (\Backend\Models\User $user) { + // @TODO: Deprecate this, and only run migrations when it makes sense + $runMigrationsOnLogin = (bool) Config::get('cms.runMigrationsOnLogin', Config::get('app.debug', false)); + if ($runMigrationsOnLogin) { + try { + // Load version updates + UpdateManager::instance()->update(); + } catch (Exception $e) { + Flash::error($e->getMessage()); + } + } + + // Log the sign in event + AccessLog::add($user); + }); + } + /* * Register widgets */ diff --git a/modules/backend/controllers/Auth.php b/modules/backend/controllers/Auth.php index 82a39dec65..8ed4ecef42 100644 --- a/modules/backend/controllers/Auth.php +++ b/modules/backend/controllers/Auth.php @@ -4,13 +4,11 @@ use Backend; use BackendAuth; use Backend\Classes\Controller; -use Backend\Models\AccessLog; use Config; use Exception; use Flash; use Mail; use Request; -use System\Classes\UpdateManager; use ValidationException; use Validator; use Winter\Storm\Foundation\Http\Middleware\CheckForTrustedHost; @@ -94,20 +92,6 @@ public function signin_onSubmit() 'password' => post('password') ], $remember); - $runMigrationsOnLogin = (bool) Config::get('cms.runMigrationsOnLogin', Config::get('app.debug', false)); - - if ($runMigrationsOnLogin) { - try { - // Load version updates - UpdateManager::instance()->update(); - } catch (Exception $ex) { - Flash::error($ex->getMessage()); - } - } - - // Log the sign in event - AccessLog::add($user); - // Redirect to the intended page after successful sign in return Backend::redirectIntended('backend'); } diff --git a/modules/backend/formwidgets/RecordFinder.php b/modules/backend/formwidgets/RecordFinder.php index 982e12dc01..0e5799cf0d 100644 --- a/modules/backend/formwidgets/RecordFinder.php +++ b/modules/backend/formwidgets/RecordFinder.php @@ -60,7 +60,7 @@ class RecordFinder extends FormWidgetBase /** * @var string Prompt to display if no record is selected. */ - public $prompt = 'Click the %s button to find a record'; + public $prompt = null; /** * @var int Maximum rows to display for each page. @@ -144,6 +144,10 @@ public function init() 'modelClass', ]); + if (!isset($this->prompt)) { + $this->prompt = Lang::get('backend::lang.recordfinder.default_prompt'); + } + if (!$this->useRelation && !class_exists($this->modelClass)) { throw new ApplicationException(Lang::get('backend::lang.recordfinder.invalid_model_class', ['modelClass' => $this->modelClass])); } diff --git a/modules/backend/formwidgets/recordfinder/partials/_recordfinder.php b/modules/backend/formwidgets/recordfinder/partials/_recordfinder.php index 79ad7f4fe9..3ad24d971a 100644 --- a/modules/backend/formwidgets/recordfinder/partials/_recordfinder.php +++ b/modules/backend/formwidgets/recordfinder/partials/_recordfinder.php @@ -10,7 +10,13 @@ class="field-recordfinder loading-indicator-container size-input-text" data-control="recordfinder" data-refresh-handler="getEventHandler('onRefresh') ?>" data-data-locker="#getId() ?>"> - > + + data-control="popup" + data-size="huge" + data-handler="getEventHandler('onFindRecord') ?>" + data-request-data="recordfinder_flag: 1" + > diff --git a/modules/backend/formwidgets/repeater/assets/js/repeater.js b/modules/backend/formwidgets/repeater/assets/js/repeater.js index 6c80b47733..c72ef23063 100644 --- a/modules/backend/formwidgets/repeater/assets/js/repeater.js +++ b/modules/backend/formwidgets/repeater/assets/js/repeater.js @@ -269,7 +269,7 @@ return $textInput.val() } } else { - var $disabledTextInput = $('.text-field:first > .form-control', $target) + var $disabledTextInput = $('.form-control:first', $target) if ($disabledTextInput.length) { return $disabledTextInput.text() } diff --git a/modules/backend/lang/en/lang.php b/modules/backend/lang/en/lang.php index 83fabed70e..5c1a96f55b 100644 --- a/modules/backend/lang/en/lang.php +++ b/modules/backend/lang/en/lang.php @@ -312,6 +312,7 @@ ], 'recordfinder' => [ 'find_record' => 'Find Record', + 'default_prompt' => 'Click the %s button to find a record', 'invalid_model_class' => 'The provided model class ":modelClass" for the recordfinder is invalid', 'cancel' => 'Cancel', ], diff --git a/modules/backend/lang/fr/lang.php b/modules/backend/lang/fr/lang.php index b0250c4d30..251d800c18 100644 --- a/modules/backend/lang/fr/lang.php +++ b/modules/backend/lang/fr/lang.php @@ -310,6 +310,7 @@ 'return_to_list' => 'Retourner à la liste' ], 'recordfinder' => [ + 'default_prompt' => 'Cliquer sur %s pour chercher un enregistrement', 'find_record' => 'Trouver un enregistrement', 'invalid_model_class' => "La classe du modèle \":modelClass\" fournie pour le recordfinder n'est pas valide.", 'cancel' => 'Annuler', diff --git a/modules/backend/layouts/_head.php b/modules/backend/layouts/_head.php index 0ff93ceb75..16c794cb2d 100644 --- a/modules/backend/layouts/_head.php +++ b/modules/backend/layouts/_head.php @@ -1,7 +1,7 @@ - + diff --git a/modules/backend/layouts/auth.php b/modules/backend/layouts/auth.php index ec65941199..a227a7a06f 100644 --- a/modules/backend/layouts/auth.php +++ b/modules/backend/layouts/auth.php @@ -4,7 +4,7 @@ - + diff --git a/modules/backend/models/User.php b/modules/backend/models/User.php index 4063c716c2..37c8892a18 100644 --- a/modules/backend/models/User.php +++ b/modules/backend/models/User.php @@ -1,10 +1,10 @@ getSaveData(true); + $saveData = $this->getSaveData(); /** * @event backend.form.beforeRefresh @@ -1172,10 +1172,9 @@ protected function showFieldLabels($field) /** * Returns post data from a submitted form. */ - public function getSaveData(bool $includeAllFields = false): array + public function getSaveData(): array { $this->defineFormFields(); - $this->applyFiltersFromModel(); $result = []; @@ -1194,7 +1193,7 @@ public function getSaveData(bool $includeAllFields = false): array /* * Disabled and hidden should be omitted from data set */ - if (!$includeAllFields && ($field->disabled || $field->hidden)) { + if ($field->disabled || $field->hidden) { continue; } diff --git a/modules/cms/console/CreateTheme.php b/modules/cms/console/CreateTheme.php index 29a5f91966..00b1196b6f 100644 --- a/modules/cms/console/CreateTheme.php +++ b/modules/cms/console/CreateTheme.php @@ -1,6 +1,8 @@ 'version.yaml', ], 'tailwind' => [ - 'scaffold/theme/tailwind/assets/src/css/base.stub' => 'assets/src/css/base.css', - 'scaffold/theme/tailwind/assets/src/css/custom.stub' => 'assets/src/css/custom.css', - 'scaffold/theme/tailwind/assets/src/css/theme.stub' => 'assets/src/css/theme.css', - 'scaffold/theme/tailwind/assets/src/js/theme.stub' => 'assets/src/js/theme.js', 'scaffold/theme/tailwind/lang/en/lang.stub' => 'lang/en/lang.php', 'scaffold/theme/tailwind/layouts/default.stub' => 'layouts/default.htm', 'scaffold/theme/tailwind/pages/404.stub' => 'pages/404.htm', @@ -68,12 +71,9 @@ class CreateTheme extends GeneratorCommand 'scaffold/theme/tailwind/partials/site/header.stub' => 'partials/site/header.htm', 'scaffold/theme/tailwind/partials/site/footer.stub' => 'partials/site/footer.htm', 'scaffold/theme/tailwind/.gitignore.stub' => '.gitignore', - 'scaffold/theme/tailwind/package.stub' => 'package.json', 'scaffold/theme/tailwind/README.stub' => 'README.md', - 'scaffold/theme/tailwind/tailwind.config.stub' => 'tailwind.config.js', 'scaffold/theme/tailwind/theme.stub' => 'theme.yaml', 'scaffold/theme/tailwind/version.stub' => 'version.yaml', - 'scaffold/theme/tailwind/winter.mix.stub' => 'winter.mix.js', ], ]; @@ -90,12 +90,13 @@ protected function getNameInput(): string */ protected function prepareVars(): array { - $scaffold = $this->argument('scaffold') ?? 'tailwind'; + $this->scaffold = $this->argument('scaffold') ?? 'tailwind'; + $validOptions = $this->suggestScaffoldValues(); - if (!in_array($scaffold, $validOptions)) { - throw new InvalidArgumentException("$scaffold is not an available theme scaffold type (Available types: " . implode(', ', $validOptions) . ')'); + if (!in_array($this->scaffold, $validOptions)) { + throw new InvalidArgumentException("$this->scaffold is not an available theme scaffold type (Available types: " . implode(', ', $validOptions) . ')'); } - $this->stubs = $this->themeScaffolds[$scaffold]; + $this->stubs = $this->themeScaffolds[$this->scaffold]; return [ 'code' => $this->getNameInput(), @@ -146,4 +147,71 @@ public function makeStub($stubName) $this->files->put($destinationFile, $destinationContent); } + + public function makeStubs(): void + { + parent::makeStubs(); + + if ($this->scaffold === 'tailwind') { + // @TODO: allow support for mix here + $this->tailwindPostCreate('vite'); + } + } + + protected function tailwindPostCreate(string $processor): void + { + if ($this->call('npm:version', ['--silent' => true, '--compatible' => true]) !== 0) { + throw new SystemException(sprintf( + 'NPM is not installed or is outdated, please ensure NPM >= v7.0 is available and then manually set up %s.', + $processor + )); + } + + $commands = [ + // Set up the vite config files + $processor . ':create' => [ + 'message' => 'Generating ' . $processor . ' + tailwind config...', + 'args' => [ + 'packageName' => 'theme-' . $this->getNameInput(), + '--no-interaction' => true, + '--force' => true, + '--silent' => true, + '--tailwind' => true + ] + ], + // Ensure all require packages are available for the new theme and add the new theme to our npm workspaces + $processor . ':install' => [ + 'message' => 'Installing NPM dependencies...', + 'args' => [ + 'assetPackage' => ['theme-' . $this->getNameInput()], + '--no-interaction' => true, + '--silent' => false, + '--disable-tty' => true + ] + ], + // Run an initial compile to ensure styles are available for first load + $processor . ':compile' => [ + 'message' => 'Compiling your theme...', + 'args' => [ + '--package' => ['theme-' . $this->getNameInput()], + '--no-interaction' => true, + '--silent' => true, + ] + ] + ]; + + foreach ($commands as $command => $data) { + $this->info($data['message']); + + // Handle commands throwing errors + if ($this->call($command, $data['args']) !== 0) { + throw new SystemException(sprintf('Post create command `%s` failed, please review manually.', $command)); + } + + // Force PackageManger to reset available packages + if ($command === $processor . ':create') { + PackageManager::forgetInstance(); + } + } + } } diff --git a/modules/cms/console/scaffold/theme/tailwind/assets/src/css/base.stub b/modules/cms/console/scaffold/theme/tailwind/assets/src/css/base.stub deleted file mode 100644 index b5c61c9567..0000000000 --- a/modules/cms/console/scaffold/theme/tailwind/assets/src/css/base.stub +++ /dev/null @@ -1,3 +0,0 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; diff --git a/modules/cms/console/scaffold/theme/tailwind/assets/src/css/custom.stub b/modules/cms/console/scaffold/theme/tailwind/assets/src/css/custom.stub deleted file mode 100644 index 5fc1ea54e5..0000000000 --- a/modules/cms/console/scaffold/theme/tailwind/assets/src/css/custom.stub +++ /dev/null @@ -1,3 +0,0 @@ -/** - * Custom CSS for theme goes here - */ diff --git a/modules/cms/console/scaffold/theme/tailwind/assets/src/css/theme.stub b/modules/cms/console/scaffold/theme/tailwind/assets/src/css/theme.stub deleted file mode 100644 index b020ae8833..0000000000 --- a/modules/cms/console/scaffold/theme/tailwind/assets/src/css/theme.stub +++ /dev/null @@ -1,2 +0,0 @@ -@import 'base.css'; -@import 'custom.css'; diff --git a/modules/cms/console/scaffold/theme/tailwind/assets/src/js/theme.stub b/modules/cms/console/scaffold/theme/tailwind/assets/src/js/theme.stub deleted file mode 100644 index 416aa12526..0000000000 --- a/modules/cms/console/scaffold/theme/tailwind/assets/src/js/theme.stub +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Application - */ -(function($) { - "use strict"; - - jQuery(document).ready(function($) { - /*------------------------------- - WINTER CMS FLASH MESSAGE HANDLING - ---------------------------------*/ - $(document).on('ajaxSetup', function(event, context) { - // Enable AJAX handling of Flash messages on all AJAX requests - context.options.flash = true; - - // Enable the StripeLoadIndicator on all AJAX requests - context.options.loading = $.oc.stripeLoadIndicator; - - // Handle Flash Messages - context.options.handleFlashMessage = function(message, type) { - $.oc.flashMsg({ text: message, class: type }); - }; - - // Handle Error Messages - context.options.handleErrorMessage = function(message) { - $.oc.flashMsg({ text: message, class: 'error' }); - }; - }); - }); -}(jQuery)); - -if (typeof(gtag) !== 'undefined' && typeof(gtag) !== 'function') { - gtag = function() { console.log('GoogleAnalytics not present.'); } -} diff --git a/modules/cms/console/scaffold/theme/tailwind/package.stub b/modules/cms/console/scaffold/theme/tailwind/package.stub deleted file mode 100644 index 51ba79a043..0000000000 --- a/modules/cms/console/scaffold/theme/tailwind/package.stub +++ /dev/null @@ -1,12 +0,0 @@ -{ - "name": "{{code}}", - "private": true, - "version": "1.0.0", - "devDependencies": { - "postcss": "~8.4.x", - "postcss-import": "~14.1.x", - "tailwindcss": "~3.0.x" - }, - "dependencies": { - } -} diff --git a/modules/cms/console/scaffold/theme/tailwind/partials/meta/styles.stub b/modules/cms/console/scaffold/theme/tailwind/partials/meta/styles.stub index fdcc745eab..154e01dcc7 100644 --- a/modules/cms/console/scaffold/theme/tailwind/partials/meta/styles.stub +++ b/modules/cms/console/scaffold/theme/tailwind/partials/meta/styles.stub @@ -1,19 +1,5 @@ == -find('dist/css/theme.css'); - if ($styles) { - $this['lastmodified'] = $styles->mtime; - } else { - throw new \Exception("Asset files were not detected, try running artisan mix:install && artisan mix:compile -p theme-{{code}}"); - } -} -?> -== - +{{ vite(['assets/src/css/theme-{{code}}.css'], 'theme-{{code}}') }}