updaetd deployer
This commit is contained in:
@@ -5,7 +5,6 @@ declare(strict_types=1);
|
|||||||
namespace Modules\Helpdesk\Providers;
|
namespace Modules\Helpdesk\Providers;
|
||||||
|
|
||||||
use Illuminate\Support\Facades\Blade;
|
use Illuminate\Support\Facades\Blade;
|
||||||
use Illuminate\Support\Facades\Config;
|
|
||||||
use Illuminate\Support\Facades\File;
|
use Illuminate\Support\Facades\File;
|
||||||
use Illuminate\Support\Facades\Gate;
|
use Illuminate\Support\Facades\Gate;
|
||||||
use Illuminate\Support\ServiceProvider;
|
use Illuminate\Support\ServiceProvider;
|
||||||
@@ -136,14 +135,19 @@ final class HelpdeskServiceProvider extends ServiceProvider
|
|||||||
*/
|
*/
|
||||||
protected function registerViews(): void
|
protected function registerViews(): void
|
||||||
{
|
{
|
||||||
$viewPath = resource_path('views/modules/'.ModuleInfo::nameLower());
|
|
||||||
$sourcePath = module_path(ModuleInfo::name(), 'Resources/views');
|
$sourcePath = module_path(ModuleInfo::name(), 'Resources/views');
|
||||||
|
$themeRoot = rtrim((string) config('stylist.themes_path', resource_path('themes')), DIRECTORY_SEPARATOR);
|
||||||
|
$backendTheme = (string) config('stylist.default_backend_theme', 'backend');
|
||||||
|
$viewPath = $themeRoot.DIRECTORY_SEPARATOR.$backendTheme
|
||||||
|
.DIRECTORY_SEPARATOR.'views'.DIRECTORY_SEPARATOR.'modules'.DIRECTORY_SEPARATOR.ModuleInfo::nameLower();
|
||||||
|
|
||||||
|
// Module source views remain module-owned. Any application override is
|
||||||
|
// published into the selected backend theme, never resources/views.
|
||||||
$this->publishes([
|
$this->publishes([
|
||||||
$sourcePath => $viewPath,
|
$sourcePath => $viewPath,
|
||||||
], ['views', ModuleInfo::nameLower().'-module-views']);
|
], ['views', ModuleInfo::nameLower().'-module-views']);
|
||||||
|
|
||||||
$this->loadViewsFrom(array_merge($this->getPublishableViewPaths(), [$sourcePath]), ModuleInfo::nameLower());
|
$this->loadViewsFrom($sourcePath, ModuleInfo::nameLower());
|
||||||
|
|
||||||
Blade::componentNamespace('Modules\Helpdesk\View\Components', 'helpdesk');
|
Blade::componentNamespace('Modules\Helpdesk\View\Components', 'helpdesk');
|
||||||
Blade::anonymousComponentPath($sourcePath.'/components', 'helpdesk');
|
Blade::anonymousComponentPath($sourcePath.'/components', 'helpdesk');
|
||||||
@@ -165,24 +169,6 @@ final class HelpdeskServiceProvider extends ServiceProvider
|
|||||||
$this->loadTranslationsFrom(module_path(ModuleInfo::name(), 'Resources/lang'), ModuleInfo::nameLower());
|
$this->loadTranslationsFrom(module_path(ModuleInfo::name(), 'Resources/lang'), ModuleInfo::nameLower());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get publishable view override paths.
|
|
||||||
*
|
|
||||||
* @return array<int, string>
|
|
||||||
*/
|
|
||||||
private function getPublishableViewPaths(): array
|
|
||||||
{
|
|
||||||
$paths = [];
|
|
||||||
|
|
||||||
foreach (Config::get('view.paths') as $path) {
|
|
||||||
if (is_dir($path.'/modules/'.ModuleInfo::nameLower())) {
|
|
||||||
$paths[] = $path.'/modules/'.ModuleInfo::nameLower();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $paths;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get provided services.
|
* Get provided services.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -73,6 +73,7 @@ final class StylistServiceProvider extends ServiceProvider
|
|||||||
|
|
||||||
$this->app->booted(function (): void {
|
$this->app->booted(function (): void {
|
||||||
$this->registerSelectedThemeOverrides();
|
$this->registerSelectedThemeOverrides();
|
||||||
|
$this->registerSelectedThemeFluxOverrides();
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -218,7 +219,14 @@ final class StylistServiceProvider extends ServiceProvider
|
|||||||
// boot order and incremental prependLocation() calls. Theme paths stay first;
|
// boot order and incremental prependLocation() calls. Theme paths stay first;
|
||||||
// Laravel's normal view locations remain as the final fallback.
|
// Laravel's normal view locations remain as the final fallback.
|
||||||
if (method_exists($finder, 'getPaths') && method_exists($finder, 'setPaths')) {
|
if (method_exists($finder, 'getPaths') && method_exists($finder, 'setPaths')) {
|
||||||
$existingPaths = $finder->getPaths();
|
// The application intentionally has no resources/views tree. Laravel's
|
||||||
|
// default FileViewFinder still starts with that location, and view:cache
|
||||||
|
// asks Symfony Finder to scan every registered path. Remove missing legacy
|
||||||
|
// locations so theme-only applications can be optimized on a clean release.
|
||||||
|
$existingPaths = array_values(array_filter(
|
||||||
|
$finder->getPaths(),
|
||||||
|
static fn (string $path): bool => is_dir($path),
|
||||||
|
));
|
||||||
$paths = array_values(array_unique(array_merge($themePaths, $existingPaths)));
|
$paths = array_values(array_unique(array_merge($themePaths, $existingPaths)));
|
||||||
$finder->setPaths($paths);
|
$finder->setPaths($paths);
|
||||||
|
|
||||||
@@ -236,6 +244,78 @@ final class StylistServiceProvider extends ServiceProvider
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make Flux application overrides theme-owned.
|
||||||
|
*
|
||||||
|
* Flux normally discovers custom components from resources/views/flux. This
|
||||||
|
* application deliberately has no resources/views tree, so expose the selected
|
||||||
|
* theme's views/flux directory through Flux's existing view namespace instead.
|
||||||
|
* Package-provided Flux views remain available as the final fallback.
|
||||||
|
*/
|
||||||
|
private function registerSelectedThemeFluxOverrides(): void
|
||||||
|
{
|
||||||
|
$stylist = $this->app->make(Stylist::class);
|
||||||
|
$orderedThemes = [$stylist->current(), $stylist->frontend(), $stylist->backend()];
|
||||||
|
$keys = [];
|
||||||
|
|
||||||
|
foreach ($orderedThemes as $theme) {
|
||||||
|
foreach ($this->themeChain($theme) as $key) {
|
||||||
|
if (! in_array($key, $keys, true)) {
|
||||||
|
$keys[] = $key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! in_array('common', $keys, true)) {
|
||||||
|
$keys[] = 'common';
|
||||||
|
}
|
||||||
|
|
||||||
|
$themeFluxPaths = [];
|
||||||
|
|
||||||
|
foreach ($keys as $key) {
|
||||||
|
try {
|
||||||
|
$theme = $this->app->make(Loader::class)->find($key);
|
||||||
|
} catch (\Throwable) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$fluxPath = $theme->path().DIRECTORY_SEPARATOR.'views'.DIRECTORY_SEPARATOR.'flux';
|
||||||
|
|
||||||
|
if (is_dir($fluxPath)) {
|
||||||
|
$themeFluxPaths[] = $fluxPath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($themeFluxPaths === []) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$finder = View::getFinder();
|
||||||
|
|
||||||
|
if (! method_exists($finder, 'getHints')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$hints = $finder->getHints();
|
||||||
|
$existingFluxPaths = array_values(array_filter(
|
||||||
|
(array) ($hints['flux'] ?? []),
|
||||||
|
static fn (string $path): bool => is_dir($path),
|
||||||
|
));
|
||||||
|
$paths = array_values(array_unique(array_merge($themeFluxPaths, $existingFluxPaths)));
|
||||||
|
|
||||||
|
if (method_exists($finder, 'replaceNamespace')) {
|
||||||
|
$finder->replaceNamespace('flux', $paths);
|
||||||
|
} else {
|
||||||
|
foreach (array_reverse($themeFluxPaths) as $fluxPath) {
|
||||||
|
View::prependNamespace('flux', $fluxPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (method_exists($finder, 'flush')) {
|
||||||
|
$finder->flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** @return array<int, string> */
|
/** @return array<int, string> */
|
||||||
private function themeChain(Theme $theme): array
|
private function themeChain(Theme $theme): array
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -42,4 +42,23 @@ final class WelcomeThemeViewTest extends TestCase
|
|||||||
$this->assertFileExists(resource_path('themes/backend/assets/css/app.css'));
|
$this->assertFileExists(resource_path('themes/backend/assets/css/app.css'));
|
||||||
$this->assertFileExists(resource_path('themes/backend/assets/js/passkeys.js'));
|
$this->assertFileExists(resource_path('themes/backend/assets/js/passkeys.js'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function test_view_finder_contains_only_existing_application_view_locations(): void
|
||||||
|
{
|
||||||
|
foreach (view()->getFinder()->getPaths() as $path) {
|
||||||
|
$this->assertDirectoryExists($path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_backend_flux_icon_overrides_are_owned_by_the_backend_theme(): void
|
||||||
|
{
|
||||||
|
$this->assertTrue(view()->exists('flux::icon.folder-git-2'));
|
||||||
|
$this->assertTrue(view()->exists('flux::icon.book-open-text'));
|
||||||
|
$this->assertTrue(view()->exists('flux::icon.chevrons-up-down'));
|
||||||
|
|
||||||
|
$this->assertStringContainsString(
|
||||||
|
resource_path('themes/backend/views/flux/icon/folder-git-2.blade.php'),
|
||||||
|
view('flux::icon.folder-git-2')->getPath(),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user