├── .editorconfig
├── .gitattributes
├── .github
├── CONTRIBUTING.md
├── FUNDING.yml
├── ISSUE_TEMPLATE
│ ├── bug.yml
│ └── feature_request.md
├── SECURITY.md
├── dependabot.yml
└── workflows
│ ├── dependabot-auto-merge.yml
│ ├── fix-php-code-style-issues.yml
│ ├── phpstan.yml
│ ├── run-tests.yml
│ └── update-changelog.yml
├── .gitignore
├── .prettierrc
├── CODE_OF_CONDUCT.md
├── LICENSE.md
├── README.md
├── composer.json
├── composer.lock
├── config
└── zeus-bolt.php
├── database
├── factories
│ ├── CategoryFactory.php
│ ├── CollectionFactory.php
│ ├── FieldFactory.php
│ ├── FieldResponseFactory.php
│ ├── FormFactory.php
│ ├── ResponseFactory.php
│ ├── SectionFactory.php
│ └── UserFactory.php
├── migrations
│ ├── add_borderless_to_section.php.stub
│ ├── add_compact_to_section.php.stub
│ ├── add_extension_item_responses.php.stub
│ ├── add_extensions_to_forms.php.stub
│ ├── add_grade_to_field_response.php.stub
│ ├── add_grade_to_response.php.stub
│ ├── add_options_to_section.php.stub
│ ├── alter_tables_constraints.php.stub
│ ├── create_categories_table.php.stub
│ ├── create_collections_table.php.stub
│ ├── create_field_responses_table.php.stub
│ ├── create_fields_table.php.stub
│ ├── create_forms_table.php.stub
│ ├── create_responses_table.php.stub
│ └── create_sections_table.php.stub
└── seeders
│ └── BoltSeeder.php
├── docs
├── _index.md
├── advanced
│ ├── _index.md
│ ├── add-datasource.md
│ ├── add-fields.md
│ ├── custom-designer.md
│ ├── custom-schemata.md
│ ├── events.md
│ ├── extension.md
│ └── render-hooks.md
├── bolt-pro
│ ├── _index.md
│ ├── advanced-tables.md
│ ├── assets.md
│ ├── fields.md
│ ├── introduction.md
│ ├── presets.md
│ └── share-form.md
├── filament-bolt-pro.md
├── filament.md
├── getting-started
│ ├── _index.md
│ ├── assets.md
│ ├── changelog.md
│ ├── configuration.md
│ ├── installation.md
│ ├── loading.md
│ └── upgrade.md
├── introduction.md
└── usage
│ ├── _index.md
│ ├── embed.md
│ └── overview.md
├── phpstan.neon
├── phpunit.xml.dist
├── pint.json
├── resources
├── lang
│ ├── ar.json
│ ├── ckb.json
│ ├── de.json
│ ├── en.json
│ ├── es.json
│ └── fr.json
└── views
│ ├── emails
│ └── form-submission.blade.php
│ ├── errors
│ ├── date-not-available.blade.php
│ ├── login-required.blade.php
│ └── one-entry-per-user.blade.php
│ ├── filament
│ ├── components
│ │ └── color-picker.blade.php
│ ├── fields
│ │ ├── file-upload.blade.php
│ │ └── types.blade.php
│ ├── pages
│ │ └── reports
│ │ │ └── entries.blade.php
│ └── resources
│ │ ├── form-resource
│ │ └── widgets
│ │ │ └── edit-collection-warning.blade.php
│ │ └── response-resource
│ │ ├── components
│ │ └── view-responses.blade.php
│ │ └── pages
│ │ ├── browse-entry.blade.php
│ │ ├── browse-responses.blade.php
│ │ └── show-entry.blade.php
│ └── themes
│ └── zeus
│ └── bolt
│ ├── fill-forms.blade.php
│ ├── list-entries.blade.php
│ ├── list-forms.blade.php
│ ├── loading.blade.php
│ ├── show-entry.blade.php
│ └── submitted.blade.php
├── routes
└── web.php
├── src
├── BoltPlugin.php
├── BoltServiceProvider.php
├── Commands
│ ├── InstallCommand.php
│ ├── PublishCommand.php
│ ├── ZeusDatasourceCommand.php
│ └── ZeusFieldCommand.php
├── Concerns
│ ├── CanManipulateFiles.php
│ ├── HasActive.php
│ ├── HasHiddenOptions.php
│ ├── HasOptions.php
│ ├── HasUpdates.php
│ └── Schemata.php
├── Configuration.php
├── Contracts
│ ├── CustomFormSchema.php
│ ├── CustomSchema.php
│ ├── DataSource.php
│ ├── Extension.php
│ └── Fields.php
├── DataSources
│ └── DataSourceContract.php
├── Events
│ ├── FormMounted.php
│ └── FormSent.php
├── Facades
│ ├── Bolt.php
│ ├── Collectors.php
│ ├── Designer.php
│ └── Extensions.php
├── Fields
│ ├── Classes
│ │ ├── CheckboxList.php
│ │ ├── ColorPicker.php
│ │ ├── DatePicker.php
│ │ ├── DateTimePicker.php
│ │ ├── FileUpload.php
│ │ ├── Paragraph.php
│ │ ├── Radio.php
│ │ ├── RichEditor.php
│ │ ├── Select.php
│ │ ├── TextInput.php
│ │ ├── Textarea.php
│ │ ├── TimePicker.php
│ │ └── Toggle.php
│ └── FieldsContract.php
├── Filament
│ ├── Actions
│ │ ├── ReplicateFormAction.php
│ │ └── SetResponseStatus.php
│ ├── Exports
│ │ └── ResponseExporter.php
│ └── Resources
│ │ ├── BoltResource.php
│ │ ├── CategoryResource.php
│ │ ├── CategoryResource
│ │ └── Pages
│ │ │ ├── CreateCategory.php
│ │ │ ├── EditCategory.php
│ │ │ └── ListCategories.php
│ │ ├── CollectionResource.php
│ │ ├── CollectionResource
│ │ ├── Pages
│ │ │ ├── CreateCollection.php
│ │ │ ├── EditCollection.php
│ │ │ └── ListCollections.php
│ │ └── Widgets
│ │ │ └── EditCollectionWarning.php
│ │ ├── FormResource.php
│ │ └── FormResource
│ │ ├── Pages
│ │ ├── BrowseResponses.php
│ │ ├── CreateForm.php
│ │ ├── EditForm.php
│ │ ├── ListForms.php
│ │ ├── ManageResponses.php
│ │ ├── ViewForm.php
│ │ └── ViewResponse.php
│ │ └── Widgets
│ │ ├── FormOverview.php
│ │ ├── ResponsesPerFields.php
│ │ ├── ResponsesPerMonth.php
│ │ └── ResponsesPerStatus.php
├── Livewire
│ ├── FillForms.php
│ ├── ListEntries.php
│ ├── ListForms.php
│ └── ShowEntry.php
├── Mail
│ └── FormSubmission.php
└── Models
│ ├── Category.php
│ ├── Collection.php
│ ├── Concerns
│ └── BelongToBolt.php
│ ├── Field.php
│ ├── FieldResponse.php
│ ├── Form.php
│ ├── FormsStatus.php
│ ├── Response.php
│ └── Section.php
├── stubs
├── ZeusDataSources.stub
└── ZeusField.stub
└── tests
├── AdminPanelProvider.php
├── ArchTest.php
├── FormsTest.php
├── Models
└── User.php
├── Pest.php
├── ResourcesTest.php
├── TestCase.php
└── migrations
├── 001_create_categories_table.php
├── 002_create_collections_table.php
├── 003_create_forms_table.php
├── 004_create_sections_table.php
├── 005_create_fields_table.php
├── 006_create_responses_table.php
└── 007_create_field_responses_table.php
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | end_of_line = lf
6 | indent_size = 4
7 | indent_style = space
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
11 | [*.md]
12 | trim_trailing_whitespace = false
13 |
14 | [*.{yml,yaml}]
15 | indent_size = 2
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | * text=auto
2 | *.css linguist-vendored
3 | *.scss linguist-vendored
4 | *.js linguist-vendored
5 | CHANGELOG.md export-ignore
6 |
--------------------------------------------------------------------------------
/.github/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | Contributions are **welcome** and will be fully **credited**.
4 |
5 | Please read and understand the contribution guide before creating an issue or pull request.
6 |
7 | ## Etiquette
8 |
9 | This project is open source, and as such, the maintainers give their free time to build and maintain the source code
10 | held within. They make the code freely available in the hope that it will be of use to other developers. It would be
11 | extremely unfair for them to suffer abuse or anger for their hard work.
12 |
13 | Please be considerate towards maintainers when raising issues or presenting pull requests. Let's show the
14 | world that developers are civilized and selfless people.
15 |
16 | It's the duty of the maintainer to ensure that all submissions to the project are of sufficient
17 | quality to benefit the project. Many developers have different skillsets, strengths, and weaknesses. Respect the maintainer's decision, and do not be upset or abusive if your submission is not used.
18 |
19 | ## Viability
20 |
21 | When requesting or submitting new features, first consider whether it might be useful to others. Open
22 | source projects are used by many developers, who may have entirely different needs to your own. Think about
23 | whether or not your feature is likely to be used by other users of the project.
24 |
25 | ## Procedure
26 |
27 | Before filing an issue:
28 |
29 | - Attempt to replicate the problem, to ensure that it wasn't a coincidental incident.
30 | - Check to make sure your feature suggestion isn't already present within the project.
31 | - Check the pull requests tab to ensure that the bug doesn't have a fix in progress.
32 | - Check the pull requests tab to ensure that the feature isn't already in progress.
33 |
34 | Before submitting a pull request:
35 |
36 | - Check the codebase to ensure that your feature doesn't already exist.
37 | - Check the pull requests to ensure that another person hasn't already submitted the feature or fix.
38 |
39 | ## Requirements
40 |
41 | If the project maintainer has any additional requirements, you will find them listed here.
42 |
43 | - **[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).
44 |
45 | - **Add tests!** - Your patch won't be accepted if it doesn't have tests.
46 |
47 | - **Document any change in behaviour** - Make sure the `README.md` and any other relevant documentation are kept up-to-date.
48 |
49 | - **Consider our release cycle** - We try to follow [SemVer v2.0.0](https://semver.org/). Randomly breaking public APIs is not an option.
50 |
51 | - **One pull request per feature** - If you want to do more than one thing, send multiple pull requests.
52 |
53 | - **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.
54 |
55 | **Happy coding**!
56 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: atmonshi
2 | custom: "https://www.buymeacoffee.com/larazeus"
3 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug.yml:
--------------------------------------------------------------------------------
1 | name: Bug Report
2 | description: Report an Issue or Bug with the Package
3 | title: "[Bug]: "
4 | labels: ["bug"]
5 | body:
6 | - type: markdown
7 | attributes:
8 | value: |
9 | We're sorry to hear you have a problem. Can you help us solve it by providing the following details.
10 | - type: textarea
11 | id: what-happened
12 | attributes:
13 | label: What happened?
14 | description: What did you expect to happen?
15 | placeholder: I cannot currently do X thing because when I do, it breaks X thing.
16 | validations:
17 | required: true
18 | - type: textarea
19 | id: how-to-reproduce
20 | attributes:
21 | label: How to reproduce the bug
22 | description: How did this occur, please add any config values used and provide a set of reliable steps if possible.
23 | placeholder: When I do X I see Y.
24 | validations:
25 | required: true
26 | - type: input
27 | id: package-version
28 | attributes:
29 | label: Package Version
30 | description: What version of our Package are you running? Please be as specific as possible
31 | placeholder: 2.0.0
32 | validations:
33 | required: true
34 | - type: input
35 | id: php-version
36 | attributes:
37 | label: PHP Version
38 | description: What version of PHP are you running? Please be as specific as possible
39 | placeholder: 8.2.0
40 | validations:
41 | required: true
42 | - type: input
43 | id: laravel-version
44 | attributes:
45 | label: Laravel Version
46 | description: What version of Laravel are you running? Please be as specific as possible
47 | placeholder: 9.0.0
48 | validations:
49 | required: true
50 | - type: dropdown
51 | id: operating-systems
52 | attributes:
53 | label: Which operating systems does with happen with?
54 | description: You may select more than one.
55 | multiple: true
56 | options:
57 | - macOS
58 | - Windows
59 | - Linux
60 | - type: textarea
61 | id: notes
62 | attributes:
63 | label: Notes
64 | description: Use this field to provide any other notes that you feel might be relevant to the issue.
65 | validations:
66 | required: false
67 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12 |
13 | **Describe the solution you'd like**
14 | A clear and concise description of what you want to happen.
15 |
16 | **Describe alternatives you've considered**
17 | A clear and concise description of any alternative solutions or features you've considered.
18 |
19 | **Additional context**
20 | Add any other context or screenshots about the feature request here.
21 |
--------------------------------------------------------------------------------
/.github/SECURITY.md:
--------------------------------------------------------------------------------
1 | # Security Policy
2 |
3 | If you discover any security related issues, please email info@larazeus.com instead of using the issue tracker.
4 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | # Please see the documentation for all configuration options:
2 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
3 |
4 | version: 2
5 | updates:
6 |
7 | - package-ecosystem: "github-actions"
8 | directory: "/"
9 | schedule:
10 | interval: "weekly"
11 | labels:
12 | - "dependencies"
--------------------------------------------------------------------------------
/.github/workflows/dependabot-auto-merge.yml:
--------------------------------------------------------------------------------
1 | name: dependabot-auto-merge
2 | on: pull_request_target
3 |
4 | permissions:
5 | pull-requests: write
6 | contents: write
7 |
8 | jobs:
9 | dependabot:
10 | runs-on: ubuntu-latest
11 | if: ${{ github.actor == 'dependabot[bot]' }}
12 | steps:
13 |
14 | - name: Dependabot metadata
15 | id: metadata
16 | uses: dependabot/fetch-metadata@v2.4.0
17 | with:
18 | github-token: "${{ secrets.GITHUB_TOKEN }}"
19 |
20 | - name: Auto-merge Dependabot PRs for semver-minor updates
21 | if: ${{steps.metadata.outputs.update-type == 'version-update:semver-minor'}}
22 | run: gh pr merge --auto --merge "$PR_URL"
23 | env:
24 | PR_URL: ${{github.event.pull_request.html_url}}
25 | GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
26 |
27 | - name: Auto-merge Dependabot PRs for semver-patch updates
28 | if: ${{steps.metadata.outputs.update-type == 'version-update:semver-patch'}}
29 | run: gh pr merge --auto --merge "$PR_URL"
30 | env:
31 | PR_URL: ${{github.event.pull_request.html_url}}
32 | GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
--------------------------------------------------------------------------------
/.github/workflows/fix-php-code-style-issues.yml:
--------------------------------------------------------------------------------
1 | name: code style
2 |
3 | on: [push]
4 |
5 | jobs:
6 | php-code-styling:
7 | runs-on: ubuntu-latest
8 |
9 | steps:
10 | - name: Checkout code
11 | uses: actions/checkout@v4
12 | with:
13 | ref: ${{ github.head_ref }}
14 |
15 | - name: Fix PHP code style issues
16 | uses: aglipanci/laravel-pint-action@2.5
17 |
18 | - name: Commit changes
19 | uses: stefanzweifel/git-auto-commit-action@v5
20 | with:
21 | commit_message: Fix styling
22 |
--------------------------------------------------------------------------------
/.github/workflows/phpstan.yml:
--------------------------------------------------------------------------------
1 | name: PHPStan
2 |
3 | on:
4 | push:
5 | paths:
6 | - '**.php'
7 | - 'phpstan.neon.dist'
8 |
9 | jobs:
10 | phpstan:
11 | name: phpstan
12 | runs-on: ubuntu-latest
13 | steps:
14 | - uses: actions/checkout@v4
15 |
16 | - name: Setup PHP
17 | uses: shivammathur/setup-php@v2
18 | with:
19 | php-version: '8.3'
20 | coverage: none
21 |
22 | - name: Install composer dependencies
23 | uses: ramsey/composer-install@v3
24 |
25 | - name: Run PHPStan
26 | run: ./vendor/bin/phpstan --error-format=github
--------------------------------------------------------------------------------
/.github/workflows/run-tests.yml:
--------------------------------------------------------------------------------
1 | name: run-tests
2 |
3 | on:
4 | push:
5 | branches: [3.x]
6 | pull_request:
7 | branches: [3.x]
8 |
9 | jobs:
10 | test:
11 | runs-on: ${{ matrix.os }}
12 | strategy:
13 | fail-fast: true
14 | matrix:
15 | os: [ubuntu-latest, windows-latest]
16 | php: [8.2]
17 | laravel: [12.*]
18 | stability: [prefer-stable]
19 | include:
20 | - laravel: 12.*
21 | testbench: 10.*
22 |
23 | name: P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.stability }} - ${{ matrix.os }}
24 |
25 | steps:
26 | - name: Checkout code
27 | uses: actions/checkout@v4
28 |
29 | - name: Setup PHP
30 | uses: shivammathur/setup-php@v2
31 | with:
32 | php-version: ${{ matrix.php }}
33 | extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick, fileinfo
34 | coverage: none
35 |
36 | - name: Setup problem matchers
37 | run: |
38 | echo "::add-matcher::${{ runner.tool_cache }}/php.json"
39 | echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json"
40 |
41 | - name: Install dependencies
42 | run: |
43 | composer require "laravel/framework:${{ matrix.laravel }}" "orchestra/testbench:${{ matrix.testbench }}" --no-interaction --no-update
44 | composer update --${{ matrix.stability }} --prefer-dist --no-interaction
45 |
46 | - name: Execute tests
47 | run: vendor/bin/pest
--------------------------------------------------------------------------------
/.github/workflows/update-changelog.yml:
--------------------------------------------------------------------------------
1 | name: "Update Changelog"
2 |
3 | on:
4 | release:
5 | types: [released]
6 |
7 | jobs:
8 | update:
9 | runs-on: ubuntu-latest
10 |
11 | steps:
12 | - name: Checkout code
13 | uses: actions/checkout@v4
14 | with:
15 | ref: 3.x
16 |
17 | - name: Update Changelog
18 | uses: stefanzweifel/changelog-updater-action@v1
19 | with:
20 | latest-version: ${{ github.event.release.name }}
21 | release-notes: ${{ github.event.release.body }}
22 |
23 | - name: Commit updated CHANGELOG
24 | uses: stefanzweifel/git-auto-commit-action@v5
25 | with:
26 | branch: 3.x
27 | commit_message: Update CHANGELOG
28 | file_pattern: CHANGELOG.md
29 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /node_modules
2 | /public/hot
3 | /public/storage
4 | /storage/*.key
5 | /vendor
6 | /vendor/.idea
7 | /bootstrap/cache
8 | .env
9 | .env.backup
10 | .phpunit.result.cache
11 | docker-compose.override.yml
12 | Homestead.json
13 | Homestead.yaml
14 | npm-debug.log
15 | yarn-error.log
16 | /.idea
17 | /.vscode
18 | /pkg
19 | /build
20 | .DS_Store
21 | /.phpunit.cache
22 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "semi": false,
3 | "singleQuote": true,
4 | "trailingComma": "all"
5 | }
6 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) Lara Zeus (Ash)
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "lara-zeus/bolt",
3 | "description": "Zeus Bolt is form builder for your users, with so many use cases",
4 | "keywords": [
5 | "laravel",
6 | "lara-zeus",
7 | "bolt",
8 | "form",
9 | "forms",
10 | "generator",
11 | "self hosted",
12 | "maker",
13 | "builder",
14 | "filamentphp"
15 | ],
16 | "homepage": "https://larazeus.com/bolt",
17 | "support": {
18 | "issues": "https://github.com/lara-zeus/bolt/issues",
19 | "source": "https://github.com/lara-zeus/bolt"
20 | },
21 | "license": "MIT",
22 | "type": "library",
23 | "authors": [
24 | {
25 | "name": "Lara Zeus (Ash)",
26 | "email": "info@larazeus.com"
27 | }
28 | ],
29 | "require": {
30 | "php": "^8.1",
31 | "flowframe/laravel-trend": "^0.4",
32 | "guava/filament-icon-picker": "^2.3",
33 | "lara-zeus/accordion": "^1.1",
34 | "lara-zeus/core": "^3.2",
35 | "lara-zeus/filament-plugin-tools": "^1.0",
36 | "lara-zeus/list-group": "^1.0",
37 | "pxlrbt/filament-excel": "^2.4",
38 | "secondnetwork/blade-tabler-icons": "^3.30"
39 | },
40 | "require-dev": {
41 | "phpstan/extension-installer": "^1.4",
42 | "larastan/larastan": "^3.0",
43 | "laravel/pint": "^1.0",
44 | "nunomaduro/collision": "^8.6",
45 | "nunomaduro/phpinsights": "^2.8",
46 | "orchestra/testbench": "^10.0",
47 | "pestphp/pest": "^3.0",
48 | "pestphp/pest-plugin-arch": "^3.0",
49 | "pestphp/pest-plugin-laravel": "^3.0",
50 | "pestphp/pest-plugin-livewire": "^3.0"
51 | },
52 | "autoload": {
53 | "psr-4": {
54 | "LaraZeus\\Bolt\\": "src",
55 | "LaraZeus\\Bolt\\Database\\Factories\\": "database/factories/"
56 | }
57 | },
58 | "autoload-dev": {
59 | "psr-4": {
60 | "LaraZeus\\Bolt\\Tests\\": "tests"
61 | }
62 | },
63 | "scripts": {
64 | "analyse": "vendor/bin/phpstan analyse",
65 | "test": "vendor/bin/pest",
66 | "test-coverage": "vendor/bin/pest --coverage",
67 | "format": "vendor/bin/pint",
68 | "pint": "vendor/bin/pint",
69 | "test:pest": "vendor/bin/pest --parallel",
70 | "test:phpstan": "vendor/bin/phpstan analyse"
71 | },
72 | "config": {
73 | "sort-packages": true,
74 | "allow-plugins": {
75 | "pestphp/pest-plugin": true,
76 | "phpstan/extension-installer": true,
77 | "dealerdirect/phpcodesniffer-composer-installer": true
78 | }
79 | },
80 | "extra": {
81 | "laravel": {
82 | "providers": [
83 | "LaraZeus\\Bolt\\BoltServiceProvider"
84 | ],
85 | "aliases": {
86 | "Bolt": "LaraZeus\\Bolt\\Facades\\Bolt"
87 | }
88 | }
89 | },
90 | "prefer-stable": true
91 | }
92 |
--------------------------------------------------------------------------------
/config/zeus-bolt.php:
--------------------------------------------------------------------------------
1 | null,
8 |
9 | /**
10 | * set the default path for the forms homepage.
11 | */
12 | 'prefix' => 'bolt',
13 |
14 | /*
15 | * set database table prefix
16 | */
17 | 'table-prefix' => 'bolt_',
18 |
19 | /**
20 | * the middleware you want to apply on all the blog routes
21 | * for example if you want to make your blog for users only, add the middleware 'auth'.
22 | */
23 | 'middleware' => ['web'],
24 |
25 | /**
26 | * you can overwrite any model and use your own
27 | * you can also configure the model per panel in your panel provider using:
28 | * ->skyModels([ ... ])
29 | */
30 | 'models' => [
31 | 'Category' => \LaraZeus\Bolt\Models\Category::class,
32 | 'Collection' => \LaraZeus\Bolt\Models\Collection::class,
33 | 'Field' => \LaraZeus\Bolt\Models\Field::class,
34 | 'FieldResponse' => \LaraZeus\Bolt\Models\FieldResponse::class,
35 | 'Form' => \LaraZeus\Bolt\Models\Form::class,
36 | 'FormsStatus' => \LaraZeus\Bolt\Models\FormsStatus::class,
37 | 'Response' => \LaraZeus\Bolt\Models\Response::class,
38 | 'Section' => \LaraZeus\Bolt\Models\Section::class,
39 | 'User' => config('auth.providers.users.model'),
40 | ],
41 |
42 | 'collectors' => [
43 | 'fields' => [
44 | 'path' => 'app/Zeus/Fields',
45 | 'namespace' => '\\App\\Zeus\\Fields\\',
46 | ],
47 |
48 | 'dataSources' => [
49 | 'path' => 'app/Zeus/DataSources',
50 | 'namespace' => 'App\\Zeus\\DataSources\\',
51 | ],
52 | ],
53 |
54 | 'defaultMailable' => \LaraZeus\Bolt\Mail\FormSubmission::class,
55 |
56 | 'uploadDisk' => env('BOLT_FILESYSTEM_DISK', 'public'),
57 |
58 | 'uploadDirectory' => env('BOLT_FILESYSTEM_DIRECTORY', 'forms'),
59 |
60 | 'uploadVisibility' => env('BOLT_FILESYSTEM_VISIBILITY', 'public'),
61 |
62 | /*
63 | * if you have installed Bolt Pro, you can enable the presets here
64 | */
65 | 'show_presets' => false,
66 |
67 | /**
68 | * the preset comes with a demo forms:
69 | * a Contact form and Ticket support form.
70 | * if you dont want them, feel free to set this to false
71 | * */
72 | 'show_core_presets' => true,
73 |
74 | /**
75 | * the preview for the presets is using sushi:
76 | * you can enable/disable the cache here
77 | * */
78 | 'should_cache_preset' => env('BOLT_CACHE_PRESET', true),
79 |
80 | /*
81 | * if you have installed Bolt Pro, you can enable the form design option here
82 | */
83 | 'allow_design' => false,
84 |
85 | /**
86 | * since `collections` or 'data sources' have many types, we cannot lazy load them
87 | * but we cache them for a while to get better performance
88 | * the key is: dataSource_*_response_md5
89 | *
90 | * here you can set the duration of the cache
91 | */
92 | 'cache' => [
93 | 'collection_values' => 30, // on seconds
94 | ],
95 | ];
96 |
--------------------------------------------------------------------------------
/database/factories/CategoryFactory.php:
--------------------------------------------------------------------------------
1 | $this->faker->words(3, true),
16 | 'ordering' => $this->faker->numberBetween(1, 10),
17 | 'is_active' => 1,
18 | 'description' => $this->faker->words(5, true),
19 | 'slug' => $this->faker->slug,
20 | ];
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/database/factories/CollectionFactory.php:
--------------------------------------------------------------------------------
1 | $this->faker->words(3, true),
16 | 'user_id' => config('auth.providers.users.model')::factory(),
17 | 'values' => 'abc',
18 | ];
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/database/factories/FieldFactory.php:
--------------------------------------------------------------------------------
1 | $this->faker->words(3, true),
17 | 'type' => '\LaraZeus\Bolt\Fields\Classes\TextInput',
18 | 'section_id' => BoltPlugin::getModel('Section')::factory(),
19 | 'ordering' => $this->faker->numberBetween(1, 20),
20 | ];
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/database/factories/FieldResponseFactory.php:
--------------------------------------------------------------------------------
1 | BoltPlugin::getModel('Forms')::factory(),
17 | 'field_id' => BoltPlugin::getModel('Field')::factory(),
18 | 'response_id' => BoltPlugin::getModel('Response')::factory(),
19 | 'response' => $this->faker->words(3, true),
20 | ];
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/database/factories/FormFactory.php:
--------------------------------------------------------------------------------
1 | $this->faker->words(3, true),
17 | 'user_id' => 1,
18 | 'ordering' => $this->faker->numberBetween(1, 20),
19 | 'description' => $this->faker->text(),
20 | 'slug' => $this->faker->slug(),
21 | 'is_active' => 1,
22 | 'category_id' => BoltPlugin::getModel('Category')::factory(),
23 | 'start_date' => $this->faker->dateTime(),
24 | 'end_date' => $this->faker->dateTime(),
25 | ];
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/database/factories/ResponseFactory.php:
--------------------------------------------------------------------------------
1 | BoltPlugin::getModel('Form')::factory(),
17 | 'status' => 'NEW',
18 | 'user_id' => 1,
19 | 'notes' => $this->faker->text(),
20 | ];
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/database/factories/SectionFactory.php:
--------------------------------------------------------------------------------
1 | $this->faker->words(3, true),
17 | 'form_id' => BoltPlugin::getModel('Form')::factory(),
18 | 'ordering' => $this->faker->numberBetween(1, 10),
19 | ];
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/database/factories/UserFactory.php:
--------------------------------------------------------------------------------
1 | fake()->name(),
17 | 'email' => fake()->unique()->safeEmail(),
18 | 'email_verified_at' => now(),
19 | 'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
20 | 'remember_token' => Str::random(10),
21 | ];
22 | }
23 |
24 | /**
25 | * Indicate that the model's email address should be unverified.
26 | */
27 | public function unverified(): static
28 | {
29 | return $this->state(fn (array $attributes) => [
30 | 'email_verified_at' => null,
31 | ]);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/database/migrations/add_borderless_to_section.php.stub:
--------------------------------------------------------------------------------
1 | boolean('borderless')->default(0);
18 | });
19 | }
20 |
21 | /**
22 | * Reverse the migrations.
23 | *
24 | * @return void
25 | */
26 | public function down()
27 | {
28 | Schema::table(config('zeus-bolt.table-prefix').'sections', function (Blueprint $table) {
29 | $table->dropColumn('borderless');
30 | });
31 | }
32 | };
33 |
--------------------------------------------------------------------------------
/database/migrations/add_compact_to_section.php.stub:
--------------------------------------------------------------------------------
1 | boolean('compact')->default(0);
18 | });
19 | }
20 |
21 | /**
22 | * Reverse the migrations.
23 | *
24 | * @return void
25 | */
26 | public function down()
27 | {
28 | Schema::table(config('zeus-bolt.table-prefix').'sections', function (Blueprint $table) {
29 | $table->dropColumn('compact');
30 | });
31 | }
32 | };
33 |
--------------------------------------------------------------------------------
/database/migrations/add_extension_item_responses.php.stub:
--------------------------------------------------------------------------------
1 | integer('extension_item_id')->nullable();
15 | });
16 | }
17 |
18 | /**
19 | * Reverse the migrations.
20 | */
21 | public function down(): void
22 | {
23 | Schema::table(config('zeus-bolt.table-prefix').'responses', function (Blueprint $table) {
24 | $table->dropColumn('extension_item_id');
25 | });
26 | }
27 | };
28 |
--------------------------------------------------------------------------------
/database/migrations/add_extensions_to_forms.php.stub:
--------------------------------------------------------------------------------
1 | text('extensions')->nullable();
18 | });
19 | }
20 |
21 | /**
22 | * Reverse the migrations.
23 | *
24 | * @return void
25 | */
26 | public function down()
27 | {
28 | Schema::table(config('zeus-bolt.table-prefix').'forms', function (Blueprint $table) {
29 | $table->dropColumn('extensions');
30 | });
31 | }
32 | };
33 |
--------------------------------------------------------------------------------
/database/migrations/add_grade_to_field_response.php.stub:
--------------------------------------------------------------------------------
1 | integer('grade')->nullable();
18 | });
19 | }
20 |
21 | /**
22 | * Reverse the migrations.
23 | *
24 | * @return void
25 | */
26 | public function down()
27 | {
28 | Schema::table(config('zeus-bolt.table-prefix').'field_responses', function (Blueprint $table) {
29 | $table->dropColumn('grade');
30 | });
31 | }
32 | };
33 |
--------------------------------------------------------------------------------
/database/migrations/add_grade_to_response.php.stub:
--------------------------------------------------------------------------------
1 | integer('grades')->nullable();
18 | });
19 | }
20 |
21 | /**
22 | * Reverse the migrations.
23 | *
24 | * @return void
25 | */
26 | public function down()
27 | {
28 | Schema::table(config('zeus-bolt.table-prefix').'responses', function (Blueprint $table) {
29 | $table->dropColumn('grades');
30 | });
31 | }
32 | };
33 |
--------------------------------------------------------------------------------
/database/migrations/add_options_to_section.php.stub:
--------------------------------------------------------------------------------
1 | text('options')->nullable();
18 | });
19 | }
20 |
21 | /**
22 | * Reverse the migrations.
23 | *
24 | * @return void
25 | */
26 | public function down()
27 | {
28 | Schema::table(config('zeus-bolt.table-prefix').'sections', function (Blueprint $table) {
29 | $table->dropColumn('options');
30 | });
31 | }
32 | };
33 |
--------------------------------------------------------------------------------
/database/migrations/alter_tables_constraints.php.stub:
--------------------------------------------------------------------------------
1 | dropForeign(['user_id']);
18 | $table->dropForeign(['category_id']);
19 |
20 | $table->unsignedBigInteger('user_id')->nullable()->change();
21 | Schema::enableForeignKeyConstraints();
22 |
23 | $table->foreign('user_id')
24 | ->onUpdate('cascade')
25 | ->nullOnDelete()
26 | ->references('id')
27 | ->on('users');
28 |
29 | $table->foreign('category_id')
30 | ->onUpdate('cascade')
31 | ->nullOnDelete()
32 | ->references('id')
33 | ->on(config('zeus-bolt.table-prefix').'categories');
34 | });
35 | }
36 |
37 | /**
38 | * Reverse the migrations.
39 | *
40 | * @return void
41 | */
42 | public function down()
43 | {
44 |
45 | }
46 | };
47 |
--------------------------------------------------------------------------------
/database/migrations/create_categories_table.php.stub:
--------------------------------------------------------------------------------
1 | id();
18 | $table->text('name');
19 | $table->integer('ordering')->default(1);
20 | $table->boolean('is_active')->default(1);
21 | $table->text('description')->nullable();
22 | $table->string('slug');
23 | $table->string('logo')->nullable();
24 | $table->timestamps();
25 | $table->softDeletes();
26 | });
27 | }
28 |
29 | /**
30 | * Reverse the migrations.
31 | *
32 | * @return void
33 | */
34 | public function down()
35 | {
36 | Schema::dropIfExists(config('zeus-bolt.table-prefix').'categories');
37 | }
38 | };
39 |
--------------------------------------------------------------------------------
/database/migrations/create_collections_table.php.stub:
--------------------------------------------------------------------------------
1 | id();
18 | $table->text('name');
19 | $table->longText('values')->nullable();
20 | $table->timestamps();
21 | $table->softDeletes();
22 | });
23 | }
24 |
25 | /**
26 | * Reverse the migrations.
27 | *
28 | * @return void
29 | */
30 | public function down()
31 | {
32 | Schema::dropIfExists(config('zeus-bolt.table-prefix').'collections');
33 | }
34 | };
35 |
--------------------------------------------------------------------------------
/database/migrations/create_field_responses_table.php.stub:
--------------------------------------------------------------------------------
1 | id();
18 | $table->foreignId('form_id')->constrained(config('zeus-bolt.table-prefix').'forms');
19 | $table->foreignId('field_id')->constrained(config('zeus-bolt.table-prefix').'fields');
20 | $table->foreignId('response_id')->constrained(config('zeus-bolt.table-prefix').'responses');
21 | $table->longText('response');
22 | $table->timestamps();
23 | $table->softDeletes();
24 | });
25 | }
26 |
27 | /**
28 | * Reverse the migrations.
29 | *
30 | * @return void
31 | */
32 | public function down()
33 | {
34 | Schema::dropIfExists(config('zeus-bolt.table-prefix').'field_responses');
35 | }
36 | };
37 |
--------------------------------------------------------------------------------
/database/migrations/create_fields_table.php.stub:
--------------------------------------------------------------------------------
1 | id();
18 | $table->foreignId('section_id')->constrained(config('zeus-bolt.table-prefix').'sections');
19 | $table->text('name');
20 | $table->text('description')->nullable();
21 | $table->string('type');
22 | $table->integer('ordering')->default(1);
23 | $table->text('options')->nullable();
24 | $table->timestamps();
25 | $table->softDeletes();
26 | });
27 | }
28 |
29 | /**
30 | * Reverse the migrations.
31 | *
32 | * @return void
33 | */
34 | public function down()
35 | {
36 | Schema::dropIfExists(config('zeus-bolt.table-prefix').'fields');
37 | }
38 | };
39 |
--------------------------------------------------------------------------------
/database/migrations/create_forms_table.php.stub:
--------------------------------------------------------------------------------
1 | id();
18 | $table->foreignId('user_id')->constrained('users');
19 | $table->foreignId('category_id')->nullable()->constrained(config('zeus-bolt.table-prefix').'categories');
20 | $table->text('name');
21 | $table->text('description')->nullable();
22 | $table->string('slug');
23 | $table->integer('ordering')->default(1);
24 | $table->boolean('is_active');
25 | $table->longText('details')->nullable();
26 | $table->longText('options')->nullable();
27 | $table->dateTime('start_date')->nullable();
28 | $table->dateTime('end_date')->nullable();
29 | $table->timestamps();
30 | $table->softDeletes();
31 | });
32 | }
33 |
34 | /**
35 | * Reverse the migrations.
36 | *
37 | * @return void
38 | */
39 | public function down()
40 | {
41 | Schema::dropIfExists(config('zeus-bolt.table-prefix').'forms');
42 | }
43 | };
44 |
--------------------------------------------------------------------------------
/database/migrations/create_responses_table.php.stub:
--------------------------------------------------------------------------------
1 | id();
18 | $table->foreignId('form_id')->constrained(config('zeus-bolt.table-prefix').'forms');
19 | $table->foreignId('user_id')->nullable()->constrained('users');
20 | $table->string('status')->default('NEW');
21 | $table->text('notes')->nullable();
22 | $table->timestamps();
23 | $table->softDeletes();
24 | });
25 | }
26 |
27 | /**
28 | * Reverse the migrations.
29 | *
30 | * @return void
31 | */
32 | public function down()
33 | {
34 | Schema::dropIfExists(config('zeus-bolt.table-prefix').'responses');
35 | }
36 | };
37 |
--------------------------------------------------------------------------------
/database/migrations/create_sections_table.php.stub:
--------------------------------------------------------------------------------
1 | id();
18 | $table->foreignId('form_id')->constrained(config('zeus-bolt.table-prefix').'forms');
19 | $table->text('name')->nullable();
20 | $table->integer('ordering')->default(1);
21 | $table->integer('columns')->default(1);
22 | $table->text('description')->nullable();
23 | $table->string('icon')->nullable();
24 | $table->boolean('aside')->default(0);
25 | $table->timestamps();
26 | $table->softDeletes();
27 | });
28 | }
29 |
30 | /**
31 | * Reverse the migrations.
32 | *
33 | * @return void
34 | */
35 | public function down()
36 | {
37 | Schema::dropIfExists(config('zeus-bolt.table-prefix').'sections');
38 | }
39 | };
40 |
--------------------------------------------------------------------------------
/docs/_index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: v3
3 | slogan: form builder for your users, with so many use cases.
4 | githubUrl: https://github.com/lara-zeus/bolt
5 | branch: main
6 | icon: akar-thunder
7 | ---
8 |
--------------------------------------------------------------------------------
/docs/advanced/_index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Advanced
3 | weight: 3
4 | ---
5 |
--------------------------------------------------------------------------------
/docs/advanced/add-datasource.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Custom Datasource
3 | weight: 5
4 | ---
5 |
6 | ## Create Custom Datasource
7 |
8 | Create a custom data source for your forms and make it available as a collection.
9 | Datasources are helpful for creating custom collections from different models or an external API.
10 |
11 | To create datasource, use the following command, passing the name of the datasource:
12 |
13 | ```bash
14 | php artisan make:zeus-datasource Car
15 | ```
16 |
17 | ## Caching
18 |
19 | Bolt will automatically list the data sources from your app in the form builder as a collection.
20 | There is a cache for all collections, so remember to flush the key `bolt.datasources`
21 |
22 | ## Customization
23 | Check out the contract `LaraZeus\Bolt\DataSources\DataSourceContract` and see all the available methods.
24 |
25 | ### Disabling
26 |
27 | You can turn off any field temporally by adding:
28 | ```php
29 | public bool $disabled = true;
30 | ```
31 |
--------------------------------------------------------------------------------
/docs/advanced/add-fields.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Custom Fields
3 | weight: 4
4 | ---
5 |
6 | ## Create Custom Fields
7 |
8 | Add any custom fields you want that is available on the [filament core](https://filamentphp.com/docs/3.x/forms/fields/getting-started) or [filament plugins](https://filamentphp.com/plugins).
9 |
10 | For example, we want to allow our users to use icon picker in the forms.
11 |
12 | ### First, install the package:
13 |
14 | ```bash
15 | composer require guava/filament-icon-picker
16 | ```
17 |
18 | ### Create bolt field
19 |
20 | Create the field using the following command, passing the fully qualified name of the form component:
21 |
22 | ```bash
23 | php artisan make:zeus-field \\Guava\\FilamentIconPicker\\Forms\\IconPicker
24 | ```
25 |
26 | ## Caching
27 |
28 | Bolt will automatically list the field in the form builder.
29 | There is a cache for all fields, so remember to flush the key `bolt.fields`
30 |
31 | ## Customization
32 |
33 | Check out the contract `LaraZeus\Bolt\Fields\FieldsContract` and see all the available methods.
34 |
35 | ### Disabling
36 |
37 | You can turn off any field temporally by adding:
38 | ```php
39 | public bool $disabled = true;
40 | ```
41 |
42 | ### Field Title
43 |
44 | ```php
45 | public function title(): string
46 | {
47 | return __(class_basename($this));
48 | }
49 | ```
50 |
51 | ### Field Options
52 |
53 | You can add any options to be shown on the admin page when creating the form
54 |
55 | ```php
56 | public static function getOptions(): array
57 | {
58 | return [
59 | Toggle::make('options.is_required')->label(__('Is Required')),
60 | ];
61 | }
62 | ```
63 |
64 | And to apply these options to the field in the frontend:
65 |
66 | ```php
67 | public function appendFilamentComponentsOptions($component, $zeusField)
68 | {
69 | parent::appendFilamentComponentsOptions($component, $zeusField);
70 |
71 | if (isset($zeusField->options['is_required']) && $zeusField->options['is_required']) {
72 | $component = $component->required();
73 | }
74 | }
75 | ```
76 |
77 | ### Disable the options tab
78 |
79 | If your field doesn't have any options, you can turn off the options tab by removing the method `getOptions` or returning false:
80 |
81 | ```php
82 | public function hasOptions(): bool
83 | {
84 | return false;
85 | }
86 | ```
87 |
88 | ### View the Response
89 |
90 | You can control how to view the response on the entries pages
91 |
92 | ```php
93 | public function getResponse($field, $resp): string
94 | {
95 | return $resp->response;
96 | }
97 | ```
98 |
--------------------------------------------------------------------------------
/docs/advanced/custom-designer.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Custom Designer
3 | weight: 7
4 | ---
5 |
6 | ## Use Custom Designer
7 |
8 | The class `Designer` is the one responsible for presenting the form in the frontend, and now you can customize it to your liking.
9 |
10 | > **Note**\
11 | > This is an advanced feature; please use it only when necessary since you have to mainline it manually with every update for Bolt.
12 |
13 | ### First, copy the class to your app
14 |
15 | Copy the class from `\LaraZeus\Bolt\Facades` to your app, lets say: `\App\Zeus\Bolt\Classes`
16 |
17 | ### Call the class in a service provider
18 |
19 | In your register method of your `AppServiceProvider` add the following:
20 |
21 | ```php
22 | \LaraZeus\Bolt\Livewire\FillForms::getBoltFormDesignerUsing(\App\Zeus\Bolt\Concerns\Designer::class);
23 | ```
24 |
25 | You're done. Customize the form builder to fit your needs. Remember to keep an eye on any changes in future updates so that you avoid breaking changes.
26 |
--------------------------------------------------------------------------------
/docs/advanced/custom-schemata.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Custom Schemata
3 | weight: 6
4 | ---
5 |
6 | ## Add Custom Schema for fields
7 |
8 | Bolt allows you to add custom components (additional metadata) to the form, sections, and fields.
9 |
10 | ### First: create the class
11 |
12 | Create a class wherever you want in your app for example in `App\Zeus\CustomSchema` with the content:
13 |
14 | ```php
15 | schema([
31 | TextInput::make('options.meta.data_binding')
32 | ->label('Data Binding'),
33 | ]);
34 | }
35 |
36 | public function hidden(?FieldsContract $field = null): array
37 | {
38 | return [
39 | Hidden::make('options.meta.data_binding'),
40 | ];
41 | }
42 | }
43 | ```
44 |
45 | - Make sure to return the hidden fields the same as the fields you have defined in the `make` method
46 | - Make sure to set the `state` correctly, if you want to store this info in the `options` then use `options. more data, or in a separate column then make sure to create the migration for it
47 |
48 | ### Second: add it to your panel config
49 |
50 | ```php
51 | BoltPlugin::make()
52 | ->customSchema([
53 | 'form' => null,
54 | 'section' => null,
55 | 'field' => \App\Zeus\CustomSchema\Field::class,
56 | ])
57 | ```
58 |
59 | ### Third: catch it on the `FormSent` event, for example
60 |
61 | ```php
62 | $event->response->fieldsResponses->each(function($fieldResponse){
63 | CustomeModel::create([
64 | 'column' => $fieldResponse->field->options['meta']['data_binding']
65 | ]);
66 | });
67 | ```
68 |
69 | >**Warning: This is a simplified example, so don't trust your user input explicitly. That could open some pretty serious security holes.**
70 |
71 | ## Replace the Schemata with Custom one
72 |
73 | The trait `Schemata` is the heart of the form builder, and now you can customize it to your liking.
74 |
75 | > **Note**\
76 | > This is an advanced feature; please use it only when necessary since you have to mainline it manually with every update for Bolt.
77 |
78 | ### First, copy the trait to your app
79 |
80 | Copy the trait from `\LaraZeus\Bolt\Concerns` to your app, lets say: `\App\Zeus\Bolt\Concerns`
81 |
82 | ### Call the trait in a service provider
83 |
84 | In your register method of your `AppServiceProvider` add the following:
85 |
86 | ```php
87 | \LaraZeus\Bolt\Filament\Resources\FormResource::getBoltFormSchemaUsing(fn(): array => \App\Zeus\Bolt\Facades\Designer::getMainFormSchema());
88 | ```
89 |
90 | You're done. Customize the form builder to fit your needs. Remember to keep an eye on any changes in future updates so that you avoid breaking changes.
--------------------------------------------------------------------------------
/docs/advanced/events.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Events
3 | weight: 1
4 | ---
5 |
6 | ## Available Events
7 |
8 | Bolt will fire these events:
9 | - `LaraZeus\Bolt\Events\FormMounted`
10 | - `LaraZeus\Bolt\Events\FormSent`
11 |
12 | ## Register a Listener:
13 | * First, create your listener:
14 | ```bash
15 | php artisan make:listener SendNotification --event=FormMounted
16 | ```
17 |
18 | * Second, register the listener in your `EventServiceProvider`
19 |
20 | ```php
21 | protected $listen = [
22 | //...
23 | LetterSent::class => [
24 | SendNotification::class,
25 | ],
26 | ];
27 | ```
28 |
29 | * Finally, you can receive the form object in the `handle` method and do whatever you want.
30 | For example:
31 |
32 | ```php
33 | Mail::to(User::first())->send(new \App\Mail\Contact(
34 | $event->form->name, $event->letter->email, $event->letter->message
35 | ));
36 | ```
37 |
--------------------------------------------------------------------------------
/docs/advanced/extension.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Extensions
3 | weight: 3
4 | ---
5 |
6 | ## Extensions
7 |
8 | Bolt offer a simple way to build your own application around the forms, with a simple interface, called `extensions` :
9 |
10 | Extensions are hooks based classes that let you perform your logic around the forms or catch the submission and do more integrations with other apps or external APIs.
11 | for example before showing the form, or after storing the data etc...
12 |
13 | ## Available Hooks:
14 |
15 | - `canView`
16 | before displaying the form, you can do some checks
17 |
18 | - `render`
19 | what to show at the beginning of the form, you can return a view to show more info or instructors while filling out the form
20 |
21 | -`formComponents`
22 | return an array of filament components to add them to the form in the frontend
23 |
24 | - `store`
25 | the store logic for the extension, insert to any DB or external API
26 |
27 | - `postStore`
28 | this is typically used for sending only. It will be executed after saving the form
29 |
30 | - `submittedRender`
31 | this will show any info after saving the form, like a request number or more buttons and links
32 |
33 |
34 | ## Creating an Extension
35 |
36 | Create a class in your app with the following content:
37 |
38 | >I will create a command later :)
39 |
40 | ```php
41 |
42 | $data['order_number'],
83 | // ...
84 | ]);*/
85 |
86 | // return these data to recive them after the form submitted
87 | // $data['model'] = $model;
88 |
89 | return $data;
90 | }
91 |
92 | public function postStore(Form $form, array $data): void
93 | {
94 | // send emails
95 | // fire some events
96 | }
97 |
98 | public function SubmittedRender(Form $form, array $data): string|null
99 | {
100 | // return view()->with('data', $data);
101 | }
102 | }
103 |
104 | ```
105 |
106 | ## Enabling The Extension
107 |
108 | In your `zeus-bolt` config file, add your extension to the array:
109 |
110 | ```php
111 | 'extensions' => [
112 | \App\Zeus\Extensions\Items::class,
113 | ],
114 | ```
115 |
116 | Now when creating or editing a form, you will see the tab Extensions, and you can select any extension per form.
117 |
--------------------------------------------------------------------------------
/docs/advanced/render-hooks.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Render hooks
3 | weight: 2
4 | ---
5 |
6 | ## Render Hooks
7 |
8 | Filament provides an elegant way to allow you to customize the UI without having to publish any views by using the `renderHook.`
9 |
10 | Bolt also utilizes these hooks to make it easier to customize any views.
11 |
12 | ### available hooks
13 |
14 | - `Zeus-forms.before`
15 | - will be rendered on the `bolt/` page before listing all categories and forms
16 |
17 | - `Zeus-forms.after`
18 | - will be rendered on the `bolt/` page after listing all categories and forms
19 |
20 | - `Zeus-form.before`
21 | - will be rendered above all forms before any other content like the `details.`
22 |
23 | - `Zeus-form.after`
24 | - this hook will be rendered after all forms
25 |
26 | - `Zeus-form-section.before`
27 | - before rendering any section in all forms
28 |
29 | - `Zeus-form-section.after`
30 | - after rendering any section in all forms
31 |
32 | - `Zeus-form-field.before`
33 | - before rendering any field in all forms
34 |
35 | - `Zeus-form-field.after`
36 | - after rendering any field in all forms
37 |
38 |
39 | ### Usage
40 |
41 | You can define your hooks in your service provider:
42 |
43 | ```php
44 | Filament::registerRenderHook(
45 | 'Zeus-form.before',
46 | fn (): View => view('filament.hooks.zeus.form-before'),
47 | );
48 | ```
49 |
--------------------------------------------------------------------------------
/docs/bolt-pro/_index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Bolt Pro
3 | weight: 4
4 | ---
5 |
--------------------------------------------------------------------------------
/docs/bolt-pro/advanced-tables.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Integrated with Advanced Tables
3 | weight: 6
4 | ---
5 |
6 | The Advanced Tables (formerly Filter Sets) plugin from [Kenneth Sese](https://filamentphp.com/plugins/kenneth-sese-advanced-tables), to Supercharge your tables with powerful features like user customizable views, enhanced filter tabs, reorderable columns, convenient view management, and more. Now fully integrated to create powerful reports from your dynamic forms.
7 |
8 | You will need a separate license for the Advanced Tables plugin to activate these features.
9 |
10 | ## Enable the Advanced Tables Plugin
11 |
12 | After installing Advanced Tables, the the filters will be available in forms immediately but you need to enable it in the Entries Report page:
13 |
14 | Create the file
15 | `resources/views/vendor/zeus/filament/pages/reports/entries-pro.blade.php`
16 | or copy it from the vendor folder
17 | and add the content:
18 |
19 | ```html
20 |
21 |
22 | {{ $this->table }}
23 |
24 | ```
--------------------------------------------------------------------------------
/docs/bolt-pro/assets.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Themes and Assets
3 | weight: 2
4 | ---
5 |
6 | ## Compiling assets
7 |
8 | We use [tailwind Css](https://tailwindcss.com/) and custom themes by filament, make sure you are familiar with [tailwindcss configuration](https://tailwindcss.com/docs/configuration), and how to make a custom [filament theme](https://filamentphp.com/docs/2.x/admin/appearance#building-themes).
9 |
10 | ### Custom Classes
11 |
12 | You need to add these files to your `tailwind.config.js` file in the `content` section.
13 |
14 | * frontend:
15 |
16 | ```js
17 | content: [
18 | //...
19 | './vendor/lara-zeus/bolt-pro/resources/views/themes/**/*.blade.php',
20 | ]
21 | ```
22 |
23 | * filament:
24 |
25 | ```js
26 | content: [
27 | //...
28 | './vendor/lara-zeus/bolt-pro/resources/views/filament/**/*.blade.php',
29 | ]
30 | ```
31 |
--------------------------------------------------------------------------------
/docs/bolt-pro/fields.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Available Fields
3 | weight: 3
4 | ---
5 |
6 | ## Available Fields
7 |
8 | - 🔥 Rating - Show Star Rating as field
9 | - 🔥 Matrix Grid - Multiple choice grid field as radio or checkboxes
10 | - 🔥 Slider - A range selector, set the min and max value
11 | - 🔥 Advance Date - Set the date picker to range, month, week, and multiple dates
12 | - 🔥 Alert - Show a note with customized styling
13 | - 🔥 Icon Picker - Allows your users to pick an icon
14 | - 🔥 Image Picker - Allows users to pick an image from uploaded set
15 | - 🔥 Dynamic Textbox - Add multiple text values
16 | - 🔥 Signature - Collect users signature
17 | - 🔥 Terms and conditions - Let the users agree to your terms and conditions
18 |
--------------------------------------------------------------------------------
/docs/bolt-pro/introduction.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Introduction
3 | weight: 1
4 | ---
5 |
6 | ## Zeus Bolt Pro
7 |
8 | Advanced Forms management, More Filtering, Presets, and New Fields for Bolt the form builder
9 |
10 | ## Features
11 |
12 | - New Fields Types
13 | - Advanced widgets and stats
14 | - Forms API
15 | - Custom colors and branding per form
16 | - Presets: create Forms with pre defined templates, or from existing forms
17 | - Prefilled Forms URLs
18 | - Advanced Widgets
19 | - Sharing and embedding the form
20 |
21 | ### Get Bolt Pro from [here](https://larazeus.com/bolt-pro)
22 |
23 | ## Installation
24 |
25 | To install bolt, you only need to require it in your composer by running the command:
26 |
27 | ```bash
28 | composer require lara-zeus/bolt-pro
29 | ```
30 |
31 | Make sure to clear the cache after the installation completed.
32 |
33 | And that is all :).
34 |
35 | You will get more details after you purchasing the package.
36 |
37 | ## Configuration
38 |
39 | Add these configuration keys to `zeus-bolt` config file:
40 |
41 | ```php
42 | // if you want to disable the preset button
43 | 'allow_design' => false,
44 |
45 | // to disable the theming tab
46 | 'show_presets' => false,
47 |
48 | // to disable the core presets
49 | 'show_core_presets' => false,
50 |
51 | /**
52 | * the preview for the presets is using sushi:
53 | * you can enable/disable the cache here
54 | */
55 | 'should_cache_preset' => env('BOLT_CACHE_PRESET', true),
56 | ```
57 |
--------------------------------------------------------------------------------
/docs/bolt-pro/presets.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Presets Forms
3 | weight: 4
4 | ---
5 |
6 | # Presets Forms:
7 |
8 | Create Forms with pre defined templates, build your form manually or use an existing form.
9 | Available Preset: Support Ticket, Contact Form.
10 |
11 | ## Create a new preset
12 |
13 | Use the artisan command to create new preset:
14 |
15 | `make:zeus-preset`
16 |
17 | This will prompts you to enter the preset class name without any namespace
18 | or the form ID from you existing forms.
19 |
20 | All new generated presets will be saved in the folder: `App\Zeus\Presets`
21 |
22 |
--------------------------------------------------------------------------------
/docs/bolt-pro/share-form.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Sharing & Embedding
3 | weight: 5
4 | ---
5 |
6 | # Sharing a Form:
7 |
8 | Bolt Pro will provide your users with a new tab, that let them share the form to social media and other webpages very easily.
9 |
10 | To customize the social media sharing icons or use any other widget, create the file:
11 | `resources/views/vendor/zeus/filament/social-share.blade.php`.
12 |
13 | And add any social platform you want.
14 |
15 | ## Embedding a Form
16 |
17 | The embed forms will be accessible from the route name `bolt.form.embed` and
18 | the url is; `/bolt/embed/$form->slug`
19 |
20 | To customize the layout you can create the file:
21 | `resources/views/vendor/zeus/filament/embed-layout.blade.php`
22 |
23 | The default content is:
24 |
25 | ```html
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 | @livewireStyles
43 | @filamentStyles
44 | @stack('styles')
45 |
46 |
47 |
48 |
52 |
53 |
54 |
55 |
56 | {{ $slot }}
57 |
58 |
59 | @stack('scripts')
60 | @livewireScripts
61 | @filamentScripts
62 | @livewire('notifications')
63 |
64 |
71 |
72 |
73 |
74 | ```
--------------------------------------------------------------------------------
/docs/filament-bolt-pro.md:
--------------------------------------------------------------------------------
1 | ## Zeus Bolt Pro
2 |
3 | Advanced Forms management, More Filtering, Presets, and New Fields for [Bolt the form builder](https://filamentphp.com/plugins/lara-zeus-bolt)
4 |
5 | ## Available Fields
6 |
7 | - 🔥 Rating. Show Star Rating as field
8 | - 🔥 Matrix Grid. multiple choice grid field as radio or checkboxes
9 | - 🔥 Slider. a range selector, set the min and max value
10 | - 🔥 Advance Date. set the date picker to range, month, week, and multiple dates
11 | - 🔥 Alert. show a note with customized styling
12 | - 🔥 Icon Picker. allows your users to pick an icon
13 | - 🔥 Image Picker. allows users to pick an image from uploaded set
14 | - 🔥 Dynamic Textbox. add multiple text values
15 | - 🔥 Signature. collect users signature
16 | - 🔥 terms and conditions. let the users agree to your terms and conditions
17 |
18 | ## And Even More Features
19 |
20 | * Advanced widgets and stats
21 | * Forms API
22 | * Presets: create Forms with pre defined templates
23 | * Custom colors and branding per form
24 | * Prefilled Forms URLs
25 | * Advanced Widgets
26 | * Sharing and embedding the form
27 |
28 | ## Fully Integrated with Advanced Tables.
29 |
30 | [The Advanced Tables (formerly Filter Sets) plugin](https://filamentphp.com/plugins/kenneth-sese-advanced-tables) from Kenneth Sese, to Supercharge your tables with powerful features like user customizable views, enhanced filter tabs, reorderable columns, convenient view management, and more. now, fully integrated to create powerful reports from your dynamic forms.
31 |
32 | You will need a separate license for the Advanced Tables plugin to activate these features.
33 |
34 | ## Screenshots
35 |
36 | 
37 | 
38 | 
39 | 
40 | 
41 | 
42 |
43 | ## More Details
44 |
45 | **✨ to learn more about Bolt Pro, please visit:**
46 |
47 | - [Discord](https://discord.com/channels/883083792112300104/1282748203376050309)
48 | - [Docs](https://larazeus.com/docs/bolt/v2/bolt-pro)
49 | - [Demo](https://demo.larazeus.com/admin/forms/bolt-pro)
50 |
51 |
--------------------------------------------------------------------------------
/docs/filament.md:
--------------------------------------------------------------------------------
1 | # Zeus Bolt
2 |
3 | Bolt is a form builder for your users, with so many use cases included a UI for the frontend built with filament
4 |
5 | ## Features
6 |
7 | - 🔥 Collections.
8 | - 🔥 Categories.
9 | - 🔥 Entries report and Filters.
10 | - 🔥 Custom Datasource.
11 | - 🔥 Custom Fields.
12 | - 🔥 Extensions.
13 | - 🔥 Conditional Visibility.
14 | - 🔥 Events.
15 | - 🔥 View the forms as livewire component.
16 | - 🔥 integrated with Sky.
17 | - 🔥 Frontend scaffolding, highly customizable.
18 |
19 | ## Screenshots
20 |
21 | * **UI Form Manager:** beautifully designed form builder, data collections, and Categories
22 |
23 | 
24 | 
25 | 
26 | 
27 | 
28 |
29 | * **Submission Manager:** Manage your forms entries with ease and set status, fully customizable, with reports and advanced filters.
30 |
31 | 
32 | 
33 | 
34 | 
35 |
36 | * **Frontend:** frontend scaffolding built with filament. Including pages to list all user entries for your clients
37 |
38 | 
39 | 
40 | 
41 | 
42 | 
43 |
44 | ## Bolt Pro
45 |
46 | [](https://filamentphp.com/plugins/lara-zeus-bolt-pro)
47 |
48 | ## More Details
49 |
50 | **✨ to learn more about Bolt the form builder, please visit:**
51 |
52 | - [Discord](https://discord.com/channels/883083792112300104/1282746904303894579)
53 | - [Docs](https://larazeus.com/docs/bolt)
54 | - [Github](https://github.com/lara-zeus/bolt)
55 | - [Demo](https://demo.larazeus.com)
56 |
--------------------------------------------------------------------------------
/docs/getting-started/_index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Getting Started
3 | weight: 1
4 | ---
5 |
--------------------------------------------------------------------------------
/docs/getting-started/assets.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Themes and Assets
3 | weight: 6
4 | ---
5 |
6 | ## Compiling assets
7 |
8 | We use [tailwind Css](https://tailwindcss.com/) and custom themes by filament, make sure you are familiar with [tailwindcss configuration](https://tailwindcss.com/docs/configuration), and how to make a custom [filament theme](https://filamentphp.com/docs/2.x/admin/appearance#building-themes).
9 |
10 | ### Custom Classes
11 |
12 | You need to add these files to your `tailwind.config.js` file in the `content` section.
13 |
14 | * frontend:
15 |
16 | ```js
17 | content: [
18 | //...
19 | './vendor/lara-zeus/core/resources/views/**/*.blade.php',
20 | './vendor/lara-zeus/bolt/resources/views/themes/**/*.blade.php',
21 | ]
22 | ```
23 |
24 | * filament:
25 |
26 | ```js
27 | content: [
28 | //...
29 | './vendor/lara-zeus/bolt/resources/views/filament/**/*.blade.php',
30 | './vendor/lara-zeus/accordion/resources/views/**/*.blade.php',
31 | ]
32 | ```
33 |
34 | ### Customizing the Frontend Views
35 |
36 | First, publish the config file:
37 |
38 | ```php
39 | php artisan vendor:publish --tag=zeus-config
40 | ```
41 |
42 | Then change the default layout in the file `zeus.php`:
43 |
44 | ```php
45 | 'layout' => 'components.layouts.app',
46 | // this is assuming your layout on the folder `resources/views/components/layouts/app`
47 | ```
48 | This will give you full control for the assets files and the header and the footer.
49 |
50 |
51 | If needed, you can publish the blade views for all zeus packages:
52 |
53 | ```php
54 | php artisan vendor:publish --tag=zeus-views
55 | ```
56 |
--------------------------------------------------------------------------------
/docs/getting-started/changelog.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Changelog
3 | weight: 100
4 | ---
5 |
6 | All changes to @zeus Bolt are auto updated documented on GitHub [changelog](https://github.com/lara-zeus/bolt/blob/main/CHANGELOG.md)
7 |
--------------------------------------------------------------------------------
/docs/getting-started/configuration.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Configuration
3 | weight: 5
4 | ---
5 |
6 | ## Configuration
7 |
8 | There are two different sets of configuration, for filament, and for the frontend pages
9 |
10 | ## Filament Configuration
11 |
12 | To configure the plugin Bolt, you can pass the configuration to the plugin in `adminPanelProvider`
13 |
14 | These all the available configuration, and their defaults values
15 |
16 | > **Note**\
17 | > All these configurations are optional
18 |
19 | ```php
20 | BoltPlugin::make()
21 | // the default models, by default Bolt will read from the config file 'zeus-bolt'.
22 | // but if you want to customize the models per panel, you can do it here
23 | ->models([
24 | // ...
25 | 'Category' => \App\Models\Bolt\Category::class,
26 | 'Collection' => \App\Models\Bolt\Collection::class,
27 | 'Field' => \App\Models\Bolt\Field::class,
28 | 'FieldResponse' => \App\Models\Bolt\FieldResponse::class,
29 | 'Form' => \App\Models\Bolt\Form::class,
30 | 'FormsStatus' => \App\Models\Bolt\FormsStatus::class,
31 | 'Response' => \App\Models\Bolt\Response::class,
32 | 'Section' => \App\Models\Bolt\Section::class,
33 | 'User' => \App\Models\Staff::class,
34 | ])
35 |
36 | // make the actions floating in create and edit forms
37 | ->formActionsAreSticky(true)
38 |
39 | ->hideResources([
40 | FormResource::class
41 | ])
42 |
43 | ->globallySearchableAttributes([
44 | // you can return empty array to disable it
45 | FormResource::class => ['name']
46 | ])
47 |
48 | ->navigationGroupLabel('Bolt')
49 |
50 | ->hideNavigationBadges(resource: LaraZeus\Bolt\Resources::CollectionResource)
51 | ->showNavigationBadges(resource: LaraZeus\Bolt\Resources::CollectionResource)
52 |
53 | // if you have custom extension or using thunder
54 | ->extensions([
55 | \LaraZeus\Thunder\Extensions\Thunder::class,
56 | ])
57 | ,
58 | ```
59 |
60 | ## Customize Filament Resources
61 |
62 | You can customize all Bolt resources icons and sorting by adding the following code to your `AppServiceProvider` boot method
63 |
64 | ```php
65 | FormResource::navigationSort(100);
66 | FormResource::navigationIcon('heroicon-o-home');
67 | FormResource::navigationGroup('New Name');
68 | ```
69 |
70 | ### Show or Hide Badges
71 |
72 | To show all navigation badges (default)
73 | ```
74 | ->showNavigationBadges()
75 | ```
76 |
77 | To hide all navigation badges
78 | ```
79 | ->hideNavigationBadges()
80 | ```
81 |
82 | This will hide only the CollectionResource navigation badge
83 | ```
84 | ->hideNavigationBadges(resource: LaraZeus\Bolt\Resources::CollectionResource)
85 | ```
86 |
87 | This will show only the FormResource navigation badge
88 | ```
89 | ->hideNavigationBadges()
90 | ->showNavigationBadges(resource: LaraZeus\Bolt\Resources::CollectionResource)
91 | ```
92 |
93 | available resources:
94 |
95 | - CategoryResource,
96 | - CollectionResource,
97 | - FormResource,
98 |
99 | ## Frontend Configuration
100 |
101 | Use the file `zeus-bolt.php`, to customize the frontend, like the prefix, domain, and middleware for each content type.
102 |
103 | To publish the configuration:
104 |
105 | ```bash
106 | php artisan vendor:publish --tag=zeus-bolt-config
107 | ```
108 |
109 | ### Custom User Model
110 |
111 | By default Bolt will use the default Laravel user model to get the user info:
112 |
113 | `config('auth.providers.users.model')`
114 |
115 | If you need to change this to use another model, add the following in your config file: `zeus-bolt.php`:
116 |
117 | ```php
118 | 'models' => [
119 | //...
120 | 'User' => AnotherUserModel::class,
121 | ],
122 | ```
--------------------------------------------------------------------------------
/docs/getting-started/installation.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Installation
3 | weight: 3
4 | ---
5 |
6 | ## Prerequisites
7 |
8 | Bolt is built on top of [laravel](https://laravel.com/docs/master) and uses [filament](https://filamentphp.com/docs/3.x/panels/installation) as an admin panel to manage everything.
9 |
10 | And for the frontend, it uses [Tall stack](https://tallstack.dev/).
11 |
12 | So, ensure you are familiar with these tools before diving into @zeus Bolt.
13 |
14 | > **Note**\
15 | > You can get up and running with our [starter kit Zeus](https://github.com/lara-zeus/zeus).
16 |
17 | ## Installation
18 |
19 | > **Important**\
20 | > Before starting, make sure you have the following PHP extensions enabled:
21 | `sqlite`
22 |
23 | Install @zeus Bolt by running the following commands in your Laravel project directory.
24 |
25 | ```bash
26 | composer require lara-zeus/bolt
27 | php artisan bolt:install
28 | ```
29 |
30 | The install command will publish the migrations and the necessary assets for the frontend.
31 |
32 | ## Register Bolt with Filament:
33 |
34 | To set up the plugin with filament, you need to add it to your panel provider; The default one is `adminPanelProvider`
35 |
36 | ```php
37 | ->plugins([
38 | SpatieLaravelTranslatablePlugin::make()->defaultLocales([config('app.locale')]),
39 | BoltPlugin::make()
40 | ])
41 | ```
42 |
43 | ## Add Bolt Trait to User Model
44 |
45 | add this to your user model:
46 |
47 | `use \LaraZeus\Bolt\Models\Concerns\BelongToBolt;`
48 |
49 | This will allow you to get the user name by another attribute like `full_name`
50 |
51 | ## Usage
52 |
53 | To access the forms, visit the URL `/admin` , and `/bolt`.
54 |
55 | ## Deploying to Production
56 |
57 | to improve performance in the production environment, make sure to run these commands with your deployment workflow:
58 |
59 | ```bash
60 | php artisan icons:cache
61 | ```
62 |
63 | To learn more about performance in the production, check out [filament docs](https://filamentphp.com/docs/3.x/panels/installation#improving-filament-panel-performance).
64 |
--------------------------------------------------------------------------------
/docs/getting-started/loading.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Loading indicator
3 | weight: 7
4 | ---
5 |
6 | ## Frontend loading indicator
7 |
8 | By default there is a loading indicator on the top left next to the breadcrumbs, but you can customize it as you want.
9 |
10 | ### the loading blade
11 |
12 | Create the file `resources/views/vendor/zeus/themes/zeus/bolt/loading.blade.php`
13 | with the default content:
14 |
15 | ```html
16 |
17 | @teleport('.bolt-loading')
18 |
19 | @svg('heroicon-o-arrow-path', 'text-primary-600 w-8 h-8 animate-spin')
20 |
21 | @endteleport
22 |
23 | ```
24 |
25 | In your app layout add the following where you want the loader to show
26 |
27 | ```html
28 |
29 | ```
30 |
--------------------------------------------------------------------------------
/docs/getting-started/upgrade.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Upgrading
3 | weight: 90
4 | ---
5 |
6 | ## upgrade to v3.0.25
7 |
8 | In v3.0.25, I added a new trait for getting the user name
9 |
10 | So you have to add this to your User model:
11 |
12 | `use \LaraZeus\Bolt\Models\Concerns\BelongToBolt;`
13 |
14 | ## upgrade to v2.1
15 |
16 | In v2.1, I refactored the configuration to separate the frontend configuration from filament-related ones.
17 | This causes an issue when having multiple panels.
18 |
19 | 1. First, publish the config file by running the command:
20 |
21 | ```bash
22 | php artisan vendor:publish --tag="zeus-bolt-config" --force
23 | ```
24 |
25 | 2. Move your configuration from your panel provider to the `zeus-bolt` config file.
26 |
27 | So these are the deprecated configuration methods:
28 |
29 |
30 | ```php
31 |
32 | ->boltPrefix()
33 | ->boltMiddleware()
34 | ->defaultMailable()
35 | ->uploadDisk()
36 | ->uploadDirectory()
37 | ->domain()
38 |
39 | ```
40 |
41 | ## upgrade from 2 to 3
42 |
43 | To upgrade @zeus Bolt to v2 please check this `Core` [upgrade guide](/docs/core/v3/upgrade)
44 |
--------------------------------------------------------------------------------
/docs/introduction.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Introduction
3 | weight: 1
4 | ---
5 |
6 | ## Introduction
7 | @zeus bolt is a form builder for your users, with so many use cases
8 | included a UI for the frontend built with filament
9 |
10 | For example, you can use it as a job board, appointments, ticketing, survey, and even [more use cases](/docs/bolt/v2/usage/use-cases).
11 |
12 | **[Demo](https://demo.larazeus.com/admin/forms) · [Github](https://github.com/lara-zeus/bolt) · [Discord](https://discord.com/channels/883083792112300104/1282746904303894579)**
13 |
14 | ## Features
15 | - 🔥 zero configuration, just composer it. but highly customizable
16 | - 🔥 Built with [TALL stack](https://tallstack.dev/)
17 | - 🔥 Using [filament](https://filamentadmin.com) as an admin panel and form builder
18 | - 🔥 Frontend scaffolding, highly customizable
19 | - 🔥 Sections to Group your fields with the Option to display them as wizard or tabs
20 | - 🔥 Categories to organize your forms in the frontend
21 | - 🔥 Control the starting and ending dates for submissions
22 | - 🔥 Email notifications per form
23 | - 🔥 Confirmation message after submission per form
24 | - 🔥 Option for requiring login per form
25 | - 🔥 Limit submissions with one entry for a user (if auth is required only)
26 | - 🔥 Conditional Visibility for fields depending on other field's values
27 | - 🔥 Extensions control the submitting and store them or perform actions
28 | - 🔥 Embed the form in [sky](https://github.com/lara-zeus/sky) posts and pages, or as a livewire component
29 | - 🔥 Add any field from filament plugins
30 | - 🔥 Create your own field
31 | - 🔥 Collections for datasets
32 | - 🔥 Create Custom Collections from eloquent model
33 | - 🔥 Validation rules for text input
34 | - 🔥 Multi lang ready
35 | - 🔥 Show responses for each form
36 | - 🔥 Search in all responses filtering on the dynamic fields
37 | - 🔥 Set status for each response
38 | - 🔥 Export or print form with its fields
39 | - 🔥 Replicate forms with their sections and fields
40 | - 🔥 Form reports, statistics, and widgets
41 | - 🔥 Multiple events ready to listen to
42 | - Poll Module: (custom layout to show the form as a poll and display the result as a chart) (soon)
43 | - Exam Module: (set correct answer, the mark for each question, autocorrection for all responses, send the mark to the user, and display the result) (soon)
44 | - Product Module: (show an order form with products and pricing) (soon)
45 |
46 | ## Bolt Pro
47 |
48 | [](https://larazeus.com/bolt-pro)
49 |
50 | ## Support
51 |
52 | Available support channels:
53 |
54 | * Join our channel on [Discord](https://discord.com/channels/883083792112300104/1282746904303894579)
55 | * open an issue on [GitHub](https://github.com/lara-zeus/bolt/issues)
56 | * Email us using the [contact center](https://larazeus.com/contact-us)
57 |
--------------------------------------------------------------------------------
/docs/usage/_index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Architecture
3 | weight: 2
4 | ---
5 |
--------------------------------------------------------------------------------
/docs/usage/embed.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Embed the Form
3 | weight: 3
4 | ---
5 |
6 | ## Embed the Form
7 |
8 | @zeus Bolt forms are simply a livewire component, you can embed it in any page in your frontend or filament pages.
9 |
10 | To embed the Form in any blade page, simply use:
11 |
12 | ```blade
13 |
14 | ```
15 |
16 | If you have an extension linked to your form, you can pass in the `extensionSlug`
17 |
18 | ```blade
19 |
20 | ```
21 |
22 | and [this](https://demo.larazeus.com/embed) is how the form looks in an empty page.
23 |
24 | ## Embed in the Sky
25 |
26 | If you are using our package @zeus [Sky](https://larazeus.com/sky), you can embed the forms by using the code:
27 | ```html
28 | formSlug
29 | ```
30 |
31 | ## Sharing on the Web
32 | With Bolt Pro, and for your users convenience, we added a new tab in the form to make it easy to copy the code.
33 |
34 | Read more about it in [Bolt Pro share-form](../bolt-pro/share-form)
35 |
--------------------------------------------------------------------------------
/docs/usage/overview.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Overview
3 | weight: 2
4 | ---
5 |
6 | ## Overview
7 | Here is the structure of the database tables; it will give you an idea of how Bolt works:
8 |
9 | 
10 |
11 | ## The concept
12 |
13 | ### Form
14 | The main component of all of this. Including all descriptive texts and the form options.
15 |
16 | ### Sections
17 | To group the fields, it has some options like columns number.
18 | Also, an option to display sections as pages or wizards, or tabs.
19 |
20 | ### Fields
21 | Fields are fields, most of the common types are available, and you can create custom ones too.
22 |
23 | ### Categories
24 | It's a way to organize and display the forms in the front end.
25 | Any form not linked to a category won't be listed in the forms list at the front end.
26 |
27 | ### Collections
28 | Collections are datasets used for lists like checkboxes and select menus.
29 |
30 | ### Responses
31 | Every submission has a response record per user.
32 | You can view the responses per form in three ways:
33 | - list: list the response only as cards
34 | - browse: how the response with the fields one per page
35 | - report: table view for all entries and their fields
36 |
37 | ### Responses Fields
38 | Fields are related to each response and each field of the form. And they contain the user input.
39 |
40 | This structure helps to create any reports you want with ease.
41 |
--------------------------------------------------------------------------------
/phpstan.neon:
--------------------------------------------------------------------------------
1 | parameters:
2 | level: 6
3 | paths:
4 | - src
5 | - database
6 |
7 | checkOctaneCompatibility: true
8 | checkModelProperties: true
9 |
10 | ignoreErrors:
11 | -
12 | identifier: trait.unused
13 | -
14 | identifier: missingType.generics
15 | -
16 | identifier: argument.templateType
17 | -
18 | identifier: missingType.iterableValue
19 | -
20 | identifier: argument.type
21 | -
22 | identifier: property.defaultValue
23 | -
24 | identifier: return.type
25 | -
26 | identifier: class.notFound
27 | -
28 | identifier: notIdentical.alwaysTrue
29 |
--------------------------------------------------------------------------------
/phpunit.xml.dist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | tests
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | ./src
15 |
16 |
17 |
--------------------------------------------------------------------------------
/pint.json:
--------------------------------------------------------------------------------
1 | {
2 | "preset": "laravel",
3 | "rules": {
4 | "blank_line_before_statement": true,
5 | "concat_space": {
6 | "spacing": "one"
7 | },
8 | "method_argument_space": true,
9 | "single_trait_insert_per_statement": true,
10 | "types_spaces": {
11 | "space": "single"
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/resources/views/emails/form-submission.blade.php:
--------------------------------------------------------------------------------
1 |
2 | # {{ __('New submission on form') }}: {{ $form->name }}
3 |
4 |
5 | {{ __('view the entry') }}
6 |
7 |
8 | {{ __('Thanks') }},
9 | {{ config('app.name') }}
10 |
--------------------------------------------------------------------------------
/resources/views/errors/date-not-available.blade.php:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{ __('Date Not Available') }}
4 |
5 |
6 |
7 |
8 |
9 |
10 | @svg('heroicon-o-exclamation-triangle','w-5 h-5 text-primary-600')
11 |
12 | {{ __('Date Not Available') }}
13 |
14 |
15 |
16 | {{ __('the form is not available for submission') }}
17 | {{ $zeusForm->name ?? '' }} .
18 |
19 |
20 | {{ __('Start date') }} :
21 | {{ $zeusForm->start_date->format(\Filament\Infolists\Infolist::$defaultDateTimeDisplayFormat) }} ,
22 | {{ __('End date') }} :
23 | {{ $zeusForm->end_date->format(\Filament\Infolists\Infolist::$defaultDateTimeDisplayFormat) }}
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/resources/views/errors/login-required.blade.php:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{ __('Login Required') }}
4 |
5 |
6 |
7 |
8 |
9 |
10 | @svg('heroicon-o-exclamation-triangle','w-5 h-5 text-primary-600')
11 |
12 | {{ __('Login Required') }}
13 |
14 |
15 |
16 | {{ __('Login is required to access the form') }}
17 | {{ $zeusForm->name ?? '' }} .
18 |
19 |
20 | {{ __('Login') }}
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/resources/views/errors/one-entry-per-user.blade.php:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{ __('one entry') }}
4 |
5 |
6 |
7 |
8 |
9 |
10 | @svg('heroicon-o-exclamation-triangle','w-5 h-5 text-primary-600')
11 |
12 | {{ __('one entry per user') }}
13 |
14 |
15 |
16 | {{ __('the form') }}
17 | {{ $zeusForm->name ?? '' }} .
18 | {{ __('allow only one entry per user') }}
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/resources/views/filament/components/color-picker.blade.php:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
10 |
{{ __('Color') }}
11 |
12 |
13 | @php
14 | $colors = collect(\Filament\Support\Colors\Color::all())->forget(['slate','zinc','neutral','stone'])->keys()->toArray();
15 | @endphp
16 | @foreach($colors as $color)
17 | @php
18 | $setColor = \Illuminate\Support\Arr::toCssStyles([
19 | \Filament\Support\get_color_css_variables($color, shades: [500]),
20 | ]);
21 | @endphp
22 |
30 |
31 | @endforeach
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/resources/views/filament/fields/file-upload.blade.php:
--------------------------------------------------------------------------------
1 |
2 | @if(filled($responseValue))
3 |
4 | @foreach($responseValue as $file)
5 |
11 | {{ __('view file') .': '. $loop->iteration }}
12 |
13 | @endforeach
14 |
15 | @else
16 |
{{ __('no file uploaded') }}
17 | @endif
18 |
19 |
--------------------------------------------------------------------------------
/resources/views/filament/fields/types.blade.php:
--------------------------------------------------------------------------------
1 |
2 | @svg($field['icon'],'text-primary-500 w-5 h-5')
3 |
4 |
5 | {{ $field['title'] }}
6 | {{--{{ $field['description'] }} --}}
7 |
8 |
12 | @svg('heroicon-o-information-circle','mx-2 w-4 h-4 text-gray-400')
13 |
14 |
15 |
--------------------------------------------------------------------------------
/resources/views/filament/pages/reports/entries.blade.php:
--------------------------------------------------------------------------------
1 |
2 | {{ $this->table }}
3 |
4 |
--------------------------------------------------------------------------------
/resources/views/filament/resources/form-resource/widgets/edit-collection-warning.blade.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{ __('any changes in the values of these items will affect the responses for the forms in') }}
5 |
6 | {{ \LaraZeus\Bolt\Models\Field::whereJsonContains('options->dataSource', "$record->id")->count() }}
7 |
8 | {{ __('field') }}
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/resources/views/filament/resources/response-resource/components/view-responses.blade.php:
--------------------------------------------------------------------------------
1 |
5 |
6 | @include('zeus::filament.resources.response-resource.pages.show-entry')
7 |
8 |
--------------------------------------------------------------------------------
/resources/views/filament/resources/response-resource/pages/browse-responses.blade.php:
--------------------------------------------------------------------------------
1 |
2 | {{ $this->table }}
3 |
4 |
--------------------------------------------------------------------------------
/resources/views/themes/zeus/bolt/list-entries.blade.php:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{ __('browse your Entries') }}
4 |
5 |
6 |
7 |
8 | {{ __('browse your Entries') }}
9 |
10 |
11 |
12 |
13 | {{ $this->table }}
14 |
15 |
16 |
--------------------------------------------------------------------------------
/resources/views/themes/zeus/bolt/list-forms.blade.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{ __('List All Forms') }}
5 |
6 |
7 |
8 |
9 | {{ __('Forms') }}
10 |
11 |
12 |
13 | {{ \LaraZeus\Bolt\Facades\Bolt::renderHookBlade('zeus-forms.before') }}
14 |
15 |
40 |
41 | {{ \LaraZeus\Bolt\Facades\Bolt::renderHookBlade('zeus-forms.before') }}
42 |
43 |
44 |
--------------------------------------------------------------------------------
/resources/views/themes/zeus/bolt/loading.blade.php:
--------------------------------------------------------------------------------
1 |
2 |
3 | @teleport('.bolt-loading')
4 |
5 | @svg('heroicon-o-arrow-path', 'text-primary-600 w-6 h-6 animate-spin')
6 |
7 | @endteleport
8 |
9 |
--------------------------------------------------------------------------------
/resources/views/themes/zeus/bolt/submitted.blade.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | @if(!empty($zeusForm->options['confirmation-message']))
5 |
6 | {!! $zeusForm->options['confirmation-message'] !!}
7 |
8 | @else
9 |
10 | {{ __('the form') }}
11 | {{ $zeusForm->name ?? '' }}
12 | {{ __('submitted successfully') }}.
13 |
14 | @endif
15 |
16 | {!! \LaraZeus\Bolt\Facades\Extensions::init($zeusForm, 'SubmittedRender', [
17 | 'extensionData' => $extensionData['extInfo']['itemId'] ?? 0,
18 | 'response' => $extensionData['response'],
19 | ]) !!}
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/routes/web.php:
--------------------------------------------------------------------------------
1 | prefix(config('zeus-bolt.prefix'))
11 | ->name('bolt.')
12 | ->middleware(config('zeus-bolt.middleware'))
13 | ->group(function () {
14 | Route::get('/', ListForms::class)
15 | ->name('forms.list');
16 |
17 | Route::get('/entries', ListEntries::class)->name('entries.list')
18 | ->middleware('auth');
19 |
20 | Route::get('/entry/{responseID}', ShowEntry::class)
21 | ->name('entry.show')
22 | ->middleware('auth');
23 |
24 | if (class_exists(\LaraZeus\BoltPro\BoltProServiceProvider::class)) {
25 | Route::get('embed/{slug}', \LaraZeus\BoltPro\Livewire\EmbedForm::class)
26 | ->name('form.embed');
27 | }
28 |
29 | Route::get('{slug}/{extensionSlug?}', FillForms::class)
30 | ->name('form.show');
31 | });
32 |
--------------------------------------------------------------------------------
/src/BoltPlugin.php:
--------------------------------------------------------------------------------
1 | ['name', 'slug'],
36 | CollectionResource::class => ['name', 'values'],
37 | FormResource::class => ['name', 'slug'],
38 | ];
39 |
40 | public function getId(): string
41 | {
42 | return 'zeus-bolt';
43 | }
44 |
45 | public function register(Panel $panel): void
46 | {
47 | $panel
48 | ->resources([
49 | CollectionResource::class,
50 | FormResource::class,
51 | CategoryResource::class,
52 | ]);
53 | }
54 |
55 | public static function make(): static
56 | {
57 | return new self;
58 | }
59 |
60 | public static function get(): static
61 | {
62 | // @phpstan-ignore-next-line
63 | return filament('zeus-bolt');
64 | }
65 |
66 | public function boot(Panel $panel): void
67 | {
68 | //
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/src/BoltServiceProvider.php:
--------------------------------------------------------------------------------
1 | name(static::$name)
25 | ->hasViews('zeus')
26 | ->hasMigrations($this->getMigrations())
27 | ->hasTranslations()
28 | ->hasConfigFile()
29 | ->hasCommands($this->getCommands())
30 | ->hasRoute('web');
31 | }
32 |
33 | public function packageBooted(): void
34 | {
35 | CoreServiceProvider::setThemePath('bolt');
36 |
37 | Livewire::component('bolt.fill-form', FillForms::class);
38 | Livewire::component('bolt.list-forms', ListForms::class);
39 | Livewire::component('bolt.list-entries', ListEntries::class);
40 | }
41 |
42 | /**
43 | * @return array
44 | */
45 | protected function getCommands(): array
46 | {
47 | return [
48 | PublishCommand::class,
49 | ZeusFieldCommand::class,
50 | ZeusDatasourceCommand::class,
51 | InstallCommand::class,
52 | ];
53 | }
54 |
55 | /**
56 | * @return array
57 | */
58 | protected function getMigrations(): array
59 | {
60 | return [
61 | 'create_categories_table',
62 | 'create_collections_table',
63 | 'create_forms_table',
64 | 'create_sections_table',
65 | 'create_fields_table',
66 | 'create_responses_table',
67 | 'create_field_responses_table',
68 | 'add_extensions_to_forms',
69 | 'add_extension_item_responses',
70 | 'alter_tables_constraints',
71 | 'add_compact_to_section',
72 | 'add_options_to_section',
73 | 'add_grade_to_response',
74 | 'add_grade_to_field_response',
75 | 'add_borderless_to_section',
76 | ];
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/src/Commands/InstallCommand.php:
--------------------------------------------------------------------------------
1 | info('publishing migrations...');
16 | $this->call('vendor:publish', ['--tag' => 'zeus-bolt-migrations']);
17 | $this->call('vendor:publish', ['--tag' => 'zeus-bolt-config']);
18 |
19 | $this->info('publishing assets...');
20 | $this->call('vendor:publish', ['--tag' => 'zeus-assets']);
21 |
22 | if ($this->confirm('Do you want to run the migration now?', true)) {
23 | $this->info('running migrations...');
24 | $this->call('migrate');
25 | }
26 |
27 | $this->output->success('Zeus Bolt has been Installed successfully, consider ⭐️ the package in filament site :)');
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/Commands/PublishCommand.php:
--------------------------------------------------------------------------------
1 | callSilent('vendor:publish', ['--tag' => 'zeus-bolt-migrations', '--force' => $this->option('force')]);
29 | $this->callSilent('vendor:publish', ['--tag' => 'zeus-bolt-config', '--force' => $this->option('force')]);
30 |
31 | // publish Zeus files
32 | $this->callSilent('vendor:publish', ['--tag' => 'zeus-config', '--force' => $this->option('force')]);
33 | $this->callSilent('vendor:publish', ['--tag' => 'zeus-views', '--force' => $this->option('force')]);
34 | $this->callSilent('vendor:publish', ['--tag' => 'zeus-assets', '--force' => $this->option('force')]);
35 | $this->callSilent('vendor:publish', ['--tag' => 'zeus-lang', '--force' => $this->option('force')]);
36 |
37 | $this->callSilent('vendor:publish', ['--tag' => 'filament-icon-picker-config', '--force' => $this->option('force')]);
38 |
39 | $this->output->success('Zeus and Bolt has been Published successfully');
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/Commands/ZeusDatasourceCommand.php:
--------------------------------------------------------------------------------
1 | argument('name');
32 |
33 | $path = config('zeus-bolt.collectors.dataSources.path');
34 | $namespace = str_replace('\\\\', '\\', trim(config('zeus-bolt.collectors.dataSources.namespace'), '\\'));
35 |
36 | $this->copyStubToApp('ZeusDataSources', "{$path}/{$filamentPluginFullNamespace}.php", [
37 | 'namespace' => $namespace,
38 | 'class' => $filamentPluginFullNamespace,
39 | ]);
40 |
41 | $this->info('zeus datasource created successfully!');
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/Commands/ZeusFieldCommand.php:
--------------------------------------------------------------------------------
1 | argument('plugin');
32 | $fieldClassName = str($filamentPluginFullNamespace)->explode('\\')->last();
33 |
34 | $path = config('zeus-bolt.collectors.fields.path');
35 | $namespace = str_replace('\\\\', '\\', trim(config('zeus-bolt.collectors.fields.namespace'), '\\'));
36 |
37 | $this->copyStubToApp('ZeusField', "{$path}/{$fieldClassName}.php", [
38 | 'namespace' => $namespace,
39 | 'plugin' => $filamentPluginFullNamespace,
40 | 'class' => $fieldClassName,
41 | ]);
42 |
43 | $this->info('zeus field created successfully!');
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/Concerns/CanManipulateFiles.php:
--------------------------------------------------------------------------------
1 | fileExists($stubPath = base_path("stubs/zeus-bolt/{$stub}.stub"))) {
16 | $stubPath = $this->getDefaultStubPath() . "/{$stub}.stub";
17 | }
18 |
19 | $stub = Str::of($filesystem->get($stubPath));
20 |
21 | foreach ($replacements as $key => $replacement) {
22 | $stub = $stub->replace("{{ {$key} }}", $replacement);
23 | }
24 |
25 | $stub = (string) $stub;
26 |
27 | $this->writeFile($targetPath, $stub);
28 | }
29 |
30 | protected function fileExists(string $path): bool
31 | {
32 | $filesystem = app(Filesystem::class);
33 |
34 | return $filesystem->exists($path);
35 | }
36 |
37 | protected function writeFile(string $path, string $contents): void
38 | {
39 | $filesystem = app(Filesystem::class);
40 |
41 | $filesystem->ensureDirectoryExists(
42 | (string) Str::of($path)
43 | ->beforeLast('/'),
44 | );
45 |
46 | $filesystem->put($path, $contents);
47 | }
48 |
49 | protected function getDefaultStubPath(): string
50 | {
51 | $reflectionClass = new ReflectionClass($this);
52 |
53 | return (string) Str::of($reflectionClass->getFileName())
54 | ->beforeLast('Commands')
55 | ->append('../stubs');
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/Concerns/HasActive.php:
--------------------------------------------------------------------------------
1 | is_active === 0)
10 | ? '' . __('Inactive') . ' '
11 | : '' . __('Active') . ' ';
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/Concerns/HasHiddenOptions.php:
--------------------------------------------------------------------------------
1 | default(false),
13 | Hidden::make('options.visibility.fieldID'),
14 | Hidden::make('options.visibility.values'),
15 | ];
16 | }
17 |
18 | public static function hiddenRequired(): array
19 | {
20 | return [
21 | Hidden::make('options.is_required')->default(false),
22 | ];
23 | }
24 |
25 | public static function hiddenHintOptions(): array
26 | {
27 | return [
28 | Hidden::make('options.hint.text'),
29 | Hidden::make('options.hint.icon'),
30 | Hidden::make('options.hint.color'),
31 | Hidden::make('options.hint.icon-tooltip'),
32 | ];
33 | }
34 |
35 | public static function hiddenColumnSpanFull(): array
36 | {
37 | return [
38 | Hidden::make('options.column_span_full')->default(false),
39 | ];
40 | }
41 |
42 | public static function hiddenHiddenLabel(): array
43 | {
44 | return [
45 | Hidden::make('options.hidden_label')->default(false),
46 | ];
47 | }
48 |
49 | public static function hiddenDataSource(): array
50 | {
51 | return [
52 | Hidden::make('options.dataSource'),
53 | ];
54 | }
55 |
56 | public static function hiddenHtmlID(): array
57 | {
58 | return [
59 | Hidden::make('options.htmlId')->default(str()->random(6)),
60 | ];
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/src/Concerns/HasUpdates.php:
--------------------------------------------------------------------------------
1 | ' . Carbon::parse($this->updated_at)->format(\Filament\Infolists\Infolist::$defaultDateTimeDisplayFormat) . '';
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/Configuration.php:
--------------------------------------------------------------------------------
1 | null,
9 | 'section' => null,
10 | 'field' => null,
11 | ];
12 |
13 | /**
14 | * available extensions, leave it null to disable the extensions tab from the forms
15 | */
16 | protected ?array $extensions = null;
17 |
18 | protected bool $formActionsAreSticky = false;
19 |
20 | public function customSchema(array $schema): static
21 | {
22 | $this->customSchema = $schema;
23 |
24 | return $this;
25 | }
26 |
27 | public function getCustomSchema(): array
28 | {
29 | return $this->customSchema;
30 | }
31 |
32 | public static function getSchema(string $type): ?string
33 | {
34 | return (new static)::get()->getCustomSchema()[$type];
35 | }
36 |
37 | public function formActionsAreSticky(bool $condition = false): static
38 | {
39 | $this->formActionsAreSticky = $condition;
40 |
41 | return $this;
42 | }
43 |
44 | public function isFormActionsAreSticky(): bool
45 | {
46 | return $this->evaluate($this->formActionsAreSticky);
47 | }
48 |
49 | public function extensions(?array $extensions): static
50 | {
51 | $this->extensions = $extensions;
52 |
53 | return $this;
54 | }
55 |
56 | public function getExtensions(): ?array
57 | {
58 | return $this->extensions;
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/Contracts/CustomFormSchema.php:
--------------------------------------------------------------------------------
1 | render()
29 | *
30 | * @param Form $form Bolt form
31 | * @param array $data extra data
32 | */
33 | public function render(Form $form, array $data): ?string;
34 |
35 | /*
36 | * return an array of filament components to add them to the form
37 | *
38 | * @param Form $form Bolt form
39 | */
40 | public function formComponents(Form $form): ?array;
41 |
42 | /*
43 | * will triggered before saving the form, if you want to perform some validation
44 | *
45 | * you can throw an exception or return true
46 | */
47 | public function preStore(Form $form, array $data): bool;
48 |
49 | /**
50 | * the store logic for the app, insert ticket or any DB ONLY calls, don't send here anything,
51 | * and you must return the saved app, if you want to depend on it in the postStore
52 | *
53 | * @param Form $form Bolt form
54 | * @param array $data extra data
55 | *
56 | * @throws \Exception
57 | */
58 | public function store(Form $form, array $data): ?array;
59 |
60 | /**
61 | * this typically used for sending only, it will execute after the DB::transaction
62 | *
63 | * @param Form $form Bolt form
64 | */
65 | public function postStore(Form $form, array $data): void;
66 |
67 | /**
68 | * this will show any info after saving the form, like ticket num or more buttons and links
69 | * also it's better to use blade file, view()->render()
70 | *
71 | * @param Form $form Bolt form
72 | */
73 | public function SubmittedRender(Form $form, array $data): ?string;
74 |
75 | /*
76 | * list all items connected to a form
77 | */
78 | public function getItems(Form $form): array;
79 |
80 | /*
81 | * return the url to the form, when clicking on `open`. append any parameters you need to your Extension
82 | */
83 | public function getUrl(Form $form, array $extension): string;
84 |
85 | /*
86 | * check if its allowed to delete the form
87 | */
88 | public function canDelete(Form $form, array $extension): bool;
89 |
90 | /*
91 | * check if its allowed to delete the response
92 | */
93 | public function canDeleteResponse(Form $form, array $extension): bool;
94 | }
95 |
--------------------------------------------------------------------------------
/src/Contracts/Fields.php:
--------------------------------------------------------------------------------
1 | getModel())->query();
22 | }
23 |
24 | public function toArray(): array
25 | {
26 | return [
27 | 'getValuesUsing' => $this->getValuesUsing(),
28 | 'getKeysUsing' => $this->getKeysUsing(),
29 | 'getModel' => $this->getModel(),
30 | 'title' => $this->title(),
31 | 'sort' => $this->getSort(),
32 | 'class' => '\\' . get_called_class(),
33 | ];
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/Events/FormMounted.php:
--------------------------------------------------------------------------------
1 | form = $form;
23 | }
24 |
25 | /**
26 | * Get the channels the event should broadcast on.
27 | */
28 | public function broadcastOn(): Channel | PrivateChannel | array
29 | {
30 | return new PrivateChannel('form-mounted');
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/Events/FormSent.php:
--------------------------------------------------------------------------------
1 | response = $response;
23 | }
24 |
25 | /**
26 | * Get the channels the event should broadcast on.
27 | */
28 | public function broadcastOn(): Channel | PrivateChannel | array
29 | {
30 | return new PrivateChannel('form-sent');
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/Facades/Collectors.php:
--------------------------------------------------------------------------------
1 | disabled) {
30 | $allClasses[str($class)->explode('\\')->last()] = $getClass->toArray();
31 | }
32 | }
33 |
34 | return $allClasses;
35 | }
36 |
37 | public static function loadClasses(string $path, string $namespace): array
38 | {
39 | $classes = [];
40 | $path = array_unique(Arr::wrap($path));
41 |
42 | foreach ((new Finder)->in($path)->files() as $className) {
43 | $classes[] = $namespace . $className->getFilenameWithoutExtension();
44 | }
45 |
46 | return $classes;
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/Facades/Extensions.php:
--------------------------------------------------------------------------------
1 | extensions !== null) {
13 | if (class_exists($form->extensions)) {
14 | return (new $form->extensions)->{$hook}($form, $data, $action);
15 | }
16 | }
17 |
18 | return null;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/Fields/Classes/CheckboxList.php:
--------------------------------------------------------------------------------
1 | accordions([
40 | Accordion::make('general-options')
41 | ->label(__('General Options'))
42 | ->icon('tabler-settings')
43 | ->schema([
44 | self::required(),
45 | self::columnSpanFull(),
46 | self::hiddenLabel(),
47 | self::htmlID(),
48 | ]),
49 | self::hintOptions(),
50 | self::visibility($sections),
51 | // @phpstan-ignore-next-line
52 | ...Bolt::hasPro() ? \LaraZeus\BoltPro\Facades\GradeOptions::schema($field) : [],
53 | Bolt::getCustomSchema('field', resolve(static::class)) ?? [],
54 | ]),
55 | ];
56 | }
57 |
58 | public static function getOptionsHidden(): array
59 | {
60 | return [
61 | // @phpstan-ignore-next-line
62 | Bolt::hasPro() ? \LaraZeus\BoltPro\Facades\GradeOptions::hidden() : [],
63 | ...Bolt::getHiddenCustomSchema('field', resolve(static::class)) ?? [],
64 | self::hiddenDataSource(),
65 | self::hiddenVisibility(),
66 | self::hiddenHtmlID(),
67 | self::hiddenHintOptions(),
68 | self::hiddenRequired(),
69 | self::hiddenColumnSpanFull(),
70 | self::hiddenHiddenLabel(),
71 | ];
72 | }
73 |
74 | public function getResponse(Field $field, FieldResponse $resp): string
75 | {
76 | return $this->getCollectionsValuesForResponse($field, $resp);
77 | }
78 |
79 | // @phpstan-ignore-next-line
80 | public function appendFilamentComponentsOptions($component, $zeusField, bool $hasVisibility = false)
81 | {
82 | parent::appendFilamentComponentsOptions($component, $zeusField, $hasVisibility);
83 |
84 | $options = FieldsContract::getFieldCollectionItemsList($zeusField);
85 |
86 | $component = $component->options($options);
87 |
88 | if (request()->filled($zeusField->options['htmlId'])) {
89 | $component = $component->default(request($zeusField->options['htmlId']));
90 |
91 | // todo set default items for datasources
92 | } elseif ($selected = $options->where('itemIsDefault', true)->pluck('itemKey')->isNotEmpty()) {
93 | $component = $component->default($selected);
94 | }
95 |
96 | return $component->live();
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/src/Fields/Classes/ColorPicker.php:
--------------------------------------------------------------------------------
1 | accordions([
38 | Accordion::make('general-options')
39 | ->label(__('General Options'))
40 | ->icon('tabler-settings')
41 | ->schema([
42 | \Filament\Forms\Components\Select::make('options.colorType')
43 | ->label(__('Color Type'))
44 | ->options([
45 | 'hsl' => 'hsl',
46 | 'rgb' => 'rgb',
47 | 'rgba' => 'rgba',
48 | ]),
49 | self::required(),
50 | self::columnSpanFull(),
51 | self::hiddenLabel(),
52 | self::htmlID(),
53 | ]),
54 | self::hintOptions(),
55 | self::visibility($sections),
56 | Bolt::getCustomSchema('field', resolve(static::class)) ?? [],
57 | ]),
58 | ];
59 | }
60 |
61 | public static function getOptionsHidden(): array
62 | {
63 | return [
64 | ...Bolt::getHiddenCustomSchema('field', resolve(static::class)) ?? [],
65 | Hidden::make('options.colorType'),
66 | self::hiddenHtmlID(),
67 | self::hiddenHintOptions(),
68 | self::hiddenRequired(),
69 | self::hiddenColumnSpanFull(),
70 | self::hiddenHiddenLabel(),
71 | self::hiddenVisibility(),
72 | ];
73 | }
74 |
75 | // @phpstan-ignore-next-line
76 | public function appendFilamentComponentsOptions($component, $zeusField, bool $hasVisibility = false)
77 | {
78 | parent::appendFilamentComponentsOptions($component, $zeusField, $hasVisibility);
79 |
80 | if (! empty($zeusField['options']['colorType'])) {
81 | call_user_func([$component, $zeusField['options']['colorType']]);
82 | }
83 |
84 | return $component;
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/src/Fields/Classes/DatePicker.php:
--------------------------------------------------------------------------------
1 | accordions([
36 | Accordion::make('general-options')
37 | ->label(__('General Options'))
38 | ->icon('tabler-settings')
39 | ->schema([
40 | self::required(),
41 | self::columnSpanFull(),
42 | self::hiddenLabel(),
43 | self::htmlID(),
44 | ]),
45 | self::hintOptions(),
46 | self::visibility($sections),
47 | // @phpstan-ignore-next-line
48 | ...Bolt::hasPro() ? \LaraZeus\BoltPro\Facades\GradeOptions::schema($field) : [],
49 | Bolt::getCustomSchema('field', resolve(static::class)) ?? [],
50 | ]),
51 | ];
52 | }
53 |
54 | public static function getOptionsHidden(): array
55 | {
56 | return [
57 | // @phpstan-ignore-next-line
58 | Bolt::hasPro() ? \LaraZeus\BoltPro\Facades\GradeOptions::hidden() : [],
59 | ...Bolt::getHiddenCustomSchema('field', resolve(static::class)) ?? [],
60 | self::hiddenHtmlID(),
61 | self::hiddenHintOptions(),
62 | self::hiddenRequired(),
63 | self::hiddenColumnSpanFull(),
64 | self::hiddenHiddenLabel(),
65 | self::hiddenVisibility(),
66 | ];
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/src/Fields/Classes/DateTimePicker.php:
--------------------------------------------------------------------------------
1 | accordions([
36 | Accordion::make('general-options')
37 | ->label(__('General Options'))
38 | ->icon('tabler-settings')
39 | ->schema([
40 | self::required(),
41 | self::columnSpanFull(),
42 | self::hiddenLabel(),
43 | self::htmlID(),
44 | ]),
45 | self::hintOptions(),
46 | self::visibility($sections),
47 | // @phpstan-ignore-next-line
48 | ...Bolt::hasPro() ? \LaraZeus\BoltPro\Facades\GradeOptions::schema($field) : [],
49 | Bolt::getCustomSchema('field', resolve(static::class)) ?? [],
50 | ]),
51 | ];
52 | }
53 |
54 | public static function getOptionsHidden(): array
55 | {
56 | return [
57 | // @phpstan-ignore-next-line
58 | Bolt::hasPro() ? \LaraZeus\BoltPro\Facades\GradeOptions::hidden() : [],
59 | ...Bolt::getHiddenCustomSchema('field', resolve(static::class)) ?? [],
60 | self::hiddenHtmlID(),
61 | self::hiddenHintOptions(),
62 | self::hiddenRequired(),
63 | self::hiddenColumnSpanFull(),
64 | self::hiddenHiddenLabel(),
65 | self::hiddenVisibility(),
66 | ];
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/src/Fields/Classes/Paragraph.php:
--------------------------------------------------------------------------------
1 | accordions([
37 | Accordion::make('general-options')
38 | ->label(__('General Options'))
39 | ->icon('tabler-settings')
40 | ->schema([
41 | self::columnSpanFull(),
42 | self::hiddenLabel(),
43 | self::hintOptions(),
44 | ]),
45 | self::visibility($sections),
46 | ]),
47 | ];
48 | }
49 |
50 | public static function getOptionsHidden(): array
51 | {
52 | return [
53 | self::hiddenHintOptions(),
54 | self::hiddenColumnSpanFull(),
55 | self::hiddenHiddenLabel(),
56 | self::hiddenVisibility(),
57 | ];
58 | }
59 |
60 | // @phpstan-ignore-next-line
61 | public function appendFilamentComponentsOptions($component, $zeusField, bool $hasVisibility = false)
62 | {
63 | parent::appendFilamentComponentsOptions($component, $zeusField, $hasVisibility);
64 |
65 | return $component
66 | ->helperText('')
67 | ->content(new HtmlString($zeusField->description));
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/src/Fields/Classes/RichEditor.php:
--------------------------------------------------------------------------------
1 | accordions([
36 | Accordion::make('general-options')
37 | ->label(__('General Options'))
38 | ->icon('tabler-settings')
39 | ->schema([
40 | self::required(),
41 | self::columnSpanFull(),
42 | self::hiddenLabel(),
43 | self::htmlID(),
44 | ]),
45 | self::hintOptions(),
46 | self::visibility($sections),
47 | // @phpstan-ignore-next-line
48 | ...Bolt::hasPro() ? \LaraZeus\BoltPro\Facades\GradeOptions::schema($field) : [],
49 | Bolt::getCustomSchema('field', resolve(static::class)) ?? [],
50 | ]),
51 | ];
52 | }
53 |
54 | public static function getOptionsHidden(): array
55 | {
56 | return [
57 | // @phpstan-ignore-next-line
58 | Bolt::hasPro() ? \LaraZeus\BoltPro\Facades\GradeOptions::hidden() : [],
59 | ...Bolt::getHiddenCustomSchema('field', resolve(static::class)) ?? [],
60 | self::hiddenVisibility(),
61 | self::hiddenHtmlID(),
62 | self::hiddenHintOptions(),
63 | self::hiddenRequired(),
64 | self::hiddenColumnSpanFull(),
65 | self::hiddenHiddenLabel(),
66 | ];
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/src/Fields/Classes/TimePicker.php:
--------------------------------------------------------------------------------
1 | accordions([
36 | Accordion::make('general-options')
37 | ->label(__('General Options'))
38 | ->icon('tabler-settings')
39 | ->schema([
40 | self::required(),
41 | self::columnSpanFull(),
42 | self::hiddenLabel(),
43 | self::htmlID(),
44 | ]),
45 | self::hintOptions(),
46 | self::visibility($sections),
47 | // @phpstan-ignore-next-line
48 | ...Bolt::hasPro() ? \LaraZeus\BoltPro\Facades\GradeOptions::schema($field) : [],
49 | Bolt::getCustomSchema('field', resolve(static::class)) ?? [],
50 | ]),
51 | ];
52 | }
53 |
54 | public static function getOptionsHidden(): array
55 | {
56 | return [
57 | // @phpstan-ignore-next-line
58 | Bolt::hasPro() ? \LaraZeus\BoltPro\Facades\GradeOptions::hidden() : [],
59 | ...Bolt::getHiddenCustomSchema('field', resolve(static::class)) ?? [],
60 | self::hiddenVisibility(),
61 | self::hiddenHtmlID(),
62 | self::hiddenHintOptions(),
63 | self::hiddenRequired(),
64 | self::hiddenColumnSpanFull(),
65 | self::hiddenHiddenLabel(),
66 | ];
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/src/Filament/Actions/ReplicateFormAction.php:
--------------------------------------------------------------------------------
1 | baseSetUp();
23 |
24 | $this->icon(FilamentIcon::resolve('actions::replicate-action') ?? 'heroicon-m-square-2-stack')
25 | ->label(__('Replicate'))
26 | ->excludeAttributes(['name', 'slug', 'responses_exists', 'responses_count'])
27 | ->form([
28 | TextInput::make('name.' . app()->getLocale())
29 | ->required()
30 | ->maxLength(255)
31 | ->live(onBlur: true)
32 | ->label(__('Form Name'))
33 | ->afterStateUpdated(function (Set $set, $state) {
34 | $set('slug', Str::slug($state));
35 | }),
36 | TextInput::make('slug')
37 | ->formatStateUsing(fn ($record) => $record->slug . '-' . rand(1, 99))
38 | ->required()
39 | ->maxLength(255)
40 | ->rules(['alpha_dash'])
41 | ->unique(ignoreRecord: true)
42 | ->label(__('Form Slug')),
43 | ])
44 | ->beforeReplicaSaved(function (ZeusForm $replica, ZeusForm $record, array $data): void {
45 | $repForm = $replica->fill($data);
46 | $repForm->save();
47 | $formID = $repForm->id;
48 | $record->sections->each(function ($item) use ($formID) {
49 | $repSec = $item->replicate()->fill(['form_id' => $formID]);
50 | $repSec->save();
51 | $sectionID = $repSec->id;
52 | $item->fields->each(function ($item) use ($sectionID) {
53 | $repField = $item->replicate()->fill(['section_id' => $sectionID]);
54 | $repField->save();
55 | });
56 | });
57 | });
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/Filament/Actions/SetResponseStatus.php:
--------------------------------------------------------------------------------
1 | visible(function (Response $record): bool {
29 | return $record->form->extensions === null;
30 | });
31 |
32 | $this->label(__('Set Status'));
33 |
34 | $this->icon('heroicon-o-tag');
35 |
36 | $this->action(function (array $data): void {
37 | $this->record->status = $data['status'];
38 | $this->record->notes = $data['notes'];
39 | $this->record->save();
40 | });
41 |
42 | $this->form([
43 | Select::make('status')
44 | ->label(__('status'))
45 | ->default(fn (Response $record) => $record->status)
46 | ->options(BoltPlugin::getModel('FormsStatus')::query()->pluck('label', 'key'))
47 | ->required(),
48 | Textarea::make('notes')
49 | ->default(fn (Response $record) => $record->notes)
50 | ->label(__('Notes')),
51 | ]);
52 | }
53 |
54 | public function mutateRecordDataUsing(?Closure $callback): static
55 | {
56 | $this->mutateRecordDataUsing = $callback;
57 |
58 | return $this;
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/Filament/Exports/ResponseExporter.php:
--------------------------------------------------------------------------------
1 | getRecord();
22 | // todo refactor with v4
23 | $userModel = BoltPlugin::getModel('User') ?? config('auth.providers.users.model');
24 | $getUserModel = $userModel::getBoltUserFullNameAttribute();
25 | $mainColumns = [
26 | ExportColumn::make('user.' . $getUserModel)
27 | ->label(__('Name'))
28 | ->default(__('guest')),
29 |
30 | ExportColumn::make('status')
31 | ->label(__('status')),
32 |
33 | ExportColumn::make('notes')
34 | ->label(__('notes')),
35 | ];
36 |
37 | /**
38 | * @var Field $field.
39 | */
40 | foreach ($record->fields->sortBy('ordering') as $field) {
41 | $getFieldTableColumn = (new $field->type)->ExportColumn($field);
42 |
43 | if ($getFieldTableColumn !== null) {
44 | $mainColumns[] = $getFieldTableColumn;
45 | }
46 | }
47 |
48 | $mainColumns[] = ExportColumn::make('created_at')
49 | ->label(__('created at'));
50 |
51 | return $mainColumns;
52 | }
53 |
54 | /*public static function getOptionsFormComponents(): array
55 | {
56 | return [
57 | TextInput::make('descriptionLimit')
58 | ->label('Limit the length of the description column content')
59 | ->integer(),
60 | ];
61 | }*/
62 |
63 | public static function getCompletedNotificationBody(Export $export): string
64 | {
65 | $body = 'Your response export has completed and ' . number_format($export->successful_rows) . ' ' . str('row')->plural($export->successful_rows) . ' exported.';
66 |
67 | if ($failedRowsCount = $export->getFailedRowsCount()) {
68 | $body .= ' ' . number_format($failedRowsCount) . ' ' . str('row')->plural($failedRowsCount) . ' failed to export.';
69 | }
70 |
71 | return $body;
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/src/Filament/Resources/BoltResource.php:
--------------------------------------------------------------------------------
1 | getHiddenResources())
16 | && parent::canViewAny();
17 | }
18 |
19 | public static function getNavigationGroup(): ?string
20 | {
21 | return BoltPlugin::get()->getNavigationGroupLabel();
22 | }
23 |
24 | public static function getGloballySearchableAttributes(): array
25 | {
26 | return BoltPlugin::get()->getGlobalAttributes(static::class);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/Filament/Resources/CategoryResource/Pages/CreateCategory.php:
--------------------------------------------------------------------------------
1 | paginated([1])
32 | ->query(BoltPlugin::getModel('Response')::query()->where('form_id', $this->record->id))
33 | ->columns([
34 | ViewColumn::make('response')
35 | ->label(__('Browse Entries'))
36 | ->view('zeus::filament.resources.response-resource.pages.browse-entry'),
37 | ])
38 | ->actions([
39 | SetResponseStatus::make(),
40 | ], position: ActionsPosition::AfterContent)
41 | ->filters([
42 | SelectFilter::make('status')
43 | ->options(BoltPlugin::getModel('FormsStatus')::query()->pluck('label', 'key'))
44 | ->label(__('Status')),
45 | ]);
46 | }
47 |
48 | public static function getNavigationLabel(): string
49 | {
50 | return __('Browse Entries');
51 | }
52 |
53 | public function getTitle(): string
54 | {
55 | return __('Browse Entries');
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/Filament/Resources/FormResource/Pages/CreateForm.php:
--------------------------------------------------------------------------------
1 | isFormActionsAreSticky();
19 | }
20 |
21 | protected function getHeaderActions(): array
22 | {
23 | return [
24 | Actions\LocaleSwitcher::make(),
25 | ];
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/Filament/Resources/FormResource/Pages/EditForm.php:
--------------------------------------------------------------------------------
1 | isFormActionsAreSticky();
25 | }
26 |
27 | public function getTitle(): string | Htmlable
28 | {
29 | return __('Edit Form');
30 | }
31 |
32 | public static function getNavigationLabel(): string
33 | {
34 | return __('Edit Form');
35 | }
36 |
37 | protected function getHeaderActions(): array
38 | {
39 | return [
40 | LocaleSwitcher::make(),
41 | Action::make('open')
42 | ->label(__('Open'))
43 | ->icon('heroicon-o-arrow-top-right-on-square')
44 | ->tooltip(__('open form'))
45 | ->color('warning')
46 | ->url(fn () => route(BoltPlugin::get()->getRouteNamePrefix() . 'bolt.form.show', $this->record))
47 | ->openUrlInNewTab(),
48 | ];
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/Filament/Resources/FormResource/Pages/ListForms.php:
--------------------------------------------------------------------------------
1 | label(__('Open'))
25 | ->icon('heroicon-o-arrow-top-right-on-square')
26 | ->tooltip(__('open all forms'))
27 | ->color('warning')
28 | ->url(fn () => route(BoltPlugin::get()->getRouteNamePrefix() . 'bolt.forms.list'))
29 | ->openUrlInNewTab(),
30 | ];
31 |
32 | if (Bolt::hasPro()) {
33 | // @phpstan-ignore-next-line
34 | $actions[] = \LaraZeus\BoltPro\Actions\PresetAction::make('new from preset')
35 | ->visible(config('zeus-bolt.show_presets'));
36 | }
37 |
38 | return $actions;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/Filament/Resources/FormResource/Pages/ViewForm.php:
--------------------------------------------------------------------------------
1 | label(__('Open'))
39 | ->icon('heroicon-o-arrow-top-right-on-square')
40 | ->tooltip(__('open form'))
41 | ->color('warning')
42 | ->url(fn () => route(BoltPlugin::get()->getRouteNamePrefix() . 'bolt.form.show', $this->record))
43 | ->visible(fn (Form $record) => $record->extensions === null)
44 | ->openUrlInNewTab(),
45 | ];
46 | }
47 |
48 | protected function getFooterWidgets(): array
49 | {
50 | $widgets = [
51 | FormResource\Widgets\FormOverview::class,
52 | FormResource\Widgets\ResponsesPerMonth::class,
53 | FormResource\Widgets\ResponsesPerStatus::class,
54 | FormResource\Widgets\ResponsesPerFields::class,
55 | ];
56 |
57 | if (Bolt::hasPro()) {
58 | // @phpstan-ignore-next-line
59 | $widgets[] = \LaraZeus\BoltPro\Widgets\ResponsesCharts::class;
60 | }
61 |
62 | return $widgets;
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/Filament/Resources/FormResource/Pages/ViewResponse.php:
--------------------------------------------------------------------------------
1 | response = Response::find($this->responseID);
33 | static::authorizeResourceAccess();
34 | }
35 |
36 | protected function getHeaderActions(): array
37 | {
38 | return [
39 | Action::make('set-status')
40 | ->visible(function (): bool {
41 | return $this->response->form->extensions === null;
42 | })
43 | ->label(__('Set Status'))
44 | ->icon('heroicon-o-tag')
45 | ->form([
46 | Select::make('status')
47 | ->label(__('status'))
48 | ->default(fn () => $this->response->status)
49 | ->options(BoltPlugin::getModel('FormsStatus')::query()->pluck('label', 'key'))
50 | ->required(),
51 | Textarea::make('notes')
52 | ->default(fn () => $this->response->notes)
53 | ->label(__('Notes')),
54 | ])
55 | ->action(function (array $data): void {
56 | $this->response->status = $data['status'];
57 | $this->response->notes = $data['notes'];
58 | $this->response->save();
59 | }),
60 | ];
61 | }
62 |
63 | public function getTitle(): string | Htmlable
64 | {
65 | return __('view response #') . $this->response->id;
66 | }
67 |
68 | public function getBreadcrumbs(): array
69 | {
70 | return [
71 | FormResource::getUrl() => FormResource::getBreadcrumb(),
72 | FormResource::getUrl('view', ['record' => $this->record->slug]) => $this->record->name,
73 | FormResource::getUrl('report', ['record' => $this->record->slug]) => __('Entries Report'),
74 | __('view the entry'),
75 | ];
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/src/Filament/Resources/FormResource/Widgets/FormOverview.php:
--------------------------------------------------------------------------------
1 | record->fields()->count())->label(__('Fields')),
17 | Stat::make('responses', $this->record->responses()->count())->label(__('Responses')),
18 | Stat::make('fields_responses', $this->record->fieldsResponses()->count())->label(__('Fields Responses')),
19 | ];
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/Filament/Resources/FormResource/Widgets/ResponsesPerFields.php:
--------------------------------------------------------------------------------
1 | 1,
17 | 'md' => 2,
18 | ];
19 |
20 | protected static ?array $options = [
21 | 'scales' => [
22 | 'y' => [
23 | 'grid' => [
24 | 'display' => false,
25 | ],
26 | 'ticks' => [
27 | 'display' => false,
28 | ],
29 | ],
30 | 'x' => [
31 | 'grid' => [
32 | 'display' => false,
33 | ],
34 | 'ticks' => [
35 | 'display' => false,
36 | ],
37 | ],
38 | ],
39 | ];
40 |
41 | protected function getType(): string
42 | {
43 | return 'pie';
44 | }
45 |
46 | public function getHeading(): string
47 | {
48 | return __('Responses Entries');
49 | }
50 |
51 | protected function getData(): array
52 | {
53 | $dataset = [];
54 |
55 | $form = BoltPlugin::getModel('Form')::query()
56 | ->with(['fields', 'fieldsResponses'])
57 | ->where('id', $this->record->id)
58 | ->first();
59 |
60 | $fields = $form->fields;
61 | foreach ($fields as $field) {
62 | $dataset[] = $form->fieldsResponses
63 | ->where('field_id', $field->id)
64 | ->count();
65 | }
66 |
67 | return [
68 | 'datasets' => [
69 | [
70 | 'label' => __('entries per month'),
71 | 'data' => $dataset,
72 | 'backgroundColor' => '#8A8AFF',
73 | 'borderColor' => '#ffffff',
74 | ],
75 | ],
76 |
77 | 'labels' => $fields->pluck('name'),
78 | ];
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/src/Filament/Resources/FormResource/Widgets/ResponsesPerMonth.php:
--------------------------------------------------------------------------------
1 | __('Per Day'),
30 | 'per_month' => __('Per month'),
31 | 'per_year' => __('Per year'),
32 | ];
33 | }
34 |
35 | public function getHeading(): string
36 | {
37 | return __('Responses Count');
38 | }
39 |
40 | protected function getData(): array
41 | {
42 | $label = null;
43 |
44 | $data = Trend::model(BoltPlugin::getModel('Response'))
45 | ->between(
46 | start: now()->startOfYear(),
47 | end: now()->endOfYear(),
48 | );
49 |
50 | if ($this->filter == 'per_day') {
51 | $label = __('Per day');
52 | $data = $data->perDay();
53 | } elseif ($this->filter == 'per_month') {
54 | $label = __('Per month');
55 | $data = $data->perMonth();
56 | } elseif ($this->filter == 'per_year') {
57 | $label = __('Per year');
58 | $data = $data->perYear();
59 | }
60 |
61 | $data = $data->count();
62 |
63 | return [
64 | 'datasets' => [
65 | [
66 | 'label' => $label,
67 | 'data' => $data->map(fn (TrendValue $value) => $value->aggregate),
68 | ],
69 | ],
70 | 'labels' => $data->map(fn (TrendValue $value) => $value->date),
71 | ];
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/src/Filament/Resources/FormResource/Widgets/ResponsesPerStatus.php:
--------------------------------------------------------------------------------
1 | [
17 | 'y' => [
18 | 'grid' => [
19 | 'display' => false,
20 | ],
21 | 'ticks' => [
22 | 'display' => false,
23 | ],
24 | ],
25 | 'x' => [
26 | 'grid' => [
27 | 'display' => false,
28 | ],
29 | 'ticks' => [
30 | 'display' => false,
31 | ],
32 | ],
33 | ],
34 | ];
35 |
36 | protected int | string | array $columnSpan = [
37 | 'lg' => 1,
38 | 'md' => 2,
39 | ];
40 |
41 | public function getHeading(): string
42 | {
43 | return __('Responses Status');
44 | }
45 |
46 | protected function getData(): array
47 | {
48 | $dataset = [];
49 | $statuses = BoltPlugin::getModel('FormsStatus')::get();
50 |
51 | $form = BoltPlugin::getModel('Form')::query()
52 | ->with(['responses'])
53 | ->where('id', $this->record->id)
54 | ->first();
55 |
56 | foreach ($statuses as $status) {
57 | $dataset[] = $form->responses
58 | ->where('status', $status->key)
59 | ->count();
60 | }
61 |
62 | return [
63 | 'datasets' => [
64 | [
65 | 'label' => __('entries per month'),
66 | 'data' => $dataset,
67 | 'backgroundColor' => $statuses->pluck('chartColor'),
68 | 'borderColor' => '#ffffff',
69 | ],
70 | ],
71 |
72 | 'labels' => $statuses->pluck('label'),
73 | ];
74 | }
75 |
76 | protected function getType(): string
77 | {
78 | return 'pie';
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/src/Livewire/ListEntries.php:
--------------------------------------------------------------------------------
1 | query(
26 | config('zeus-bolt.models.Response')::query()->where('user_id', auth()->user()->id)
27 | )
28 | ->contentGrid([
29 | 'sm' => 1,
30 | 'md' => 2,
31 | 'xl' => 3,
32 | ])
33 | ->columns([
34 | Split::make([
35 | TextColumn::make('status')
36 | ->badge()
37 | ->label(__('status'))
38 | ->colors(config('zeus-bolt.models.FormsStatus')::pluck('key', 'color')->toArray())
39 | ->icons(config('zeus-bolt.models.FormsStatus')::pluck('key', 'icon')->toArray())
40 | ->grow(false),
41 | TextColumn::make('form.name')
42 | ->searchable('name')
43 | ->label(__('Form Name'))
44 | ->url(fn (Response $record): string => route('bolt.entry.show', $record)),
45 | ]),
46 | Stack::make([
47 | TextColumn::make('updated_at')->label(__('Updated At'))->dateTime(),
48 | ]),
49 | ]);
50 | }
51 |
52 | public function render(): View
53 | {
54 | seo()
55 | ->title(__('My Responses') . ' ' . config('zeus.site_title', 'Laravel'))
56 | ->description(__('My Responses') . ' ' . config('zeus.site_description', 'Laravel'))
57 | ->site(config('zeus.site_title', 'Laravel'))
58 | ->rawTag('favicon', ' ')
59 | ->rawTag(' ')
60 | ->withUrl()
61 | ->twitter();
62 |
63 | return view(app('boltTheme') . '.list-entries')
64 | ->layout(config('zeus.layout'));
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/Livewire/ListForms.php:
--------------------------------------------------------------------------------
1 | site(config('zeus.site_title', 'Laravel'))
14 | ->title(__('Forms') . ' - ' . config('zeus.site_title'))
15 | ->description(__('Forms') . ' - ' . config('zeus.site_description') . ' ' . config('zeus.site_title'))
16 | ->rawTag('favicon', ' ')
17 | ->rawTag(' ')
18 | ->withUrl()
19 | ->twitter();
20 |
21 | return view(app('boltTheme') . '.list-forms')
22 | ->with(
23 | 'categories',
24 | config('zeus-bolt.models.Category')::query()
25 | ->whereHas('forms', function ($query) {
26 | $query->whereNull('extensions');
27 | })
28 | ->where('is_active', 1)
29 | ->orderBy('ordering')
30 | ->get()
31 | )
32 | ->layout(config('zeus.layout'));
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/Livewire/ShowEntry.php:
--------------------------------------------------------------------------------
1 | response = config('zeus-bolt.models.Response')::with('user')
19 | ->where('user_id', auth()->user()->id)
20 | ->where('id', $responseID)
21 | ->firstOrFail();
22 | }
23 |
24 | public function render(): View
25 | {
26 | seo()
27 | ->title(__('Show entry') . ' #' . $this->response->id . ' - ' . config('zeus.site_title', 'Laravel'))
28 | ->description(__('Show entry') . ' - ' . config('zeus.site_description', 'Laravel'))
29 | ->site(config('zeus.site_title', 'Laravel'))
30 | ->rawTag('favicon', ' ')
31 | ->rawTag(' ')
32 | ->withUrl()
33 | ->twitter();
34 |
35 | return view(app('boltTheme') . '.show-entry')
36 | ->with('response', $this->response)
37 | ->layout(config('zeus.layout'));
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/Mail/FormSubmission.php:
--------------------------------------------------------------------------------
1 | form = $form;
30 | $this->response = $response;
31 | }
32 |
33 | /**
34 | * Get the message envelope.
35 | */
36 | public function envelope(): Envelope
37 | {
38 | return new Envelope(
39 | subject: __('New Submission in') . ' ' . $this->form->name,
40 | );
41 | }
42 |
43 | /**
44 | * Get the message content definition.
45 | */
46 | public function content(): Content
47 | {
48 | return new Content(
49 | markdown: 'zeus::emails.form-submission',
50 | with: [
51 | 'url' => url(Filament::getDefaultPanel()->getPath() . '/responses/' . $this->response->id),
52 | ],
53 | );
54 | }
55 |
56 | /**
57 | * Get the attachments for the message.
58 | *
59 | * @return array
60 | */
61 | public function attachments(): array
62 | {
63 | return [];
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/src/Models/Category.php:
--------------------------------------------------------------------------------
1 | hasMany(config('zeus-bolt.models.Form'));
45 | }
46 |
47 | /**
48 | * @return Attribute
49 | */
50 | protected function logoUrl(): Attribute
51 | {
52 | return Attribute::make(
53 | get: fn () => Storage::disk(config('zeus-bolt.uploadDisk'))->url($this->logo),
54 | );
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/Models/Collection.php:
--------------------------------------------------------------------------------
1 | 'collection',
27 | ];
28 |
29 | public function getTable(): string
30 | {
31 | return config('zeus-bolt.table-prefix') . 'collections';
32 | }
33 |
34 | public function getValuesListAttribute(): ?string
35 | {
36 | $allValues = collect($this->values);
37 |
38 | if ($allValues->isNotEmpty()) {
39 | return $allValues
40 | ->take(5)
41 | ->map(function ($item) {
42 | return $item['itemValue'] ?? null;
43 | })
44 | ->join(',');
45 | }
46 |
47 | return null;
48 | }
49 |
50 | protected static function newFactory(): Factory
51 | {
52 | return CollectionFactory::new();
53 | }
54 |
55 | public function user(): BelongsTo
56 | {
57 | return $this->belongsTo(config('zeus-bolt.models.User') ?? config('auth.providers.users.model'));
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/Models/Concerns/BelongToBolt.php:
--------------------------------------------------------------------------------
1 | 'array',
34 | ];
35 |
36 | public function getTable(): string
37 | {
38 | return config('zeus-bolt.table-prefix') . 'fields';
39 | }
40 |
41 | protected static function booted(): void
42 | {
43 | static::deleting(function (Field $field) {
44 | if ($field->isForceDeleting()) {
45 | // @phpstan-ignore-next-line
46 | $field->fieldResponses()->withTrashed()->get()->each(function ($item) {
47 | $item->forceDelete();
48 | });
49 | } else {
50 | $field->fieldResponses->each(function ($item) {
51 | $item->delete();
52 | });
53 | }
54 | });
55 | }
56 |
57 | protected static function newFactory(): Factory
58 | {
59 | return FieldFactory::new();
60 | }
61 |
62 | public function section(): BelongsTo
63 | {
64 | return $this->belongsTo(config('zeus-bolt.models.Section'));
65 | }
66 |
67 | public function fieldResponses(): HasMany
68 | {
69 | return $this->hasMany(config('zeus-bolt.models.FieldResponse'));
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/src/Models/FieldResponse.php:
--------------------------------------------------------------------------------
1 | belongsTo(config('zeus-bolt.models.Field'));
42 | }
43 |
44 | public function parentResponse(): BelongsTo
45 | {
46 | return $this->belongsTo(config('zeus-bolt.models.Response'), 'response_id', 'id');
47 | }
48 |
49 | public function form(): BelongsTo
50 | {
51 | return $this->belongsTo(config('zeus-bolt.models.Form'));
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/Models/FormsStatus.php:
--------------------------------------------------------------------------------
1 | 'NEW',
25 | 'label' => __('New'),
26 | 'description' => 'used when a new form created by the user or an employee',
27 | 'color' => 'success',
28 | 'chartColor' => '#21C55D',
29 | 'icon' => 'heroicon-o-document',
30 | 'class' => 'px-2 py-0.5 text-xs rounded-xl text-success-700 bg-success-500/10',
31 | ],
32 | [
33 | 'key' => 'OPEN',
34 | 'label' => __('Open'),
35 | 'description' => 'used when a new form created by the user or an employee',
36 | 'color' => 'success',
37 | 'chartColor' => '#21C55D',
38 | 'icon' => 'heroicon-o-document',
39 | 'class' => 'px-2 py-0.5 text-xs rounded-xl text-success-700 bg-success-500/10',
40 | ],
41 | [
42 | 'key' => 'CLOSE',
43 | 'label' => __('closed'),
44 | 'description' => 'used when a new form created by the user or an employee',
45 | 'color' => 'danger',
46 | 'chartColor' => '#EF4444',
47 | 'icon' => 'heroicon-o-x-circle',
48 | 'class' => 'px-2 py-0.5 text-xs rounded-xl text-danger-700 bg-danger-500/10',
49 | ],
50 | ];
51 | }
52 |
53 | protected function sushiShouldCache(): bool
54 | {
55 | return ! app()->isLocal();
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/Models/Response.php:
--------------------------------------------------------------------------------
1 | form, 'canDeleteResponse', ['response' => $response]);
45 |
46 | if ($canDelete === null) {
47 | $canDelete = true;
48 | }
49 |
50 | if (! $canDelete) {
51 | Notification::make()
52 | ->title(__('Can\'t delete a form linked to an Extensions'))
53 | ->danger()
54 | ->send();
55 |
56 | return false;
57 | }
58 |
59 | if ($response->isForceDeleting()) {
60 | // @phpstan-ignore-next-line
61 | $response->fieldsResponses()->withTrashed()->get()->each(fn ($item) => $item->forceDelete());
62 | } else {
63 | $response->fieldsResponses->each(fn ($item) => $item->delete());
64 | }
65 |
66 | return true;
67 | });
68 | }
69 |
70 | protected static function newFactory(): Factory
71 | {
72 | return ResponseFactory::new();
73 | }
74 |
75 | public function fieldsResponses(): HasMany
76 | {
77 | return $this->hasMany(config('zeus-bolt.models.FieldResponse'));
78 | }
79 |
80 | public function user(): BelongsTo
81 | {
82 | return $this->belongsTo(config('zeus-bolt.models.User') ?? config('auth.providers.users.model'));
83 | }
84 |
85 | public function form(): BelongsTo
86 | {
87 | return $this->belongsTo(config('zeus-bolt.models.Form'));
88 | }
89 |
90 | /**
91 | * get status detail.
92 | */
93 | public function statusDetails(): array
94 | {
95 | $getStatues = config('zeus-bolt.models.FormsStatus')::where('key', $this->status)->first();
96 |
97 | return [
98 | 'class' => $getStatues->class ?? '',
99 | 'icon' => $getStatues->icon ?? 'heroicon-s-document',
100 | 'label' => $getStatues->label ?? $this->status,
101 | 'key' => $getStatues->key ?? '',
102 | 'color' => $getStatues->color ?? '',
103 | ];
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/src/Models/Section.php:
--------------------------------------------------------------------------------
1 | 'array',
36 | ];
37 |
38 | public function getTable(): string
39 | {
40 | return config('zeus-bolt.table-prefix') . 'sections';
41 | }
42 |
43 | protected static function booted(): void
44 | {
45 | parent::booted();
46 | static::deleting(function (Section $section) {
47 | if ($section->isForceDeleting()) {
48 | // @phpstan-ignore-next-line
49 | $section->fields()->withTrashed()->get()->each(function ($item) {
50 | $item->fieldResponses()->withTrashed()->get()->each(function ($item) {
51 | $item->forceDelete();
52 | });
53 | $item->forceDelete();
54 | });
55 | } else {
56 | $section->fields->each(function ($item) {
57 | $item->fieldResponses->each(function ($item) {
58 | $item->delete();
59 | });
60 | $item->delete();
61 | });
62 | }
63 | });
64 | }
65 |
66 | protected static function newFactory(): Factory
67 | {
68 | return SectionFactory::new();
69 | }
70 |
71 | public function fields(): HasMany
72 | {
73 | return $this->hasMany(config('zeus-bolt.models.Field'), 'section_id', 'id');
74 | }
75 |
76 | public function form(): BelongsTo
77 | {
78 | return $this->belongsTo(config('zeus-bolt.models.Form'));
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/stubs/ZeusDataSources.stub:
--------------------------------------------------------------------------------
1 | default()
27 | ->id('admin')
28 | ->login()
29 | ->plugins([
30 | BoltPlugin::make(),
31 | SpatieLaravelTranslatablePlugin::make()
32 | ->defaultLocales(['en']),
33 | ])
34 | ->resources([
35 | CategoryResource::class,
36 | ])
37 | ->registration()
38 | ->passwordReset()
39 | ->emailVerification()
40 | ->middleware([
41 | EncryptCookies::class,
42 | AddQueuedCookiesToResponse::class,
43 | StartSession::class,
44 | AuthenticateSession::class,
45 | ShareErrorsFromSession::class,
46 | VerifyCsrfToken::class,
47 | SubstituteBindings::class,
48 | DisableBladeIconComponents::class,
49 | DispatchServingFilamentEvent::class,
50 | ])
51 | ->authMiddleware([
52 | Authenticate::class,
53 | ]);
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/tests/ArchTest.php:
--------------------------------------------------------------------------------
1 | expect(['dd', 'dump', 'ray'])
5 | ->each->not->toBeUsed();
6 |
--------------------------------------------------------------------------------
/tests/Models/User.php:
--------------------------------------------------------------------------------
1 | in(__DIR__);
7 |
--------------------------------------------------------------------------------
/tests/ResourcesTest.php:
--------------------------------------------------------------------------------
1 | assertSuccessful();
12 | });
13 |
14 | it('can render collection list', function () {
15 | get(CollectionResource::getUrl())
16 | ->assertSuccessful();
17 | });
18 |
19 | it('can render form list', function () {
20 | get(FormResource::getUrl())
21 | ->assertSuccessful();
22 | });
23 |
--------------------------------------------------------------------------------
/tests/TestCase.php:
--------------------------------------------------------------------------------
1 | actingAs(
38 | User::create(['email' => 'admin@domain.com', 'name' => 'Admin', 'password' => 'password'])
39 | );
40 | }
41 |
42 | protected function defineDatabaseMigrations(): void
43 | {
44 | $this->loadMigrationsFrom(__DIR__ . '/migrations');
45 | }
46 |
47 | protected function getPackageProviders($app): array
48 | {
49 | return [
50 | ActionsServiceProvider::class,
51 | BladeCaptureDirectiveServiceProvider::class,
52 | BladeHeroiconsServiceProvider::class,
53 | BladeIconsServiceProvider::class,
54 | FilamentServiceProvider::class,
55 | FormsServiceProvider::class,
56 | InfolistsServiceProvider::class,
57 | LivewireServiceProvider::class,
58 | NotificationsServiceProvider::class,
59 | SpatieLaravelTranslatablePluginServiceProvider::class,
60 | SupportServiceProvider::class,
61 | TablesServiceProvider::class,
62 | WidgetsServiceProvider::class,
63 | BladeTablerIconsServiceProvider::class,
64 | AdminPanelProvider::class,
65 | CoreServiceProvider::class,
66 | BoltServiceProvider::class,
67 | SEOServiceProvider::class,
68 | FilamentIconPickerServiceProvider::class,
69 | ];
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/tests/migrations/001_create_categories_table.php:
--------------------------------------------------------------------------------
1 | id();
18 | $table->text('name');
19 | $table->integer('ordering')->default(1);
20 | $table->boolean('is_active')->default(1);
21 | $table->text('description')->nullable();
22 | $table->string('slug');
23 | $table->string('logo')->nullable();
24 | $table->timestamps();
25 | $table->softDeletes();
26 | });
27 | }
28 |
29 | /**
30 | * Reverse the migrations.
31 | *
32 | * @return void
33 | */
34 | public function down()
35 | {
36 | Schema::dropIfExists(config('zeus-bolt.table-prefix') . 'categories');
37 | }
38 | };
39 |
--------------------------------------------------------------------------------
/tests/migrations/002_create_collections_table.php:
--------------------------------------------------------------------------------
1 | id();
18 | $table->text('name');
19 | $table->longText('values')->nullable();
20 | $table->timestamps();
21 | $table->softDeletes();
22 | });
23 | }
24 |
25 | /**
26 | * Reverse the migrations.
27 | *
28 | * @return void
29 | */
30 | public function down()
31 | {
32 | Schema::dropIfExists(config('zeus-bolt.table-prefix') . 'collections');
33 | }
34 | };
35 |
--------------------------------------------------------------------------------
/tests/migrations/003_create_forms_table.php:
--------------------------------------------------------------------------------
1 | id();
18 | $table->foreignId('user_id')->constrained('users');
19 | $table->foreignId('category_id')->nullable()->constrained(config('zeus-bolt.table-prefix') . 'categories');
20 | $table->text('name');
21 | $table->text('description')->nullable();
22 | $table->string('slug');
23 | $table->integer('ordering')->default(1);
24 | $table->boolean('is_active');
25 | $table->longText('details')->nullable();
26 | $table->longText('options')->nullable();
27 | $table->dateTime('start_date')->nullable();
28 | $table->dateTime('end_date')->nullable();
29 | $table->text('extensions')->nullable();
30 | $table->timestamps();
31 | $table->softDeletes();
32 | });
33 | }
34 |
35 | /**
36 | * Reverse the migrations.
37 | *
38 | * @return void
39 | */
40 | public function down()
41 | {
42 | Schema::dropIfExists(config('zeus-bolt.table-prefix') . 'forms');
43 | }
44 | };
45 |
--------------------------------------------------------------------------------
/tests/migrations/004_create_sections_table.php:
--------------------------------------------------------------------------------
1 | id();
18 | $table->foreignId('form_id')->constrained(config('zeus-bolt.table-prefix') . 'forms');
19 | $table->text('name')->nullable();
20 | $table->integer('ordering')->default(1);
21 | $table->integer('columns')->default(1);
22 | $table->text('description')->nullable();
23 | $table->string('icon')->nullable();
24 | $table->boolean('aside')->default(0);
25 | $table->boolean('borderless')->default(0);
26 | $table->boolean('compact')->default(0);
27 | $table->text('options')->nullable();
28 | $table->timestamps();
29 | $table->softDeletes();
30 | });
31 | }
32 |
33 | /**
34 | * Reverse the migrations.
35 | *
36 | * @return void
37 | */
38 | public function down()
39 | {
40 | Schema::dropIfExists(config('zeus-bolt.table-prefix') . 'sections');
41 | }
42 | };
43 |
--------------------------------------------------------------------------------
/tests/migrations/005_create_fields_table.php:
--------------------------------------------------------------------------------
1 | id();
18 | $table->foreignId('section_id')->constrained(config('zeus-bolt.table-prefix') . 'sections');
19 | $table->text('name');
20 | $table->text('description')->nullable();
21 | $table->string('type');
22 | $table->integer('ordering')->default(1);
23 | $table->text('options')->nullable();
24 | $table->timestamps();
25 | $table->softDeletes();
26 | });
27 | }
28 |
29 | /**
30 | * Reverse the migrations.
31 | *
32 | * @return void
33 | */
34 | public function down()
35 | {
36 | Schema::dropIfExists(config('zeus-bolt.table-prefix') . 'fields');
37 | }
38 | };
39 |
--------------------------------------------------------------------------------
/tests/migrations/006_create_responses_table.php:
--------------------------------------------------------------------------------
1 | id();
18 | $table->foreignId('form_id')->constrained(config('zeus-bolt.table-prefix') . 'forms');
19 | $table->foreignId('user_id')->nullable()->constrained('users');
20 | $table->string('status')->default('NEW');
21 | $table->text('notes')->nullable();
22 | $table->integer('extension_item_id')->nullable();
23 | $table->timestamps();
24 | $table->softDeletes();
25 | });
26 | }
27 |
28 | /**
29 | * Reverse the migrations.
30 | *
31 | * @return void
32 | */
33 | public function down()
34 | {
35 | Schema::dropIfExists(config('zeus-bolt.table-prefix') . 'responses');
36 | }
37 | };
38 |
--------------------------------------------------------------------------------
/tests/migrations/007_create_field_responses_table.php:
--------------------------------------------------------------------------------
1 | id();
18 | $table->foreignId('form_id')->constrained(config('zeus-bolt.table-prefix') . 'forms');
19 | $table->foreignId('field_id')->constrained(config('zeus-bolt.table-prefix') . 'fields');
20 | $table->foreignId('response_id')->constrained(config('zeus-bolt.table-prefix') . 'responses');
21 | $table->longText('response');
22 | $table->timestamps();
23 | $table->softDeletes();
24 | });
25 | }
26 |
27 | /**
28 | * Reverse the migrations.
29 | *
30 | * @return void
31 | */
32 | public function down()
33 | {
34 | Schema::dropIfExists(config('zeus-bolt.table-prefix') . 'field_responses');
35 | }
36 | };
37 |
--------------------------------------------------------------------------------