diff --git a/.gitattributes b/.gitattributes index 9e9519b3..9c9472bc 100644 --- a/.gitattributes +++ b/.gitattributes @@ -2,18 +2,27 @@ # https://www.kernel.org/pub/software/scm/git/docs/gitattributes.html # Ignore all test and documentation with "export-ignore". -/.github export-ignore -/.gitattributes export-ignore -/.gitignore export-ignore -/phpunit.xml.dist export-ignore -/art export-ignore -/docs export-ignore -/tests export-ignore -/.editorconfig export-ignore -/.php_cs.dist.php export-ignore -/psalm.xml export-ignore -/psalm.xml.dist export-ignore -/testbench.yaml export-ignore -/UPGRADING.md export-ignore -/phpstan.neon.dist export-ignore +/.github export-ignore +/.gitattributes export-ignore +/.gitignore export-ignore +/.idea export-ignore +/.prettierrc export-ignore +/.package-lock.json export-ignore +/.editorconfig export-ignore +/.php_cs.dist.php export-ignore +/.vscode export-ignore +/art export-ignore +/docs export-ignore +/images export-ignore +/tests export-ignore +/package.json export-ignore /phpstan-baseline.neon export-ignore +/phpstan.neon.dist export-ignore +/postcss.config.js export-ignore +/phpunit.xml.dist export-ignore +/pint.json export-ignore +/psalm.xml export-ignore +/psalm.xml.dist export-ignore +/tailwind.config.js export-ignore +/testbench.yaml export-ignore +/UPGRADING.md export-ignore diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md new file mode 100644 index 00000000..b0ee5d8e --- /dev/null +++ b/.github/CONTRIBUTING.md @@ -0,0 +1,55 @@ +# Contributing + +Contributions are **welcome** and will be fully **credited**. + +Please read and understand the contribution guide before creating an issue or pull request. + +## Etiquette + +This project is open source, and as such, the maintainers give their free time to build and maintain the source code +held within. They make the code freely available in the hope that it will be of use to other developers. It would be +extremely unfair for them to suffer abuse or anger for their hard work. + +Please be considerate towards maintainers when raising issues or presenting pull requests. Let's show the +world that developers are civilized and selfless people. + +It's the duty of the maintainer to ensure that all submissions to the project are of sufficient +quality to benefit the project. Many developers have different skills, strengths, and weaknesses. Respect the maintainer's decision, and do not be upset or abusive if your submission is not used. + +## Viability + +When requesting or submitting new features, first consider whether it might be useful to others. Open +source projects are used by many developers, who may have entirely different needs to your own. Think about +whether or not your feature is likely to be used by other users of the project. + +## Procedure + +Before filing an issue: + +- Attempt to replicate the problem, to ensure that it wasn't a coincidental incident. +- Check to make sure your feature suggestion isn't already present within the project. +- Check the pull requests tab to ensure that the bug doesn't have a fix in progress. +- Check the pull requests tab to ensure that the feature isn't already in progress. + +Before submitting a pull request: + +- Check the codebase to ensure that your feature doesn't already exist. +- Check the pull requests to ensure that another person hasn't already submitted the feature or fix. + +## Requirements + +If the project maintainer has any additional requirements, you will find them listed here. + +- **[PSR-2 Coding Standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)** - The easiest way to apply the conventions is to install [PHP Code Sniffer](https://pear.php.net/package/PHP_CodeSniffer). + +- **Add tests!** - Your patch won't be accepted if it doesn't have tests. + +- **Document any change in behaviour** - Make sure the `README.md` and any other relevant documentation are kept up-to-date. + +- **Consider our release cycle** - We try to follow [SemVer v2.0.0](https://semver.org/). Randomly breaking public APIs is not an option. + +- **One pull request per feature** - If you want to do more than one thing, send multiple pull requests. + +- **Send coherent history** - Make sure each individual commit in your pull request is meaningful. If you had to make multiple intermediate commits while developing, please [squash them](https://www.git-scm.com/book/en/v2/Git-Tools-Rewriting-History#Changing-Multiple-Commit-Messages) before submitting. + +**Happy coding**! diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 00000000..6a57d72d --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1 @@ +github: coolsam diff --git a/.github/ISSUE_TEMPLATE/bug.yml b/.github/ISSUE_TEMPLATE/bug.yml index fe4cfe6d..8fa85ce7 100644 --- a/.github/ISSUE_TEMPLATE/bug.yml +++ b/.github/ISSUE_TEMPLATE/bug.yml @@ -3,64 +3,64 @@ description: Report an Issue or Bug with the Package title: "[Bug]: " labels: ["bug"] body: - - type: markdown - attributes: - value: | - We're sorry to hear you have a problem. Can you help us solve it by providing the following details. - - type: textarea - id: what-happened - attributes: - label: What happened? - description: What did you expect to happen? - placeholder: I cannot currently do X thing because when I do, it breaks X thing. - validations: - required: true - - type: textarea - id: how-to-reproduce - attributes: - label: How to reproduce the bug - description: How did this occur, please add any config values used and provide a set of reliable steps if possible. - placeholder: When I do X I see Y. - validations: - required: true - - type: input - id: package-version - attributes: - label: Package Version - description: What version of our Package are you running? Please be as specific as possible - placeholder: 2.0.0 - validations: - required: true - - type: input - id: php-version - attributes: - label: PHP Version - description: What version of PHP are you running? Please be as specific as possible - placeholder: 8.2.0 - validations: - required: true - - type: input - id: laravel-version - attributes: - label: Laravel Version - description: What version of Laravel are you running? Please be as specific as possible - placeholder: 9.0.0 - validations: - required: true - - type: dropdown - id: operating-systems - attributes: - label: Which operating systems does with happen with? - description: You may select more than one. - multiple: true - options: + - type: markdown + attributes: + value: | + We're sorry to hear you have a problem. Can you help us solve it by providing the following details. + - type: textarea + id: what-happened + attributes: + label: What happened? + description: What did you expect to happen? + placeholder: I cannot currently do X thing because when I do, it breaks X thing. + validations: + required: true + - type: textarea + id: how-to-reproduce + attributes: + label: How to reproduce the bug + description: How did this occur, please add any config values used and provide a set of reliable steps if possible. + placeholder: When I do X I see Y. + validations: + required: true + - type: input + id: package-version + attributes: + label: Package Version + description: What version of our Package are you running? Please be as specific as possible + placeholder: 2.0.0 + validations: + required: true + - type: input + id: php-version + attributes: + label: PHP Version + description: What version of PHP are you running? Please be as specific as possible + placeholder: 8.2.0 + validations: + required: true + - type: input + id: laravel-version + attributes: + label: Laravel Version + description: What version of Laravel are you running? Please be as specific as possible + placeholder: 9.0.0 + validations: + required: true + - type: dropdown + id: operating-systems + attributes: + label: Which operating systems does with happen with? + description: You may select more than one. + multiple: true + options: - macOS - Windows - Linux - - type: textarea - id: notes - attributes: - label: Notes - description: Use this field to provide any other notes that you feel might be relevant to the issue. - validations: - required: false + - type: textarea + id: notes + attributes: + label: Notes + description: Use this field to provide any other notes that you feel might be relevant to the issue. + validations: + required: false diff --git a/.github/SECURITY.md b/.github/SECURITY.md new file mode 100644 index 00000000..9b6d33f8 --- /dev/null +++ b/.github/SECURITY.md @@ -0,0 +1,3 @@ +# Security Policy + +If you discover any security related issues, please email maosa.sam@gmail.com instead of using the issue tracker. diff --git a/.github/workflows/dependabot-auto-merge.yml b/.github/workflows/dependabot-auto-merge.yml index 67e66c6a..d2664188 100644 --- a/.github/workflows/dependabot-auto-merge.yml +++ b/.github/workflows/dependabot-auto-merge.yml @@ -1,4 +1,5 @@ -name: dependabot-auto-merge +name: "Dependabot Auto-Merge" + on: pull_request_target permissions: @@ -10,20 +11,20 @@ jobs: runs-on: ubuntu-latest if: ${{ github.actor == 'dependabot[bot]' }} steps: - + - name: Dependabot metadata id: metadata - uses: dependabot/fetch-metadata@v2.0.0 + uses: dependabot/fetch-metadata@v1.6.0 with: github-token: "${{ secrets.GITHUB_TOKEN }}" - + - name: Auto-merge Dependabot PRs for semver-minor updates if: ${{steps.metadata.outputs.update-type == 'version-update:semver-minor'}} run: gh pr merge --auto --merge "$PR_URL" env: PR_URL: ${{github.event.pull_request.html_url}} GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} - + - name: Auto-merge Dependabot PRs for semver-patch updates if: ${{steps.metadata.outputs.update-type == 'version-update:semver-patch'}} run: gh pr merge --auto --merge "$PR_URL" diff --git a/.github/workflows/fix-php-code-style-issues.yml b/.github/workflows/fix-php-code-style-issues.yml index c958238f..2067a668 100644 --- a/.github/workflows/fix-php-code-style-issues.yml +++ b/.github/workflows/fix-php-code-style-issues.yml @@ -1,4 +1,4 @@ -name: Fix PHP code style issues +name: "Fix PHP Code Styling" on: push: @@ -14,7 +14,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: ${{ github.head_ref }} @@ -22,6 +22,6 @@ jobs: uses: aglipanci/laravel-pint-action@2.3.1 - name: Commit changes - uses: stefanzweifel/git-auto-commit-action@v4 + uses: stefanzweifel/git-auto-commit-action@v5 with: commit_message: Fix styling diff --git a/.github/workflows/phpstan.yml b/.github/workflows/phpstan.yml new file mode 100644 index 00000000..3855a084 --- /dev/null +++ b/.github/workflows/phpstan.yml @@ -0,0 +1,26 @@ +name: PHPStan + +on: + push: + paths: + - '**.php' + - 'phpstan.neon.dist' + +jobs: + phpstan: + name: phpstan + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '8.1' + coverage: none + + - name: Install composer dependencies + uses: ramsey/composer-install@v3 + + - name: Run PHPStan + run: ./vendor/bin/phpstan --error-format=github diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 82f98f2f..7c60f1f3 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -2,13 +2,9 @@ name: run-tests on: push: - branches: - - main - - 3.x + branches: [main] pull_request: - branches: - - main - - 3.x + branches: [main] jobs: test: @@ -23,13 +19,13 @@ jobs: include: - laravel: 10.* testbench: 8.* - carbon: ^2.63 + carbon: 2.* name: P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.stability }} - ${{ matrix.os }} steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup PHP uses: shivammathur/setup-php@v2 diff --git a/.github/workflows/update-changelog.yml b/.github/workflows/update-changelog.yml index 8c12ba9e..ec40921c 100644 --- a/.github/workflows/update-changelog.yml +++ b/.github/workflows/update-changelog.yml @@ -13,7 +13,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: main @@ -24,7 +24,7 @@ jobs: release-notes: ${{ github.event.release.body }} - name: Commit updated CHANGELOG - uses: stefanzweifel/git-auto-commit-action@v4 + uses: stefanzweifel/git-auto-commit-action@v5 with: branch: main commit_message: Update CHANGELOG diff --git a/.gitignore b/.gitignore index a7f372d8..8271e655 100644 --- a/.gitignore +++ b/.gitignore @@ -1,11 +1,13 @@ +.DS_Store .idea -.phpunit.cache +.phpunit.result.cache +.vscode build composer.lock coverage docs +node_modules phpunit.xml phpstan.neon testbench.yaml vendor -node_modules diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 00000000..98406c6b --- /dev/null +++ b/.prettierrc @@ -0,0 +1,5 @@ +{ + "semi": false, + "singleQuote": true, + "trailingComma": "all" +} diff --git a/CHANGELOG.md b/CHANGELOG.md index 1b3f303a..1f71dc03 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ # Changelog All notable changes to `modules` will be documented in this file. + +## 1.0.0 - 202X-XX-XX + +- initial release diff --git a/LICENSE.md b/LICENSE.md index 628f3beb..99fc78d1 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) coolsam +Copyright (c) coolsam Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index f580578e..ab265f78 100644 --- a/README.md +++ b/README.md @@ -1,75 +1,55 @@ -

- Tests - Styling - Laravel v9.x - Filament v3.x - PHP 8.1 - Packagist -

+# Organize your Filament Code into modules using nwidart/laravel-modules -Modules is a FilamentPHP Plugin to enable easy integration with `nwidart/laravel-modules` +[![Latest Version on Packagist](https://img.shields.io/packagist/v/coolsam/modules.svg?style=flat-square)](https://packagist.org/packages/coolsam/modules) +[![GitHub Tests Action Status](https://img.shields.io/github/actions/workflow/status/coolsam/modules/run-tests.yml?branch=main&label=tests&style=flat-square)](https://github.com/coolsam/modules/actions?query=workflow%3Arun-tests+branch%3Amain) +[![GitHub Code Style Action Status](https://img.shields.io/github/actions/workflow/status/coolsam/modules/fix-php-code-styling.yml?branch=main&label=code%20style&style=flat-square)](https://github.com/coolsam/modules/actions?query=workflow%3A"Fix+PHP+code+styling"+branch%3Amain) +[![Total Downloads](https://img.shields.io/packagist/dt/coolsam/modules.svg?style=flat-square)](https://packagist.org/packages/coolsam/modules) -**NB: These docs are for v3, which only supports Filament 3. If you are using Filament -v2, [see the documentation here](https://github.com/savannabits/filament-modules/tree/main#readme) to get started.** -## Installation - -Requirements: -1. Filament >= 3 -2. PHP >= 8.1 -3. Laravel >= 9.0 -4. Livewire >= 3.0 -5. nwidart/laravel-modules >=10.0 +This is where your description should go. Limit it to a paragraph or two. Consider adding a small example. ## Installation -- Ensure you have insalled and configured [Laravel Modules (follow these instructions)]() -- Ensure you have installed and configured Filamentphp (follow these instructions) -- You can now install the package via composer: +You can install the package via composer: ```bash composer require coolsam/modules ``` -## Usage +You can publish and run the migrations with: -In this guide we are going to use the `Blog module` as an example +```bash +php artisan vendor:publish --tag="modules-migrations" +php artisan migrate +``` -### Create your laravel module: -If the module that you want to work on does not exist, create it using nwidart/laravel-modules +You can publish the config file with: ```bash -php artisan module:make Blog # Create the blog module +php artisan vendor:publish --tag="modules-config" ``` -### Generate a new Panel inside your module +Optionally, you can publish the views using ```bash -php artisan module:make-filament-panel admin Blog # php artisan module:make-filament-panel [id] [module] +php artisan vendor:publish --tag="modules-views" ``` -If none of the two arguments are passed, the command will ask for each of them interactively. -In this example, if the Panel id passed is `admin` and the module is blog, the command will generate a panel with -id `blog::admin`. This ID should be used in the next step when generating resources, pages and widgets. -### Generate your resources, pages and widgets as usual, selecting the panel you just created above. -From here on, use filament as you would normally to generate `resources`, `Pages` and `Widgets`. Be sure to specify the `--panel` option as the ID generated earlier. -If the `--panel` option is not passed, the command will ask for it interactively. -```bash -# For each of these commands, the package will ask for the Model and Panel. -php artisan make:filament-resource -php artisan make:filament-page -php artisan make:filament-widget +This is the contents of the published config file: + +```php +return [ +]; ``` -```bash -# The Model and Panel arguments are passed inline -php artisan make:filament-resource Author blog::admin -php artisan make:filament-page Library blog::admin -php artisan make:filament-widget BookStats blog::admin +## Usage + +```php +$modules = new Coolsam\Modules(); +echo $modules->echoPhrase('Hello, Coolsam!'); ``` -**All Done!** For each of the panels generated, you can navigate to your `module-path/panel-path` e.g `blog/admin` to acess your panel and links to resources and pages. ## Testing ```bash @@ -82,7 +62,7 @@ Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed re ## Contributing -Please see [CONTRIBUTING](CONTRIBUTING.md) for details. +Please see [CONTRIBUTING](.github/CONTRIBUTING.md) for details. ## Security Vulnerabilities diff --git a/bin/build.js b/bin/build.js new file mode 100644 index 00000000..3a3439e6 --- /dev/null +++ b/bin/build.js @@ -0,0 +1,50 @@ +import esbuild from 'esbuild' + +const isDev = process.argv.includes('--dev') + +async function compile(options) { + const context = await esbuild.context(options) + + if (isDev) { + await context.watch() + } else { + await context.rebuild() + await context.dispose() + } +} + +const defaultOptions = { + define: { + 'process.env.NODE_ENV': isDev ? `'development'` : `'production'`, + }, + bundle: true, + mainFields: ['module', 'main'], + platform: 'neutral', + sourcemap: isDev ? 'inline' : false, + sourcesContent: isDev, + treeShaking: true, + target: ['es2020'], + minify: !isDev, + plugins: [{ + name: 'watchPlugin', + setup: function (build) { + build.onStart(() => { + console.log(`Build started at ${new Date(Date.now()).toLocaleTimeString()}: ${build.initialOptions.outfile}`) + }) + + build.onEnd((result) => { + if (result.errors.length > 0) { + console.log(`Build failed at ${new Date(Date.now()).toLocaleTimeString()}: ${build.initialOptions.outfile}`, result.errors) + } else { + console.log(`Build finished at ${new Date(Date.now()).toLocaleTimeString()}: ${build.initialOptions.outfile}`) + } + }) + } + }], +} + +compile({ + ...defaultOptions, + entryPoints: ['./resources/js/index.js'], + outfile: './resources/dist/modules.js', +}) diff --git a/composer.json b/composer.json index 27ec7f72..00235b98 100644 --- a/composer.json +++ b/composer.json @@ -1,70 +1,79 @@ { - "name": "coolsam/modules", - "description": "Support for nwidart/laravel-modules in filamentphp", - "keywords": [ - "coolsam", - "laravel", - "modules" - ], - "homepage": "https://github.com/coolsam/modules", - "license": "MIT", - "authors": [ - { - "name": "Sam Maosa", - "email": "smaosa@savannabits.com", - "role": "Developer" - } - ], - "require": { - "php": "^8.1|^8.2", - "spatie/laravel-package-tools": "^1.14.0", - "illuminate/contracts": "^9.1|^10.0|^11.0", - "filament/filament": "^3.0.0", - "nwidart/laravel-modules": "^10.0|^11.0" - }, - "require-dev": { - "laravel/pint": "^1.0", - "nunomaduro/collision": "^8.1", - "orchestra/testbench": "^8.0", - "pestphp/pest": "^2.0", - "pestphp/pest-plugin-arch": "^2.0", - "pestphp/pest-plugin-laravel": "^2.0", - "spatie/laravel-ray": "^1.26" - }, - "autoload": { - "psr-4": { - "Coolsam\\FilamentModules\\": "src/" - } - }, - "autoload-dev": { - "psr-4": { - "Coolsam\\FilamentModules\\Tests\\": "tests/" - } - }, - "scripts": { - "post-autoload-dump": "@php ./vendor/bin/testbench package:discover --ansi", - "analyse": "vendor/bin/phpstan analyse", - "test": "vendor/bin/pest", - "test-coverage": "vendor/bin/pest --coverage", - "format": "vendor/bin/pint" - }, - "config": { - "sort-packages": true, - "allow-plugins": { - "pestphp/pest-plugin": true, - "phpstan/extension-installer": true - } - }, - "extra": { - "laravel": { - "providers": [ - "Coolsam\\FilamentModules\\ModulesServiceProvider" - ], - "aliases": { - "Modules": "Coolsam\\FilamentModules\\Facades\\Modules" - } - } - }, - "minimum-stability": "dev", - "prefer-stable": true -} + "name": "coolsam/modules", + "description": "Organize your Filament Code into modules using nwidart/laravel-modules", + "keywords": [ + "coolsam", + "laravel", + "FilamentModules", + "filament" + ], + "homepage": "https://github.com/savannabits/filament-modules", + "support": { + "issues": "https://github.com/savannabits/filament-modules/issues", + "source": "https://github.com/savannabits/filament-modules" + }, + "license": "MIT", + "authors": [ + { + "name": "Sam Maosa", + "email": "maosa.sam@gmail.com", + "role": "Developer" + } + ], + "require": { + "php": "^8.1", + "filament/filament": "^3.0", + "nwidart/laravel-modules": "^10.0", + "spatie/laravel-package-tools": "^1.15.0" + }, + "require-dev": { + "laravel/pint": "^1.0", + "nunomaduro/collision": "^7.9", + "nunomaduro/larastan": "^2.0.1", + "orchestra/testbench": "^8.0", + "pestphp/pest": "^2.1", + "pestphp/pest-plugin-arch": "^2.0", + "pestphp/pest-plugin-laravel": "^2.0", + "phpstan/extension-installer": "^1.1", + "phpstan/phpstan-deprecation-rules": "^1.0", + "phpstan/phpstan-phpunit": "^1.0", + "spatie/laravel-ray": "^1.26" + }, + "autoload": { + "psr-4": { + "Coolsam\\Modules\\": "src/", + "Coolsam\\Modules\\Database\\Factories\\": "database/factories/" + } + }, + "autoload-dev": { + "psr-4": { + "Coolsam\\Modules\\Tests\\": "tests/" + } + }, + "scripts": { + "post-autoload-dump": "@php ./vendor/bin/testbench package:discover --ansi", + "analyse": "vendor/bin/phpstan analyse", + "test": "vendor/bin/pest", + "test-coverage": "vendor/bin/pest --coverage", + "format": "vendor/bin/pint" + }, + "config": { + "sort-packages": true, + "allow-plugins": { + "pestphp/pest-plugin": true, + "phpstan/extension-installer": true + } + }, + "extra": { + "laravel": { + "providers": [ + "Coolsam\\Modules\\ModulesServiceProvider" + ], + "aliases": { + "FilamentModules": "FilamentModules" + } + } + }, + "minimum-stability": "dev", + "prefer-stable": true +} \ No newline at end of file diff --git a/config/filament-modules.php b/config/filament-modules.php new file mode 100644 index 00000000..008c279a --- /dev/null +++ b/config/filament-modules.php @@ -0,0 +1,10 @@ + true, // whether to auto-register plugins from various modules in the Panel + 'clusters' => [ + 'enabled' => true, // whether to enable the clusters feature which allows you to group each module's filament resources and pages into a cluster + 'use-top-navigation' => true, // display the main cluster menu in the top navigation and the sub-navigation in the side menu, which improves the UI + ], +]; diff --git a/config/modules.php b/config/modules.php deleted file mode 100644 index dcdbf6b0..00000000 --- a/config/modules.php +++ /dev/null @@ -1,6 +0,0 @@ -id(); - - // add fields - - $table->timestamps(); - }); - } -}; diff --git a/package.json b/package.json new file mode 100644 index 00000000..0e3e148c --- /dev/null +++ b/package.json @@ -0,0 +1,26 @@ +{ + "private": true, + "type": "module", + "scripts": { + "dev:styles": "npx tailwindcss -i resources/css/index.css -o resources/dist/modules.css --postcss --watch", + "dev:scripts": "node bin/build.js --dev", + "build:styles": "npx tailwindcss -i resources/css/index.css -o resources/dist/modules.css --postcss --minify && npm run purge", + "build:scripts": "node bin/build.js", + "purge": "filament-purge -i resources/dist/modules.css -o resources/dist/modules.css -v 3.x", + "dev": "npm-run-all --parallel dev:*", + "build": "npm-run-all build:*" + }, + "devDependencies": { + "@awcodes/filament-plugin-purge": "^1.1.1", + "@tailwindcss/forms": "^0.5.4", + "@tailwindcss/typography": "^0.5.9", + "autoprefixer": "^10.4.14", + "esbuild": "^0.19.2", + "npm-run-all": "^4.1.5", + "postcss": "^8.4.26", + "postcss-import": "^15.1.0", + "prettier": "^2.7.1", + "prettier-plugin-tailwindcss": "^0.1.13", + "tailwindcss": "^3.3.3" + } +} diff --git a/resources/views/.gitkeep b/phpstan-baseline.neon similarity index 100% rename from resources/views/.gitkeep rename to phpstan-baseline.neon diff --git a/phpstan.neon.dist b/phpstan.neon.dist new file mode 100644 index 00000000..e005ac7d --- /dev/null +++ b/phpstan.neon.dist @@ -0,0 +1,13 @@ +includes: + - phpstan-baseline.neon + +parameters: + level: 4 + paths: + - src + - config + tmpDir: build/phpstan + checkOctaneCompatibility: true + checkModelProperties: true + checkMissingIterableValueType: false + diff --git a/pint.json b/pint.json new file mode 100644 index 00000000..c6ddb494 --- /dev/null +++ b/pint.json @@ -0,0 +1,14 @@ +{ + "preset": "laravel", + "rules": { + "blank_line_before_statement": true, + "concat_space": { + "spacing": "one" + }, + "method_argument_space": true, + "single_trait_insert_per_statement": true, + "types_spaces": { + "space": "single" + } + } +} diff --git a/postcss.config.cjs b/postcss.config.cjs new file mode 100644 index 00000000..28553945 --- /dev/null +++ b/postcss.config.cjs @@ -0,0 +1,8 @@ +module.exports = { + plugins: { + "postcss-import": {}, + "tailwindcss/nesting": {}, + tailwindcss: {}, + autoprefixer: {}, + }, +} diff --git a/resources/css/index.css b/resources/css/index.css new file mode 100644 index 00000000..b3949d56 --- /dev/null +++ b/resources/css/index.css @@ -0,0 +1 @@ +@import '../../vendor/filament/filament/resources/css/theme.css'; diff --git a/resources/dist/.gitkeep b/resources/dist/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/resources/js/index.js b/resources/js/index.js new file mode 100644 index 00000000..e69de29b diff --git a/resources/lang/en/modules.php b/resources/lang/en/modules.php new file mode 100644 index 00000000..04443e91 --- /dev/null +++ b/resources/lang/en/modules.php @@ -0,0 +1,6 @@ +resolveStubPath('/stubs/filament-cluster.stub'); + } + + protected function stubReplacements(): array + { + return [ + 'moduleStudlyName' => $this->getModule()->getStudlyName(), + 'navigationLabel' => str($this->argument('name'))->kebab()->title()->replace('-', ' ')->toString(), + 'navigationIcon' => 'heroicon-o-squares-2x2', + ]; + } +} diff --git a/src/Commands/ModuleMakeFilamentPluginCommand.php b/src/Commands/ModuleMakeFilamentPluginCommand.php new file mode 100644 index 00000000..ee74a59a --- /dev/null +++ b/src/Commands/ModuleMakeFilamentPluginCommand.php @@ -0,0 +1,35 @@ +resolveStubPath('/stubs/filament-plugin.stub'); + } + + protected function stubReplacements(): array + { + return [ + 'moduleStudlyName' => $this->getModule()->getStudlyName(), + 'pluginId' => str($this->argument('name'))->replace('Plugin', '')->studly()->lower()->toString(), + ]; + } +} diff --git a/src/Commands/ModuleMakePanelCommand.php b/src/Commands/ModuleMakePanelCommand.php deleted file mode 100644 index e0dda5f7..00000000 --- a/src/Commands/ModuleMakePanelCommand.php +++ /dev/null @@ -1,103 +0,0 @@ -argument('id') ?? $this->askRequired('ID (e.g. `app`)', 'id')); - - $class = $id - ->studly() - ->append('PanelProvider'); - $module = $this->argument('module'); - if (! $module) { - try { - $usedNow = app('modules')->getUsedNow(); - } catch (\Throwable $exception) { - $usedNow = null; - } - $module = Str::of($this->askRequired('Module Name (e.g. `Sales`)', 'module', $usedNow))->toString(); - } - $this->module = app('modules')->findOrFail($module); - - $path = str($this->module->getExtraPath("{$this->basePath}/$class")) - ->replace('\\', '/') - ->append('.php')->toString(); - - if (! $this->option('force') && $this->checkForCollision([$path])) { - return static::INVALID; - } - $namespace = Str::of($this->basePath) - ->replace('/', '\\') - ->prepend('\\') - ->prepend($this->getModuleNamespace()); - - $moduleJson = static::readModuleJson($this->module->getName()); - // $panelPath = Str::of($this->module->getLowerName()); - $panelPath = $id->prepend('/')->prepend($this->module->getLowerName()); - - if (collect($moduleJson['providers'])->filter( - fn ($provider) => Str::of($provider)->contains('PanelProvider') && ! Str::of($provider)->contains($class) - )->count()) { - $panelPath = $id->prepend('/')->prepend($this->module->getLowerName()); - } - - $this->copyStubToApp('PanelProvider', $path, [ - 'namespace' => $namespace, - 'Module' => $this->module->getStudlyName(), - 'module_namespace' => $this->getModuleNamespace(), - 'class' => $class, - 'directory' => $id->studly()->toString(), - 'panel_path' => $panelPath->toString(), - 'id' => $id->prepend('::')->prepend($this->module->getLowerName())->lcfirst(), - ]); - - $providers = collect($moduleJson['providers']); - $provider = "$namespace\\$class"; - if (! $providers->contains($provider)) { - $moduleJson['providers'][] = $provider; - static::writeToModuleJson($this->module->getName(), $moduleJson); - } - $this->components->info("Successfully created {$class}!"); - - return static::SUCCESS; - } - - public function getModuleNamespace(): string - { - return $this->laravel['modules']->config('namespace').'\\'.$this->module->getName(); - } - - public static function readModuleJson(string $moduleName) - { - return json_decode(file_get_contents(module_path($moduleName, 'module.json')), true); - } - - public static function writeToModuleJson($moduleName, array $data): bool|int - { - $jsonString = json_encode($data, JSON_PRETTY_PRINT); - - return file_put_contents(module_path($moduleName, 'module.json'), $jsonString); - } -} diff --git a/src/Commands/ModulesCommand.php b/src/Commands/ModulesCommand.php deleted file mode 100644 index 4047dd65..00000000 --- a/src/Commands/ModulesCommand.php +++ /dev/null @@ -1,19 +0,0 @@ -comment('All done'); - - return self::SUCCESS; - } -} diff --git a/src/Commands/ModulesFilamentInstallCommand.php b/src/Commands/ModulesFilamentInstallCommand.php new file mode 100644 index 00000000..3906a4fd --- /dev/null +++ b/src/Commands/ModulesFilamentInstallCommand.php @@ -0,0 +1,147 @@ +moduleName = $this->argument('module'); + if (! $this->option('cluster')) { + $this->cluster = confirm('Do you want to organize your code into filament clusters?', true); + } + $module = $this->getModule(true); + // Ensure the Filament directories exist + $this->ensureFilamentDirectoriesExist(); + // Create Filament Plugin + $this->createDefaultFilamentPlugin(); + + if ($this->cluster && confirm('Would you like to create a default Cluster for the module?', true)) { + $this->createDefaultFilamentCluster(); + } + } + + protected function getArguments(): array + { + return [ + ['module', InputArgument::REQUIRED, 'The name of the module in which to install filament support'], + ]; + } + + protected function getOptions(): array + { + return [ + ['cluster', 'C', InputOption::VALUE_NONE], + ]; + } + + protected function promptForMissingArgumentsUsing(): array + { + return [ + 'module' => [ + 'What is the name of the module?', + 'e.g AccessControl, Blog, etc.', + ], + ]; + } + + protected function getModule(): \Nwidart\Modules\Module + { + try { + return Module::findOrFail($this->moduleName); + } catch (ModuleNotFoundException | \Throwable $exception) { + if (confirm("Module $this->moduleName does not exist. Would you like to generate it?", true)) { + $this->call('module:make', ['name' => [$this->moduleName]]); + + return $this->getModule(); + } + $this->error($exception->getMessage()); + exit(1); + } + } + + private function ensureFilamentDirectoriesExist(): void + { + if (! is_dir($dir = $this->getModule()->appPath('Filament'))) { + $this->makeDirectory($dir); + } + + if ($this->cluster) { + if (! is_dir($dir = $this->getModule()->appPath('Filament/Clusters'))) { + $this->makeDirectory($dir); + } + } else { + if (! is_dir($dir = $this->getModule()->appPath('Filament/Pages'))) { + $this->makeDirectory($dir); + } + + if (! is_dir($dir = $this->getModule()->appPath('Filament/Resources'))) { + $this->makeDirectory($dir); + } + + if (! is_dir($dir = $this->getModule()->appPath('Filament/Widgets'))) { + $this->makeDirectory($dir); + } + } + } + + private function makeDirectory(string $dir): void + { + if (! mkdir($dir, 0755, true) && ! is_dir($dir)) { + $this->error(sprintf('Directory "%s" was not created', $dir)); + exit(1); + } + } + + protected function createDefaultFilamentPlugin(): void + { + $module = $this->getModule(); + $this->call('module:make:filament-plugin', [ + 'name' => $module->getStudlyName() . 'Plugin', + 'module' => $module->getStudlyName(), + ]); + } + + protected function createDefaultFilamentCluster(): void + { + $module = $this->getModule(); + $this->call('module:make:filament-cluster', [ + 'name' => $module->getStudlyName(), + 'module' => $module->getStudlyName(), + ]); + } +} diff --git a/src/Commands/stubs/filament-cluster.stub b/src/Commands/stubs/filament-cluster.stub new file mode 100644 index 00000000..d2d4fe6f --- /dev/null +++ b/src/Commands/stubs/filament-cluster.stub @@ -0,0 +1,29 @@ + $paths + */ + protected function checkForCollision(array $paths): bool + { + foreach ($paths as $path) { + if (! $this->fileExists($path)) { + continue; + } + + if (! confirm(basename($path) . ' already exists, do you want to overwrite it?')) { + $this->components->error("{$path} already exists, aborting."); + + return true; + } + + unlink($path); + } + + return false; + } + + /** + * @param array $replacements + */ + protected function copyStubToApp(string $stub, string $targetPath, array $replacements = []): void + { + $filesystem = app(Filesystem::class); + + $stubPath = $this->getDefaultStubPath() . "/{$stub}.stub"; + + $stub = str($filesystem->get($stubPath)); + + foreach ($replacements as $key => $replacement) { + $stub = $stub->replace("{{ {$key} }}", $replacement); + } + + $stub = (string) $stub; + + $this->writeFile($targetPath, $stub); + } + + protected function fileExists(string $path): bool + { + $filesystem = app(Filesystem::class); + + return $filesystem->exists($path); + } + + protected function writeFile(string $path, string $contents): void + { + $filesystem = app(Filesystem::class); + + $filesystem->ensureDirectoryExists( + pathinfo($path, PATHINFO_DIRNAME), + ); + + $filesystem->put($path, $contents); + } + + protected function getDefaultStubPath(): string + { + return $this->getModule()->appPath('Commands/stubs'); + } + + protected function getModule(): Module + { + return FilamentModules::getModule($this->getModuleStudlyName()); + } + + abstract protected function getModuleStudlyName(): string; +} diff --git a/src/Concerns/GeneratesModularFiles.php b/src/Concerns/GeneratesModularFiles.php new file mode 100644 index 00000000..529ec945 --- /dev/null +++ b/src/Concerns/GeneratesModularFiles.php @@ -0,0 +1,124 @@ +argument('module')); + } + + protected function getDefaultNamespace($rootNamespace): string + { + return trim($rootNamespace, '\\') . '\\' . trim(Str::replace(DIRECTORY_SEPARATOR, '\\', $this->getRelativeNamespace()), '\\'); + } + + abstract protected function getRelativeNamespace(): string; + + protected function rootNamespace(): string + { + return $this->getModule()->namespace(''); + } + + protected function getPath($name): string + { + $name = Str::replaceFirst($this->rootNamespace(), '', $name); + + return $this->getModule()->getExtraPath(str_replace('\\', '/', $name) . '.php'); + } + + protected function possibleModels() + { + $modelPath = $this->getModule()->appPath('Models'); + + return collect(Finder::create()->files()->depth(0)->in($modelPath)) + ->map(fn ($file) => $file->getBasename('.php')) + ->sort() + ->values() + ->all(); + } + + protected function viewPath($path = ''): string + { + $views = $this->getModule()->resourcesPath('views'); + + return $views . ($path ? DIRECTORY_SEPARATOR . $path : $path); + } + + protected function buildClass($name) + { + $stub = $this->files->get($this->getStub()); + + return $this->replaceNamespace($stub, $name)->applyStubReplacements($stub)->replaceClass($stub, $name); + } + + protected function applyStubReplacements(&$stub): static + { + foreach ($this->stubReplacements() as $key => $replacement) { + $stub = str_replace(["{{ $key }}", "{{{$key}}}"], $replacement, $stub); + } + + return $this; + } + + protected function stubReplacements(): array + { + return []; + } + + protected function promptForMissingArgumentsUsing(): array + { + return [ + 'name' => [ + 'What should the ' . strtolower($this->type ?: 'class') . ' be named?', + match ($this->type) { + 'Cast' => 'E.g. Json', + 'Channel' => 'E.g. OrderChannel', + 'Console command' => 'E.g. SendEmails', + 'Component' => 'E.g. Alert', + 'Controller' => 'E.g. UserController', + 'Event' => 'E.g. PodcastProcessed', + 'Exception' => 'E.g. InvalidOrderException', + 'Factory' => 'E.g. PostFactory', + 'Job' => 'E.g. ProcessPodcast', + 'Listener' => 'E.g. SendPodcastNotification', + 'Mailable' => 'E.g. OrderShipped', + 'Middleware' => 'E.g. EnsureTokenIsValid', + 'Model' => 'E.g. Flight', + 'Notification' => 'E.g. InvoicePaid', + 'Observer' => 'E.g. UserObserver', + 'Policy' => 'E.g. PostPolicy', + 'Provider' => 'E.g. ElasticServiceProvider', + 'Request' => 'E.g. StorePodcastRequest', + 'Resource' => 'E.g. UserResource', + 'Rule' => 'E.g. Uppercase', + 'Scope' => 'E.g. TrendingScope', + 'Seeder' => 'E.g. UserSeeder', + 'Test' => 'E.g. UserTest', + 'Filament Cluster' => 'E.g Settings', + 'Filament Plugin' => 'e.g AccessControlPlugin', + default => '', + }, + ], + ]; + } +} diff --git a/src/Concerns/ModuleFilamentPlugin.php b/src/Concerns/ModuleFilamentPlugin.php new file mode 100644 index 00000000..792a8053 --- /dev/null +++ b/src/Concerns/ModuleFilamentPlugin.php @@ -0,0 +1,61 @@ +getModuleName()); + } + + public function register(Panel $panel): void + { + $module = $this->getModule(); + $useClusters = config('filament-modules.clusters.enabled', false); + $panel->discoverPages( + in: $module->appPath('Filament' . DIRECTORY_SEPARATOR . 'Pages'), + for: $module->appNamespace('\\Filament\\Pages') + ); + $panel->discoverResources( + in: $module->appPath('Filament' . DIRECTORY_SEPARATOR . 'Resources'), + for: $module->appNamespace('\\Filament\\Resources') + ); + $panel->discoverWidgets( + in: $module->appPath('Filament' . DIRECTORY_SEPARATOR . 'Widgets'), + for: $module->appNamespace('\\Filament\\Widgets') + ); + + $panel->discoverLivewireComponents( + in: $module->appPath('Livewire'), + for: $module->appNamespace('\\Livewire') + ); + + if ($useClusters) { + $path = $module->appPath('Filament' . DIRECTORY_SEPARATOR . 'Clusters'); + $namespace = $module->appNamespace('\\Filament\\Clusters'); + $panel->discoverClusters( + in: $path, + for: $namespace, + ); + } + } + + public static function make(): static + { + return app(static::class); + } + + public static function get(): static + { + /** @var static $plugin */ + $plugin = filament(app(static::class)->getId()); + + return $plugin; + } +} diff --git a/src/Extensions/LaravelModulesServiceProvider.php b/src/Extensions/LaravelModulesServiceProvider.php deleted file mode 100644 index 17172669..00000000 --- a/src/Extensions/LaravelModulesServiceProvider.php +++ /dev/null @@ -1,21 +0,0 @@ -registerPanels(); - parent::register(); - Log::info('Registered Modules'); - } - - public function registerPanels(): void - { - // Override this to do anything during registration - } -} diff --git a/src/Facades/FilamentModules.php b/src/Facades/FilamentModules.php new file mode 100644 index 00000000..e629ab29 --- /dev/null +++ b/src/Facades/FilamentModules.php @@ -0,0 +1,16 @@ +replace('\\', DIRECTORY_SEPARATOR)->toString(); + + return str($fullPath) + ->replace($base, $relative) + ->replace('.php', '') + ->explode(DIRECTORY_SEPARATOR) + ->map(fn ($piece) => str($piece)->studly()->toString()) + ->implode('\\'); } - public function register(Panel $panel): void + public function execCommand(string $command, ?Command $artisan = null): void { - // + $process = Process::fromShellCommandline($command); + $process->start(); + foreach ($process as $type => $data) { + if (! $artisan) { + echo $data; + } else { + $artisan->info(trim($data)); + } + } } - public function boot(Panel $panel): void + public function packagePath(string $path = ''): string { + //return the base path of this package + return dirname(__DIR__ . '../') . ($path ? DIRECTORY_SEPARATOR . trim($path, DIRECTORY_SEPARATOR) : ''); } } diff --git a/src/ModulesPlugin.php b/src/ModulesPlugin.php new file mode 100644 index 00000000..7de25762 --- /dev/null +++ b/src/ModulesPlugin.php @@ -0,0 +1,55 @@ +topNavigation(config('filament-modules.clusters.enabled', false) && config('filament-modules.clusters.use-top-navigation', false)); + foreach ($this->getModulePlugins() as $modulePlugin) { + $panel->plugin($modulePlugin::make()); + } + } + + public function boot(Panel $panel): void + { + } + + public static function make(): static + { + return app(static::class); + } + + public static function get(): static + { + /** @var static $plugin */ + $plugin = filament(app(static::class)->getId()); + + return $plugin; + } + + protected function getModulePlugins(): array + { + if (! config('filament-modules.auto-register-plugins', false)) { + return []; + } + // get a glob of all Filament plugins + $basePath = str(config('modules.paths.modules', 'Modules')); + $pattern = $basePath . '/*/App/Filament/*Plugin.php'; + $pluginPaths = glob($pattern); + + return collect($pluginPaths)->map(fn ($path) => FilamentModules::convertPathToNamespace($path))->toArray(); + + } +} diff --git a/src/ModulesServiceProvider.php b/src/ModulesServiceProvider.php index 0fb3a652..0f1f0d12 100644 --- a/src/ModulesServiceProvider.php +++ b/src/ModulesServiceProvider.php @@ -1,16 +1,24 @@ name('modules') - ->hasConfigFile('modules') - ->hasViews() - ->hasCommands([ - ModuleMakePanelCommand::class, - ]); - } - - public function register() - { - $this->app->register(LaravelModulesServiceProvider::class); - $this->app->singleton('coolsam-modules', Modules::class); - $this->app->afterResolving('filament', function () { - foreach (Filament::getPanels() as $panel) { - $id = \Str::of($panel->getId()); - if ($id->contains('::')) { - $title = $id->replace(['::', '-'], [' ', ' '])->title()->toString(); - $panel - ->renderHook( - 'panels::sidebar.nav.start', - fn () => new HtmlString("

$title

"), - ) - ->renderHook( - 'panels::sidebar.nav.end', - fn () => new HtmlString( - ' - - - - Main Panel - ' - ), - ); - } + $package->name(static::$name) + ->hasCommands($this->getCommands()) + ->hasInstallCommand(function (InstallCommand $command) { + $command + ->publishConfigFile() + ->endWith(function (InstallCommand $command) { + $command->askToStarRepoOnGitHub('savannabits/filament-modules'); + }); + }); + + $configFileName = 'filament-modules'; + + if (file_exists($package->basePath("/../config/{$configFileName}.php"))) { + $package->hasConfigFile($configFileName); + } + + if (file_exists($package->basePath('/../database/migrations'))) { + $package->hasMigrations($this->getMigrations()); + } + + if (file_exists($package->basePath('/../resources/lang'))) { + $package->hasTranslations(); + } + + if (file_exists($package->basePath('/../resources/views'))) { + $package->hasViews(static::$viewNamespace); + } + } + + public function packageRegistered(): void + { + $this->registerModuleMacros(); + } + + public function packageBooted(): void + { + // Asset Registration + FilamentAsset::register( + $this->getAssets(), + $this->getAssetPackageName() + ); + + FilamentAsset::registerScriptData( + $this->getScriptData(), + $this->getAssetPackageName() + ); + + // Icon Registration + FilamentIcon::register($this->getIcons()); + + // Handle Stubs + if (app()->runningInConsole()) { + foreach (app(Filesystem::class)->files(__DIR__ . '/../stubs/') as $file) { + $this->publishes([ + $file->getRealPath() => base_path("stubs/modules/{$file->getFilename()}"), + ], 'modules-stubs'); } + } + + // Testing + Testable::mixin(new TestsModules()); + } + + protected function getAssetPackageName(): ?string + { + return 'coolsam/modules'; + } + + /** + * @return array + */ + protected function getAssets(): array + { + return []; + } + + /** + * @return array + */ + protected function getCommands(): array + { + return [ + Commands\ModulesFilamentInstallCommand::class, + Commands\ModuleMakeFilamentClusterCommand::class, + Commands\ModuleMakeFilamentPluginCommand::class, + ]; + } + + /** + * @return array + */ + protected function getIcons(): array + { + return []; + } + + /** + * @return array + */ + protected function getRoutes(): array + { + return []; + } + + /** + * @return array + */ + protected function getScriptData(): array + { + return []; + } + + /** + * @return array + */ + protected function getMigrations(): array + { + return [ + // 'create_modules_table', + ]; + } + + protected function registerModuleMacros(): void + { + Module::macro('namespace', function (string $relativeNamespace = '') { + $base = trim($this->app['config']->get('modules.namespace', 'Modules'), '\\'); + $relativeNamespace = trim($relativeNamespace, '\\'); + $studlyName = $this->getStudlyName(); + + return trim("{$base}\\{$studlyName}\\{$relativeNamespace}", '\\'); + }); + + Module::macro('getTitle', function () { + return str($this->getStudlyName())->kebab()->title()->replace('-', ' ')->toString(); }); - return parent::register(); + Module::macro('appNamespace', function (string $relativeNamespace = '') { + $relativeNamespace = trim($relativeNamespace, '\\'); + $relativeNamespace = str_replace('App\\', '', $relativeNamespace); + $relativeNamespace = str_replace('App', '', $relativeNamespace); + $relativeNamespace = trim($relativeNamespace, '\\'); + $relativeNamespace = 'App\\' . $relativeNamespace; + + return $this->namespace($relativeNamespace); + }); + Module::macro('appPath', function (string $relativePath = '') { + $appPath = $this->getExtraPath('App'); + + return $appPath . ($relativePath ? DIRECTORY_SEPARATOR . $relativePath : ''); + }); + + Module::macro('databasePath', function (string $relativePath = '') { + $appPath = $this->getExtraPath('Database'); + + return $appPath . ($relativePath ? DIRECTORY_SEPARATOR . $relativePath : ''); + }); + + Module::macro('resourcesPath', function (string $relativePath = '') { + $appPath = $this->getExtraPath('resources'); + + return $appPath . ($relativePath ? DIRECTORY_SEPARATOR . $relativePath : ''); + }); + + Module::macro('migrationsPath', function (string $relativePath = '') { + $appPath = $this->databasePath('migrations'); + + return $appPath . ($relativePath ? DIRECTORY_SEPARATOR . $relativePath : ''); + }); + + Module::macro('seedersPath', function (string $relativePath = '') { + $appPath = $this->databasePath('Seeders'); + + return $appPath . ($relativePath ? DIRECTORY_SEPARATOR . $relativePath : ''); + }); + + Module::macro('factoriesPath', function (string $relativePath = '') { + $appPath = $this->databasePath('Factories'); + + return $appPath . ($relativePath ? DIRECTORY_SEPARATOR . $relativePath : ''); + }); } } diff --git a/src/Testing/TestsModules.php b/src/Testing/TestsModules.php new file mode 100644 index 00000000..63da6ea9 --- /dev/null +++ b/src/Testing/TestsModules.php @@ -0,0 +1,13 @@ + - - diff --git a/stubs/PanelProvider.stub b/stubs/PanelProvider.stub deleted file mode 100644 index 58054289..00000000 --- a/stubs/PanelProvider.stub +++ /dev/null @@ -1,63 +0,0 @@ -getModuleNamespace(); - return $panel - ->id('{{ id }}') - ->path('{{ panel_path }}') - ->colors([ - 'primary' => Color::Teal, - ]) - ->discoverResources(in: module_path($this->module, 'Filament/{{ directory }}/Resources'), for: "$moduleNamespace\\Filament\\{{ directory }}\\Resources") - ->discoverPages(in: module_path($this->module, 'Filament/{{ directory }}/Pages'), for: "$moduleNamespace\\Filament\\{{ directory }}\\Pages") - ->pages([ - Pages\Dashboard::class, - ]) - ->discoverWidgets(in: module_path($this->module, 'Filament/{{ directory }}/Widgets'), for: "$moduleNamespace\\Filament\\{{ directory }}\\Widgets") - ->widgets([ - Widgets\AccountWidget::class, - Widgets\FilamentInfoWidget::class, - ]) - ->middleware([ - EncryptCookies::class, - AddQueuedCookiesToResponse::class, - StartSession::class, - AuthenticateSession::class, - ShareErrorsFromSession::class, - VerifyCsrfToken::class, - SubstituteBindings::class, - DisableBladeIconComponents::class, - DispatchServingFilamentEvent::class, - ]) - ->authMiddleware([ - Authenticate::class, - ]); - } - - protected function getModuleNamespace(): string - { - return config('modules.namespace').'\\'.$this->module; - } -} diff --git a/stubs/RelationManager.stub b/stubs/RelationManager.stub deleted file mode 100644 index 0146dd07..00000000 --- a/stubs/RelationManager.stub +++ /dev/null @@ -1,51 +0,0 @@ -schema([ - Forms\Components\TextInput::make('{{ recordTitleAttribute }}') - ->required() - ->maxLength(255), - ]); - } - - public function table(Table $table): Table - { - return $table -{{ modifyQueryUsing }} - ->columns([ - Tables\Columns\TextColumn::make('{{ recordTitleAttribute }}'), - ]) - ->filters([ -{{ tableFilters }} - ]) - ->headerActions([ -{{ tableHeaderActions }} - ]) - ->actions([ -{{ tableActions }} - ]) - ->bulkActions([ - Tables\Actions\BulkActionGroup::make([ -{{ tableBulkActions }} - ]), - ]); - } -} diff --git a/stubs/Resource.stub b/stubs/Resource.stub deleted file mode 100644 index 887d42db..00000000 --- a/stubs/Resource.stub +++ /dev/null @@ -1,55 +0,0 @@ -schema([ -{{ formSchema }} - ]); - } - - public static function table(Table $table): Table - { - return $table - ->columns([ -{{ tableColumns }} - ]) - ->filters([ -{{ tableFilters }} - ]) - ->actions([ -{{ tableActions }} - ]) - ->bulkActions([ - Tables\Actions\BulkActionGroup::make([ -{{ tableBulkActions }} - ]), - ]); - } -{{ relations }} - public static function getPages(): array - { - return [ -{{ pages }} - ]; - }{{ eloquentQuery }} -} diff --git a/stubs/ResourceEditPage.stub b/stubs/ResourceEditPage.stub deleted file mode 100644 index 753de152..00000000 --- a/stubs/ResourceEditPage.stub +++ /dev/null @@ -1,19 +0,0 @@ -in(__DIR__); diff --git a/tests/TestCase.php b/tests/TestCase.php index 416fc5c6..c6b35099 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -1,10 +1,22 @@ 'Coolsam\\Modules\\Database\\Factories\\'.class_basename($modelName).'Factory' + fn (string $modelName) => 'Coolsam\\Modules\\Database\\Factories\\' . class_basename($modelName) . 'Factory' ); } protected function getPackageProviders($app) { return [ + ActionsServiceProvider::class, + BladeCaptureDirectiveServiceProvider::class, + BladeHeroiconsServiceProvider::class, + BladeIconsServiceProvider::class, + FilamentServiceProvider::class, + FormsServiceProvider::class, + InfolistsServiceProvider::class, + LivewireServiceProvider::class, + NotificationsServiceProvider::class, + SupportServiceProvider::class, + TablesServiceProvider::class, + WidgetsServiceProvider::class, ModulesServiceProvider::class, ]; }