├── .gitignore ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── composer.json ├── dist └── js │ ├── field.js │ └── field.js.map ├── docs ├── demo-2.gif └── demo.gif ├── mix-manifest.json ├── package.json ├── resources └── js │ ├── components │ ├── DetailField.vue │ └── FormField.vue │ └── field.js ├── src ├── ActionHasDependencies.php ├── FieldServiceProvider.php ├── HasChildFields.php ├── HasDependencies.php ├── Http │ ├── Controllers │ │ └── ActionController.php │ └── Requests │ │ └── ActionRequest.php └── NovaDependencyContainer.php └── webpack.mix.js /.gitignore: -------------------------------------------------------------------------------- 1 | /.idea 2 | /vendor 3 | /node_modules 4 | package-lock.json 5 | composer.phar 6 | composer.lock 7 | phpunit.xml 8 | .phpunit.result.cache 9 | .DS_Store 10 | Thumbs.db 11 | .nvmrc 12 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## Nova Dependency Container 2 | 3 |
4 | 5 | ### Releases 6 | - [v1.2.10](https://github.com/epartment/nova-dependency-container/releases/tag/1.2.10) 7 | - Fixes a problem with [Whitecubes Flexible Content](https://github.com/whitecube/nova-flexible-content) package where the dependency container would do nothing #93 [whitecube/nova-flexible-content#87](https://github.com/whitecube/nova-flexible-content/issues/87) 8 | - [v1.2.9](https://github.com/epartment/nova-dependency-container/releases/tag/1.2.9) 9 | - Support BelongsToMany field when depending on the seleced resource #52 10 | - [v1.2.8](https://github.com/epartment/nova-dependency-container/releases/tag/1.2.8) 11 | - Ensure that each field resolves on it's own depending on the situation - PR #90 12 | - Fixes #89, #88, #87, #85 and #40 13 | - [v1.2.7](https://github.com/epartment/nova-dependency-container/releases/tag/1.2.7) 14 | - Fix an index error in Nova 2.5.0 where the rules-set array requires a key fields attribute #86 15 | - Support MorphTo controller #62,#85 16 | - Moved releases/changes to `CHANGELOG.md` 17 | - [v1.2.6](https://github.com/epartment/nova-dependency-container/releases/tag/1.2.6) 18 | - Fixes a problem where it should check if a model exist when creating a resource when it's impossible to satisfy dependencies 19 | - [v1.2.5](https://github.com/epartment/nova-dependency-container/releases/tag/1.2.5) 20 | - Fixes a problem where Nova can't resolve custom ActionRequest [#82](https://github.com/epartment/nova-dependency-container/issues/82) 21 | - [v1.2.4](https://github.com/epartment/nova-dependency-container/releases/tag/1.2.4) 22 | - Fixes a problem where fields with same names use previous validation rules when used in multiple containers [#81](https://github.com/epartment/nova-dependency-container/issues/81), [#60](https://github.com/epartment/nova-dependency-container/pull/60) (@melewski) 23 | - [v1.2.3](https://github.com/epartment/nova-dependency-container/releases/tag/1.2.3) 24 | - Fixed belongs-to/morph-to as nested fields [#80](https://github.com/epartment/nova-dependency-container/issues/80) 25 | - Added missing methods in validation rules 26 | - [v1.2.2](https://github.com/epartment/nova-dependency-container/releases/tag/1.2.2) 27 | - fixed fields not resolving when using `displayUsingLabels`, `resolveUsing` or `displayUsing`. (@dbf) 28 | - fixed action fields who do not return a collection (@bsormagec) 29 | - added two new methods `onEmpty` and `onNullOrZero`. (@niektenhoopen, @dbf) 30 | - changed the logic for dependency satisfaction where it is reversed 31 | - changed `field` in two separate names; `field` and `property`, to avoid confusion when being used on a resource or component. 32 | - [v1.2.1](https://github.com/epartment/nova-dependency-container/releases/tag/1.2.1) 33 | - fixed support for [BelongsTo](https://nova.laravel.com/docs/1.0/resources/relationships.html#belongsto) and [MorphTo](https://nova.laravel.com/docs/1.0/resources/relationships.html#morphto) fields (@mikaelpopowicz, @dbf) 34 | - [v1.2.0](https://github.com/epartment/nova-dependency-container/releases/tag/1.2.0) 35 | - working version for Laravel 5.8 | 6 and Nova 2.x. (@FastPointGaming, @spaceo, @cdbeaton, @yaroslawww) 36 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Epartment Ecommerce 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. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Nova Field Dependency Container 2 | 3 | [![Latest Version on Packagist](https://img.shields.io/packagist/v/epartment/nova-dependency-container.svg)](https://packagist.org/packages/epartment/nova-dependency-container) 4 | [![Total Downloads](https://img.shields.io/packagist/dt/epartment/nova-dependency-container.svg)](https://packagist.org/packages/epartment/nova-dependency-container) 5 | [![License](https://img.shields.io/packagist/l/epartment/nova-dependency-container.svg)](https://github.com/epartment/nova-dependency-container/blob/master/LICENSE.md) 6 | 7 |
8 | 9 | ### Description 10 | 11 | A container for grouping fields that depend on other field values. Dependencies can be set on any field type or value. 12 | 13 |
14 | 15 | ### Demo 16 | 17 | ![Demo](https://raw.githubusercontent.com/epartment/nova-dependency-container/master/docs/demo.gif) 18 | 19 |
20 | 21 | ### Versions 22 | 23 | - install v1.2.x for Laravel v5.8 or v6.x and Nova 2.x 24 | - install v1.1.2 for Laravel v5.7 and Nova v1.x 25 | 26 |
27 | 28 | ### Installation 29 | 30 | The package can be installed through Composer. 31 | 32 | ```bash 33 | composer require epartment/nova-dependency-container 34 | ``` 35 | 36 |
37 | 38 | ### Usage 39 | 40 | 1. Add the `Epartment\NovaDependencyContainer\HasDependencies` trait to your Nova Resource. 41 | 2. Add the `Epartment\NovaDependencyContainer\NovaDependencyContainer` to your Nova Resource `fields` method. 42 | 3. Add the `Epartment\NovaDependencyContainer\ActionHasDependencies` trait to your Nova Actions that you wish to use dependencies on. 43 | 44 | ```php 45 | class Page extends Resource 46 | { 47 | use HasDependencies; 48 | 49 | public function fields(Request $request) 50 | { 51 | return [ 52 | 53 | Select::make('Name format', 'name_format')->options([ 54 | 0 => 'First Name', 55 | 1 => 'First Name / Last Name', 56 | 2 => 'Full Name' 57 | ])->displayUsingLabels(), 58 | 59 | NovaDependencyContainer::make([ 60 | Text::make('First Name', 'first_name') 61 | ])->dependsOn('name_format', 0), 62 | 63 | ]; 64 | } 65 | } 66 | ``` 67 | 68 |
69 | 70 | ### Dependencies 71 | 72 | The package supports four kinds of dependencies: 73 | 74 | 1. `->dependsOn('field', 'value')` 75 | 2. `->dependsOnNot('field', 'value')` 76 | 3. `->dependsOnEmpty('field')` 77 | 4. `->dependsOnNotEmpty('field')` 78 | 5. `->dependsOnNullOrZero('field')` 79 | 80 | These dependencies can be combined by chaining the methods on the `NovaDependencyContainer`: 81 | 82 | ```php 83 | NovaDependencyContainer::make([ 84 | // dependency fields 85 | ]) 86 | ->dependsOn('field1', 'value1') 87 | ->dependsOnNotEmpty('field2') 88 | ->dependsOn('field3', 'value3') 89 | ``` 90 | 91 | The fields used as dependencies can be of any Laravel Nova field type. Currently only two relation field types are supported, `BelongsTo` and `MorphTo`. 92 | 93 | Here is an example using a checkbox: 94 | 95 | ![Demo](https://raw.githubusercontent.com/epartment/nova-dependency-container/master/docs/demo-2.gif) 96 | 97 | 98 |
99 | 100 | ### BelongsTo dependency 101 | 102 | If we follow the example of a *Post model belongsTo a User model*, taken from Novas documentation [BelongsTo](https://nova.laravel.com/docs/2.0/resources/relationships.html#belongsto), the dependency setup has the following construction. 103 | 104 | We use the singular form of the `belongsTo` resource in lower case, in this example `Post` becomes `post`. Then we define in dot notation, the property of the resource we want to depend on. In this example we just use the `id` property, as in `post.id`. 105 | 106 | ```php 107 | BelongsTo::make('Post'), 108 | 109 | NovaDependencyContainer::make([ 110 | Boolean::make('Visible') 111 | ]) 112 | ->dependsOn('post.id', 2) 113 | ``` 114 | 115 | When the `Post` resource with `id` 2 is being selected, a `Boolean` field will appear. 116 | 117 |
118 | 119 | ### BelongsToMany dependency 120 | 121 | A [BelongsToMany](https://nova.laravel.com/docs/2.0/resources/relationships.html#belongstomany) setup is similar to that of a [BelongsTo](https://nova.laravel.com/docs/2.0/resources/relationships.html#belongsto). 122 | 123 | The `dependsOn` method should be pointing to the name of the intermediate table. If it is called `role_user`, the setup should be 124 | 125 | ```php 126 | BelongsToMany::make('Roles') 127 | ->fields(function() { 128 | return [ 129 | NovaDependencyContainer::make([ 130 | // pivot field rules_all 131 | Boolean::make('Rules All', 'rules_all') 132 | ]) 133 | ->dependsOn('role_user', 1) 134 | ] 135 | }), 136 | ``` 137 | 138 | If the pivot field name occurs multiple times, consider using [custom intermediate table models](https://laravel.com/docs/6.x/eloquent-relationships#defining-custom-intermediate-table-models) and define it in the appropiate model relation methods. The only reliable solution I found was using mutators to get/set a field which was being used multiple times. Although this may seem ugly, the events which should be fired on the intermediate model instance, when using an Observer, would work unreliable with every new release of Nova. 139 | 140 | > If Nova becomes reliable firing eloquent events on the intermediate table, I will update this examples with a more elegant approach using events instead. 141 | 142 | Here is an (ugly) example of a get/set mutator setup for an intermediate table using a pivot field called `type`. 143 | 144 | ```php 145 | // model User 146 | class User ... { 147 | 148 | public function roles() { 149 | return $this->belongsToMany->using(RoleUser::class)->withPivot('rules_all'); 150 | } 151 | 152 | } 153 | 154 | // model Role 155 | class Role ... { 156 | 157 | public function users() { 158 | return $this->belongsToMany->using(RoleUser::class)->withPivot('rules_all'); 159 | } 160 | 161 | } 162 | 163 | // intermediate table 164 | use Illuminate\Database\Eloquent\Relations\Pivot; 165 | class RoleUser extends Pivot { 166 | 167 | protected $table 'role_user'; 168 | 169 | public function getType1Attribute() { 170 | return $this->type; 171 | } 172 | 173 | public function setType1Attribute($value) { 174 | $this->attributes['type'] = $value; 175 | } 176 | 177 | // ... repeat for as many types as needed 178 | } 179 | ``` 180 | 181 | And now for the dependency container. 182 | 183 | ```php 184 | ->fields(function() { 185 | return [ 186 | NovaDependencyContainer::make([ 187 | // pivot field rules_all 188 | Select::make('Type', 'type_1') 189 | ->options([ 190 | /* some options */ 191 | ]) 192 | ->displayUsingLabels() 193 | ]) 194 | ->dependsOn('role_user', 1) 195 | , 196 | 197 | NovaDependencyContainer::make([ 198 | // pivot field rules_all 199 | Select::make('Type', 'type_2') 200 | ->options([ 201 | /* different options */ 202 | ]) 203 | ->displayUsingLabels() 204 | ]) 205 | ->dependsOn('role_user', 2) 206 | , 207 | 208 | // .. and so on 209 | ] 210 | }), 211 | ``` 212 | 213 |
214 | 215 | ### MorphTo dependency 216 | 217 | A similar example taken from Novas documentation for [MorphTo](https://nova.laravel.com/docs/2.0/resources/relationships.html#morphto) is called commentable. It uses 3 Models; `Comment`, `Video` and `Post`. Here `Comment` has the morphable fields `commentable_id` and `commentable_type` 218 | 219 | For a `MorphTo` dependency, the following construction is needed. 220 | 221 | `Commentable` becomes lower case `commentable` and the value to depend on is the resource singular form. In this example the dependency container will add two additional fields, `Additional Text` and `Visible`, only when the `Post` resource is selected. 222 | 223 | ```php 224 | MorphTo::make('Commentable')->types([ 225 | Post::class, 226 | Video::class, 227 | ]), 228 | 229 | NovaDependencyContainer::make([ 230 | Text::make('Additional Text', 'additional'), 231 | Boolean::make('Visible', 'visible') 232 | ]) 233 | ->dependsOn('commentable', 'Post') 234 | ``` 235 | 236 |
237 | 238 | ### License 239 | 240 | The MIT License (MIT). Please see [License File](https://github.com/epartment/nova-dependency-container/blob/master/LICENSE.md) for more information. 241 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "epartment/nova-dependency-container", 3 | "description": "A Laravel Nova field container allowing to depend on other fields values", 4 | "keywords": [ 5 | "laravel", 6 | "nova" 7 | ], 8 | "license": "MIT", 9 | "require": { 10 | "php": ">=7.1.0" 11 | }, 12 | "autoload": { 13 | "psr-4": { 14 | "Epartment\\NovaDependencyContainer\\": "src/" 15 | } 16 | }, 17 | "extra": { 18 | "laravel": { 19 | "providers": [ 20 | "Epartment\\NovaDependencyContainer\\FieldServiceProvider" 21 | ] 22 | } 23 | }, 24 | "config": { 25 | "sort-packages": true 26 | }, 27 | "minimum-stability": "dev", 28 | "prefer-stable": true 29 | } 30 | -------------------------------------------------------------------------------- /dist/js/field.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"/dist/js/field.js","sources":["webpack:////dist/js/field.js"],"sourcesContent":["!function(e){var t={};function r(n){if(t[n])return t[n].exports;var o=t[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,r),o.l=!0,o.exports}r.m=e,r.c=t,r.d=function(e,t,n){r.o(e,t)||Object.defineProperty(e,t,{configurable:!1,enumerable:!0,get:n})},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,\"a\",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p=\"\",r(r.s=1)}([function(e,t){e.exports=function(e,t,r,n,o,i){var u,s=e=e||{},a=typeof e.default;\"object\"!==a&&\"function\"!==a||(u=e,s=e.default);var c,f=\"function\"==typeof s?s.options:s;if(t&&(f.render=t.render,f.staticRenderFns=t.staticRenderFns,f._compiled=!0),r&&(f.functional=!0),o&&(f._scopeId=o),i?(c=function(e){(e=e||this.$vnode&&this.$vnode.ssrContext||this.parent&&this.parent.$vnode&&this.parent.$vnode.ssrContext)||\"undefined\"==typeof __VUE_SSR_CONTEXT__||(e=__VUE_SSR_CONTEXT__),n&&n.call(this,e),e&&e._registeredComponents&&e._registeredComponents.add(i)},f._ssrRegister=c):n&&(c=n),c){var l=f.functional,p=l?f.render:f.beforeCreate;l?(f._injectStyles=c,f.render=function(e,t){return c.call(t),p(e,t)}):f.beforeCreate=p?[].concat(p,c):[c]}return{esModule:u,exports:s,options:f}}},function(e,t,r){e.exports=r(2)},function(e,t,r){Nova.booting(function(e,t){e.component(\"detail-nova-dependency-container\",r(3)),e.component(\"form-nova-dependency-container\",r(6))})},function(e,t,r){var n=r(0)(r(4),r(5),!1,null,null,null);e.exports=n.exports},function(e,t,r){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0}),t.default={props:[\"resource\",\"resourceName\",\"resourceId\",\"field\"],created:function(){this.updateDependencyStatus()},data:function(){return{dependenciesSatisfied:!1}},methods:{updateDependencyStatus:function(){var e=!0,t=!1,r=void 0;try{for(var n,o=this.field.dependencies[Symbol.iterator]();!(e=(n=o.next()).done);e=!0){var i=n.value,u=!0,s=!1,a=void 0;try{for(var c,f=_.values(this.resource.fields)[Symbol.iterator]();!(u=(c=f.next()).done);u=!0){var l=c.value;if(i.field===l.attribute){if(i.hasOwnProperty(\"notEmpty\")&&!l.value)return void(this.dependenciesSatisfied=!1);if(i.hasOwnProperty(\"value\")&&l.value!==i.value)return void(this.dependenciesSatisfied=!1)}}}catch(e){s=!0,a=e}finally{try{!u&&f.return&&f.return()}finally{if(s)throw a}}}}catch(e){t=!0,r=e}finally{try{!e&&o.return&&o.return()}finally{if(t)throw r}}this.dependenciesSatisfied=!0}}}},function(e,t){e.exports={render:function(){var e=this,t=e.$createElement,r=e._self._c||t;return e.dependenciesSatisfied?r(\"div\",e._l(e.field.fields,function(t){return r(\"div\",[r(\"detail-\"+t.component,{ref:\"field-\"+t.attribute,refInFor:!0,tag:\"component\",attrs:{\"resource-id\":e.resourceId,\"resource-name\":e.resourceName,field:t}})],1)})):e._e()},staticRenderFns:[]}},function(e,t,r){var n=r(0)(r(7),r(9),!1,null,null,null);e.exports=n.exports},function(e,t,r){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=r(8);r.n(n);t.default={mixins:[n.FormField,n.HandlesValidationErrors],props:[\"resourceName\",\"resourceId\",\"field\"],mounted:function(){this.registerDependencyWatchers(this.$root),this.updateDependencyStatus()},data:function(){return{dependencyValues:{},dependenciesSatisfied:!1}},methods:{registerDependencyWatchers:function(e){var t=this;e.$children.forEach(function(e){t.componentIsDependency(e)&&(e.$watch(\"value\",function(r){t.dependencyValues[e.field.attribute]=r,t.updateDependencyStatus()},{immediate:!0}),t.dependencyValues[e.field.attribute]=e.field.value),t.registerDependencyWatchers(e)})},componentIsDependency:function(e){if(void 0===e.field)return!1;var t=!0,r=!1,n=void 0;try{for(var o,i=this.field.dependencies[Symbol.iterator]();!(t=(o=i.next()).done);t=!0){var u=o.value;if(e.field.attribute===u.field)return console.log(e),!0}}catch(e){r=!0,n=e}finally{try{!t&&i.return&&i.return()}finally{if(r)throw n}}return!1},updateDependencyStatus:function(){var e=!0,t=!1,r=void 0;try{for(var n,o=this.field.dependencies[Symbol.iterator]();!(e=(n=o.next()).done);e=!0){var i=n.value;if(i.hasOwnProperty(\"notEmpty\")&&!this.dependencyValues[i.field])return void(this.dependenciesSatisfied=!1);if(i.hasOwnProperty(\"value\")&&this.dependencyValues[i.field]!==i.value)return void(this.dependenciesSatisfied=!1)}}catch(e){t=!0,r=e}finally{try{!e&&o.return&&o.return()}finally{if(t)throw r}}this.dependenciesSatisfied=!0},fill:function(e){this.dependenciesSatisfied&&this.$children.forEach(function(t){t.fill(e)})}}}},function(e,t,r){var n;n=function(){return function(e){var t={};function r(n){if(t[n])return t[n].exports;var o=t[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,r),o.l=!0,o.exports}return r.m=e,r.c=t,r.i=function(e){return e},r.d=function(e,t,n){r.o(e,t)||Object.defineProperty(e,t,{configurable:!1,enumerable:!0,get:n})},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,\"a\",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p=\"\",r(r.s=47)}([function(e,t,r){\"use strict\";var n=r(46),o=r(158),i=Object.prototype.toString;function u(e){return\"[object Array]\"===i.call(e)}function s(e){return null!==e&&\"object\"==typeof e}function a(e){return\"[object Function]\"===i.call(e)}function c(e,t){if(null!==e&&void 0!==e)if(\"object\"!=typeof e&&(e=[e]),u(e))for(var r=0,n=e.length;r=200&&e<300}};a.headers={common:{Accept:\"application/json, text/plain, */*\"}},n.forEach([\"delete\",\"get\",\"head\"],function(e){a.headers[e]={}}),n.forEach([\"post\",\"put\",\"patch\"],function(e){a.headers[e]=n.merge(i)}),e.exports=a}).call(t,r(73))},function(e,t,r){\"use strict\";t.__esModule=!0;var n,o=r(112),i=(n=o)&&n.__esModule?n:{default:n};t.default=function(e,t,r){return t in e?(0,i.default)(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}},function(e,t){e.exports=function(e){if(void 0==e)throw TypeError(\"Can't call method on \"+e);return e}},function(e,t,r){var n=r(9),o=r(1).document,i=n(o)&&n(o.createElement);e.exports=function(e){return i?o.createElement(e):{}}},function(e,t){e.exports=function(e){try{return!!e()}catch(e){return!0}}},function(e,t){e.exports=!0},function(e,t,r){\"use strict\";var n=r(14);e.exports.f=function(e){return new function(e){var t,r;this.promise=new e(function(e,n){if(void 0!==t||void 0!==r)throw TypeError(\"Bad Promise constructor\");t=e,r=n}),this.resolve=n(t),this.reject=n(r)}(e)}},function(e,t,r){var n=r(11).f,o=r(17),i=r(2)(\"toStringTag\");e.exports=function(e,t,r){e&&!o(e=r?e:e.prototype,i)&&n(e,i,{configurable:!0,value:t})}},function(e,t,r){var n=r(58)(\"keys\"),o=r(63);e.exports=function(e){return n[e]||(n[e]=o(e))}},function(e,t){var r=Math.ceil,n=Math.floor;e.exports=function(e){return isNaN(e=+e)?0:(e>0?n:r)(e)}},function(e,t,r){var n=r(52),o=r(27);e.exports=function(e){return n(o(e))}},function(e,t,r){var n=r(12).Symbol;e.exports=n},function(e,t,r){var n=r(172),o=r(191);e.exports=function(e,t){var r=o(e,t);return n(r)?r:void 0}},function(e,t){e.exports=function(e,t){return e===t||e!=e&&t!=t}},function(e,t){e.exports=function(e){return e}},function(e,t,r){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0}),t.default=[\"1/2\",\"1/3\",\"2/3\",\"1/4\",\"3/4\",\"1/5\",\"2/5\",\"3/5\",\"4/5\",\"1/6\",\"5/6\"]},function(e,t,r){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=r(156);Object.defineProperty(t,\"default\",{enumerable:!0,get:function(){return i(n).default}}),Object.defineProperty(t,\"Form\",{enumerable:!0,get:function(){return i(n).default}});var o=r(64);function i(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,\"Errors\",{enumerable:!0,get:function(){return i(o).default}})},function(e,t,r){\"use strict\";(function(t){var n=r(0),o=r(99),i=r(102),u=r(108),s=r(106),a=r(45),c=\"undefined\"!=typeof window&&window.btoa&&window.btoa.bind(window)||r(101);e.exports=function(e){return new Promise(function(f,l){var p=e.data,d=e.headers;n.isFormData(p)&&delete d[\"Content-Type\"];var h=new XMLHttpRequest,v=\"onreadystatechange\",y=!1;if(\"test\"===t.env.NODE_ENV||\"undefined\"==typeof window||!window.XDomainRequest||\"withCredentials\"in h||s(e.url)||(h=new window.XDomainRequest,v=\"onload\",y=!0,h.onprogress=function(){},h.ontimeout=function(){}),e.auth){var g=e.auth.username||\"\",m=e.auth.password||\"\";d.Authorization=\"Basic \"+c(g+\":\"+m)}if(h.open(e.method.toUpperCase(),i(e.url,e.params,e.paramsSerializer),!0),h.timeout=e.timeout,h[v]=function(){if(h&&(4===h.readyState||y)&&(0!==h.status||h.responseURL&&0===h.responseURL.indexOf(\"file:\"))){var t=\"getAllResponseHeaders\"in h?u(h.getAllResponseHeaders()):null,r={data:e.responseType&&\"text\"!==e.responseType?h.response:h.responseText,status:1223===h.status?204:h.status,statusText:1223===h.status?\"No Content\":h.statusText,headers:t,config:e,request:h};o(f,l,r),h=null}},h.onerror=function(){l(a(\"Network Error\",e,null,h)),h=null},h.ontimeout=function(){l(a(\"timeout of \"+e.timeout+\"ms exceeded\",e,\"ECONNABORTED\",h)),h=null},n.isStandardBrowserEnv()){var x=r(104),b=(e.withCredentials||s(e.url))&&e.xsrfCookieName?x.read(e.xsrfCookieName):void 0;b&&(d[e.xsrfHeaderName]=b)}if(\"setRequestHeader\"in h&&n.forEach(d,function(e,t){void 0===p&&\"content-type\"===t.toLowerCase()?delete d[t]:h.setRequestHeader(t,e)}),e.withCredentials&&(h.withCredentials=!0),e.responseType)try{h.responseType=e.responseType}catch(t){if(\"json\"!==e.responseType)throw t}\"function\"==typeof e.onDownloadProgress&&h.addEventListener(\"progress\",e.onDownloadProgress),\"function\"==typeof e.onUploadProgress&&h.upload&&h.upload.addEventListener(\"progress\",e.onUploadProgress),e.cancelToken&&e.cancelToken.promise.then(function(e){h&&(h.abort(),l(e),h=null)}),void 0===p&&(p=null),h.send(p)})}}).call(t,r(73))},function(e,t,r){\"use strict\";function n(e){this.message=e}n.prototype.toString=function(){return\"Cancel\"+(this.message?\": \"+this.message:\"\")},n.prototype.__CANCEL__=!0,e.exports=n},function(e,t,r){\"use strict\";e.exports=function(e){return!(!e||!e.__CANCEL__)}},function(e,t,r){\"use strict\";var n=r(98);e.exports=function(e,t,r,o,i){var u=new Error(e);return n(u,t,r,o,i)}},function(e,t,r){\"use strict\";e.exports=function(e,t){return function(){for(var r=new Array(arguments.length),n=0;nr;)t.push(arguments[r++]);return g[++y]=function(){s(\"function\"==typeof e?e:Function(e),t)},n(y),y},d=function(e){delete g[e]},\"process\"==r(15)(l)?n=function(e){l.nextTick(u(m,e,1))}:v&&v.now?n=function(e){v.now(u(m,e,1))}:h?(i=(o=new h).port2,o.port1.onmessage=x,n=u(i.postMessage,i,1)):f.addEventListener&&\"function\"==typeof postMessage&&!f.importScripts?(n=function(e){f.postMessage(e+\"\",\"*\")},f.addEventListener(\"message\",x,!1)):n=\"onreadystatechange\"in c(\"script\")?function(e){a.appendChild(c(\"script\")).onreadystatechange=function(){a.removeChild(this),m.call(e)}}:function(e){setTimeout(u(m,e,1),0)}),e.exports={set:p,clear:d}},function(e,t,r){var n=r(34),o=Math.min;e.exports=function(e){return e>0?o(n(e),9007199254740991):0}},function(e,t,r){var n=r(27);e.exports=function(e){return Object(n(e))}},function(e,t){var r=0,n=Math.random();e.exports=function(e){return\"Symbol(\".concat(void 0===e?\"\":e,\")_\",(++r+n).toString(36))}},function(e,t,r){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=function(){function e(e,t){for(var r=0;r0&&void 0!==arguments[0]?arguments[0]:{};!function(e,t){if(!(e instanceof t))throw new TypeError(\"Cannot call a class as a function\")}(this,e),this.record(t)}return n(e,[{key:\"all\",value:function(){return this.errors}},{key:\"has\",value:function(e){var t=this.errors.hasOwnProperty(e);t||(t=Object.keys(this.errors).filter(function(t){return t.startsWith(e+\".\")||t.startsWith(e+\"[\")}).length>0);return t}},{key:\"first\",value:function(e){return this.get(e)[0]}},{key:\"get\",value:function(e){return this.errors[e]||[]}},{key:\"any\",value:function(){return Object.keys(this.errors).length>0}},{key:\"record\",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};this.errors=e}},{key:\"clear\",value:function(e){if(e){var t=Object.assign({},this.errors);Object.keys(t).filter(function(t){return t===e||t.startsWith(e+\".\")||t.startsWith(e+\"[\")}).forEach(function(e){return delete t[e]}),this.errors=t}else this.errors={}}}]),e}();t.default=o},function(e,t,r){var n=r(179),o=r(231),i=r(13),u=r(232),s=r(68),a=r(233),c=Object.prototype.hasOwnProperty;e.exports=function(e,t){var r=i(e),f=!r&&o(e),l=!r&&!f&&u(e),p=!r&&!f&&!l&&a(e),d=r||f||l||p,h=d?n(e.length,String):[],v=h.length;for(var y in e)!t&&!c.call(e,y)||d&&(\"length\"==y||l&&(\"offset\"==y||\"parent\"==y)||p&&(\"buffer\"==y||\"byteLength\"==y||\"byteOffset\"==y)||s(y,v))||h.push(y);return h}},function(e,t,r){(function(t){var r=\"object\"==typeof t&&t&&t.Object===Object&&t;e.exports=r}).call(t,r(243))},function(e,t){var r=RegExp(\"[\\\\u200d\\\\ud800-\\\\udfff\\\\u0300-\\\\u036f\\\\ufe20-\\\\ufe2f\\\\u20d0-\\\\u20ff\\\\ufe0e\\\\ufe0f]\");e.exports=function(e){return r.test(e)}},function(e,t){var r=9007199254740991,n=/^(?:0|[1-9]\\d*)$/;e.exports=function(e,t){var o=typeof e;return!!(t=null==t?r:t)&&(\"number\"==o||\"symbol\"!=o&&n.test(e))&&e>-1&&e%1==0&&e-1&&e%1==0&&e<=r}},function(e,t,r){var n=r(180);e.exports=function(e){return null==e?\"\":n(e)}},function(e,t){var r,n,o=e.exports={};function i(){throw new Error(\"setTimeout has not been defined\")}function u(){throw new Error(\"clearTimeout has not been defined\")}function s(e){if(r===setTimeout)return setTimeout(e,0);if((r===i||!r)&&setTimeout)return r=setTimeout,setTimeout(e,0);try{return r(e,0)}catch(t){try{return r.call(null,e,0)}catch(t){return r.call(this,e,0)}}}!function(){try{r=\"function\"==typeof setTimeout?setTimeout:i}catch(e){r=i}try{n=\"function\"==typeof clearTimeout?clearTimeout:u}catch(e){n=u}}();var a,c=[],f=!1,l=-1;function p(){f&&a&&(f=!1,a.length?c=a.concat(c):l=-1,c.length&&d())}function d(){if(!f){var e=s(p);f=!0;for(var t=c.length;t;){for(a=c,c=[];++l1)for(var r=1;r1&&void 0!==arguments[1]?arguments[1]:null;return this.viaManyToMany?this.detachResources(e):Nova.request({url:\"/nova-api/\"+this.resourceName,method:\"delete\",params:(0,i.default)({},this.queryString,{resources:u(e)})}).then(r||function(){t.deleteModalOpen=!1,t.getResources()})},deleteSelectedResources:function(){this.deleteResources(this.selectedResources)},deleteAllMatchingResources:function(){var e=this;return this.viaManyToMany?this.detachAllMatchingResources():Nova.request({url:this.deleteAllMatchingResourcesEndpoint,method:\"delete\",params:(0,i.default)({},this.queryString,{resources:\"all\"})}).then(function(){e.deleteModalOpen=!1,e.getResources()})},detachResources:function(e){var t=this;return Nova.request({url:\"/nova-api/\"+this.resourceName+\"/detach\",method:\"delete\",params:(0,i.default)({},this.queryString,{resources:u(e)})}).then(function(){t.deleteModalOpen=!1,t.getResources()})},detachAllMatchingResources:function(){var e=this;return Nova.request({url:\"/nova-api/\"+this.resourceName+\"/detach\",method:\"delete\",params:(0,i.default)({},this.queryString,{resources:\"all\"})}).then(function(){e.deleteModalOpen=!1,e.getResources()})},forceDeleteResources:function(e){var t=this,r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;return Nova.request({url:\"/nova-api/\"+this.resourceName+\"/force\",method:\"delete\",params:(0,i.default)({},this.queryString,{resources:u(e)})}).then(r||function(){t.deleteModalOpen=!1,t.getResources()})},forceDeleteSelectedResources:function(){this.forceDeleteResources(this.selectedResources)},forceDeleteAllMatchingResources:function(){var e=this;return Nova.request({url:this.forceDeleteSelectedResourcesEndpoint,method:\"delete\",params:(0,i.default)({},this.queryString,{resources:\"all\"})}).then(function(){e.deleteModalOpen=!1,e.getResources()})},restoreResources:function(e){var t=this,r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;return Nova.request({url:\"/nova-api/\"+this.resourceName+\"/restore\",method:\"put\",params:(0,i.default)({},this.queryString,{resources:u(e)})}).then(r||function(){t.restoreModalOpen=!1,t.getResources()})},restoreSelectedResources:function(){this.restoreResources(this.selectedResources)},restoreAllMatchingResources:function(){var e=this;return Nova.request({url:this.restoreAllMatchingResourcesEndpoint,method:\"put\",params:(0,i.default)({},this.queryString,{resources:\"all\"})}).then(function(){e.restoreModalOpen=!1,e.getResources()})}},computed:{deleteAllMatchingResourcesEndpoint:function(){return this.lens?\"/nova-api/\"+this.resourceName+\"/lens/\"+this.lens:\"/nova-api/\"+this.resourceName},forceDeleteSelectedResourcesEndpoint:function(){return this.lens?\"/nova-api/\"+this.resourceName+\"/lens/\"+this.lens+\"/force\":\"/nova-api/\"+this.resourceName+\"/force\"},restoreAllMatchingResourcesEndpoint:function(){return this.lens?\"/nova-api/\"+this.resourceName+\"/lens/\"+this.lens+\"/restore\":\"/nova-api/\"+this.resourceName+\"/restore\"},queryString:function(){return{search:this.currentSearch,filters:this.encodedFilters,trashed:this.currentTrashed,viaResource:this.viaResource,viaResourceId:this.viaResourceId,viaRelationship:this.viaRelationship}}}}},function(e,t,r){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=s(r(26)),o=s(r(110)),i=s(r(228)),u=s(r(230));function s(e){return e&&e.__esModule?e:{default:e}}t.default={data:function(){return{filters:[],currentFilters:[]}},methods:{initializeFilterValuesFromQueryString:function(){this.clearAllFilters(),this.encodedFilters&&(this.currentFilters=JSON.parse(atob(this.encodedFilters)),this.syncFilterValues())},clearAllFilters:function(){this.currentFilters=[],(0,i.default)(this.filters,function(e){e.currentValue=\"\"})},syncFilterValues:function(){var e=this;(0,i.default)(this.filters,function(t){t.currentValue=(0,u.default)(_(e.currentFilters).find(function(e){return t.class==e.class}),\"value\",t.currentValue)})},filterChanged:function(){var e;this.updateQueryString((e={},(0,n.default)(e,this.pageParameter,1),(0,n.default)(e,this.filterParameter,btoa((0,o.default)(this.currentFilters))),e))}},computed:{encodedFilters:function(){return this.$route.query[this.filterParameter]||\"\"}}}},function(e,t,r){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0}),t.default={props:{resourceName:{},field:{}},data:function(){return{value:\"\"}},mounted:function(){var e=this;this.setInitialValue(),this.field.fill=this.fill,Nova.$on(this.field.attribute+\"-value\",function(t){e.value=t})},destroyed:function(){Nova.$off(this.field.attribute+\"-value\")},methods:{setInitialValue:function(){this.value=void 0!==this.field.value&&null!==this.field.value?this.field.value:\"\"},fill:function(e){e.append(this.field.attribute,this.value||\"\")},handleChange:function(e){this.value=e}}}},function(e,t,r){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=r(41);t.default={props:{errors:{default:function(){return new n.Errors}}},data:function(){return{errorClass:\"border-danger\"}},computed:{errorClasses:function(){return this.hasError?[this.errorClass]:[]},fieldAttribute:function(){return this.field.attribute},hasError:function(){return this.errors.has(this.fieldAttribute)},firstError:function(){if(this.hasError)return this.errors.first(this.fieldAttribute)}}}},function(e,t,r){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=u(r(115)),o=u(r(113)),i=u(r(40));function u(e){return e&&e.__esModule?e:{default:e}}t.default={props:{loadCards:{type:Boolean,default:!0}},data:function(){return{cards:[]}},created:function(){this.fetchCards()},watch:{cardsEndpoint:function(){this.fetchCards()}},methods:{fetchCards:function(){var e=(0,o.default)(n.default.mark(function e(){var t,r;return n.default.wrap(function(e){for(;;)switch(e.prev=e.next){case 0:if(!this.loadCards){e.next=6;break}return e.next=3,Nova.request().get(this.cardsEndpoint);case 3:t=e.sent,r=t.data,this.cards=r;case 6:case\"end\":return e.stop()}},e,this)}));return function(){return e.apply(this,arguments)}}()},computed:{shouldShowCards:function(){return this.cards.length>0},smallCards:function(){return _.filter(this.cards,function(e){return-1!==i.default.indexOf(e.width)})},largeCards:function(){return _.filter(this.cards,function(e){return\"full\"==e.width})}}}},function(e,t,r){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0}),t.default={methods:{toAppTimezone:function(e){return e?moment.tz(e,this.userTimezone).clone().tz(Nova.config.timezone).format(\"YYYY-MM-DD HH:mm:ss\"):e},fromAppTimezone:function(e){return e?moment.tz(e,Nova.config.timezone).clone().tz(this.userTimezone).format(\"YYYY-MM-DD HH:mm:ss\"):e},localizeDateTimeField:function(e){if(!e.value)return e.value;var t=moment.tz(e.value,Nova.config.timezone).clone().tz(this.userTimezone);return e.format?t.format(e.format):this.usesTwelveHourTime?t.format(\"YYYY-MM-DD h:mm:ss A\"):t.format(\"YYYY-MM-DD HH:mm:ss\")},localizeDateField:function(e){if(!e.value)return e.value;var t=moment.tz(e.value,Nova.config.timezone).clone().tz(this.userTimezone);return e.format?t.format(e.format):t.format(\"YYYY-MM-DD\")}},computed:{userTimezone:function(){return Nova.config.userTimezone?Nova.config.userTimezone:moment.tz.guess()},usesTwelveHourTime:function(){return _.endsWith((new Date).toLocaleString(),\"AM\")||_.endsWith((new Date).toLocaleString(),\"PM\")}}}},function(e,t,r){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n,o=r(227),i=(n=o)&&n.__esModule?n:{default:n};t.default={methods:{updateQueryString:function(e){this.$router.push({query:(0,i.default)(e,this.$route.query)})}}}},function(e,t,r){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0}),t.default={computed:{resourceInformation:function(){var e=this;return _.find(Nova.config.resources,function(t){return t.uriKey==e.resourceName})},viaResourceInformation:function(){var e=this;if(this.viaResource)return _.find(Nova.config.resources,function(t){return t.uriKey==e.viaResource})},authorizedToCreate:function(){return this.resourceInformation.authorizedToCreate}}}},function(e,t,r){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n,o=r(26),i=(n=o)&&n.__esModule?n:{default:n};t.default={methods:{selectPreviousPage:function(){this.updateQueryString((0,i.default)({},this.pageParameter,this.currentPage-1))},selectNextPage:function(){this.updateQueryString((0,i.default)({},this.pageParameter,this.currentPage+1))}},computed:{currentPage:function(){return parseInt(this.$route.query[this.pageParameter]||1)}}}},function(e,t,r){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n,o=r(26),i=(n=o)&&n.__esModule?n:{default:n};t.default={data:function(){return{perPage:25}},methods:{initializePerPageFromQueryString:function(){this.perPage=this.currentPerPage},perPageChanged:function(){this.updateQueryString((0,i.default)({},this.perPageParameter,this.perPage))}},computed:{currentPerPage:function(){return this.$route.query[this.perPageParameter]||25}}}},function(e,t,r){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n,o=r(226),i=(n=o)&&n.__esModule?n:{default:n};t.default={data:function(){return{search:\"\",selectedResource:\"\",availableResources:[]}},methods:{selectResource:function(e){this.selectedResource=e},handleSearchCleared:function(){this.availableResources=[]},clearSelection:function(){this.selectedResource=\"\",this.availableResources=[]},performSearch:function(e){var t=this;this.search=e;var r=e.trim();\"\"!=r?this.debouncer(function(){t.selectedResource=\"\",t.getAvailableResources(r)},500):this.clearSelection()},debouncer:(0,i.default)(function(e){return e()},500)}}},function(e,t,r){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0}),t.default={data:function(){return{withTrashed:!1}},methods:{toggleWithTrashed:function(){this.withTrashed=!this.withTrashed},enableWithTrashed:function(){this.withTrashed=!0},disableWithTrashed:function(){this.withTrashed=!1}}}},function(e,t,r){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0}),t.default=function(e){return(0,i.default)(e)};var n,o=r(240),i=(n=o)&&n.__esModule?n:{default:n}},function(e,t,r){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n,o=r(48),i=(n=o)&&n.__esModule?n:{default:n};t.default=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:100;return i.default.all([e,new i.default(function(e){setTimeout(function(){return e()},t)})]).then(function(e){return e[0]})}},function(e,t,r){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0}),t.default=function(e,t){return e>1||0==e?n.Inflector.pluralize(t):n.Inflector.singularize(t)};var n=r(47)},function(e,t,r){\"use strict\";var n={uncountableWords:[\"equipment\",\"information\",\"rice\",\"money\",\"species\",\"series\",\"fish\",\"sheep\",\"moose\",\"deer\",\"news\"],pluralRules:[[new RegExp(\"(m)an$\",\"gi\"),\"$1en\"],[new RegExp(\"(pe)rson$\",\"gi\"),\"$1ople\"],[new RegExp(\"(child)$\",\"gi\"),\"$1ren\"],[new RegExp(\"^(ox)$\",\"gi\"),\"$1en\"],[new RegExp(\"(ax|test)is$\",\"gi\"),\"$1es\"],[new RegExp(\"(octop|vir)us$\",\"gi\"),\"$1i\"],[new RegExp(\"(alias|status)$\",\"gi\"),\"$1es\"],[new RegExp(\"(bu)s$\",\"gi\"),\"$1ses\"],[new RegExp(\"(buffal|tomat|potat)o$\",\"gi\"),\"$1oes\"],[new RegExp(\"([ti])um$\",\"gi\"),\"$1a\"],[new RegExp(\"sis$\",\"gi\"),\"ses\"],[new RegExp(\"(?:([^f])fe|([lr])f)$\",\"gi\"),\"$1$2ves\"],[new RegExp(\"(hive)$\",\"gi\"),\"$1s\"],[new RegExp(\"([^aeiouy]|qu)y$\",\"gi\"),\"$1ies\"],[new RegExp(\"(x|ch|ss|sh)$\",\"gi\"),\"$1es\"],[new RegExp(\"(matr|vert|ind)ix|ex$\",\"gi\"),\"$1ices\"],[new RegExp(\"([m|l])ouse$\",\"gi\"),\"$1ice\"],[new RegExp(\"(quiz)$\",\"gi\"),\"$1zes\"],[new RegExp(\"s$\",\"gi\"),\"s\"],[new RegExp(\"$\",\"gi\"),\"s\"]],singularRules:[[new RegExp(\"(m)en$\",\"gi\"),\"$1an\"],[new RegExp(\"(pe)ople$\",\"gi\"),\"$1rson\"],[new RegExp(\"(child)ren$\",\"gi\"),\"$1\"],[new RegExp(\"([ti])a$\",\"gi\"),\"$1um\"],[new RegExp(\"((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$\",\"gi\"),\"$1$2sis\"],[new RegExp(\"(hive)s$\",\"gi\"),\"$1\"],[new RegExp(\"(tive)s$\",\"gi\"),\"$1\"],[new RegExp(\"(curve)s$\",\"gi\"),\"$1\"],[new RegExp(\"([lr])ves$\",\"gi\"),\"$1f\"],[new RegExp(\"([^fo])ves$\",\"gi\"),\"$1fe\"],[new RegExp(\"([^aeiouy]|qu)ies$\",\"gi\"),\"$1y\"],[new RegExp(\"(s)eries$\",\"gi\"),\"$1eries\"],[new RegExp(\"(m)ovies$\",\"gi\"),\"$1ovie\"],[new RegExp(\"(x|ch|ss|sh)es$\",\"gi\"),\"$1\"],[new RegExp(\"([m|l])ice$\",\"gi\"),\"$1ouse\"],[new RegExp(\"(bus)es$\",\"gi\"),\"$1\"],[new RegExp(\"(o)es$\",\"gi\"),\"$1\"],[new RegExp(\"(shoe)s$\",\"gi\"),\"$1\"],[new RegExp(\"(cris|ax|test)es$\",\"gi\"),\"$1is\"],[new RegExp(\"(octop|vir)i$\",\"gi\"),\"$1us\"],[new RegExp(\"(alias|status)es$\",\"gi\"),\"$1\"],[new RegExp(\"^(ox)en\",\"gi\"),\"$1\"],[new RegExp(\"(vert|ind)ices$\",\"gi\"),\"$1ex\"],[new RegExp(\"(matr)ices$\",\"gi\"),\"$1ix\"],[new RegExp(\"(quiz)zes$\",\"gi\"),\"$1\"],[new RegExp(\"s$\",\"gi\"),\"\"]],nonTitlecasedWords:[\"and\",\"or\",\"nor\",\"a\",\"an\",\"the\",\"so\",\"but\",\"to\",\"of\",\"at\",\"by\",\"from\",\"into\",\"on\",\"onto\",\"off\",\"out\",\"in\",\"over\",\"with\",\"for\"],idSuffix:new RegExp(\"(_ids|_id)$\",\"g\"),underbar:new RegExp(\"_\",\"g\"),spaceOrUnderbar:new RegExp(\"[ _]\",\"g\"),uppercase:new RegExp(\"([A-Z])\",\"g\"),underbarPrefix:new RegExp(\"^_\"),applyRules:function(e,t,r,n){if(n)e=n;else if(!(r.indexOf(e.toLowerCase())>-1))for(var o=0;o>8-s%1*8)){if((r=i.charCodeAt(s+=.75))>255)throw new o;t=t<<8|r}return u}},function(e,t,r){\"use strict\";var n=r(0);function o(e){return encodeURIComponent(e).replace(/%40/gi,\"@\").replace(/%3A/gi,\":\").replace(/%24/g,\"$\").replace(/%2C/gi,\",\").replace(/%20/g,\"+\").replace(/%5B/gi,\"[\").replace(/%5D/gi,\"]\")}e.exports=function(e,t,r){if(!t)return e;var i;if(r)i=r(t);else if(n.isURLSearchParams(t))i=t.toString();else{var u=[];n.forEach(t,function(e,t){null!==e&&void 0!==e&&(n.isArray(e)?t+=\"[]\":e=[e],n.forEach(e,function(e){n.isDate(e)?e=e.toISOString():n.isObject(e)&&(e=JSON.stringify(e)),u.push(o(t)+\"=\"+o(e))}))}),i=u.join(\"&\")}return i&&(e+=(-1===e.indexOf(\"?\")?\"?\":\"&\")+i),e}},function(e,t,r){\"use strict\";e.exports=function(e,t){return t?e.replace(/\\/+$/,\"\")+\"/\"+t.replace(/^\\/+/,\"\"):e}},function(e,t,r){\"use strict\";var n=r(0);e.exports=n.isStandardBrowserEnv()?{write:function(e,t,r,o,i,u){var s=[];s.push(e+\"=\"+encodeURIComponent(t)),n.isNumber(r)&&s.push(\"expires=\"+new Date(r).toGMTString()),n.isString(o)&&s.push(\"path=\"+o),n.isString(i)&&s.push(\"domain=\"+i),!0===u&&s.push(\"secure\"),document.cookie=s.join(\"; \")},read:function(e){var t=document.cookie.match(new RegExp(\"(^|;\\\\s*)(\"+e+\")=([^;]*)\"));return t?decodeURIComponent(t[3]):null},remove:function(e){this.write(e,\"\",Date.now()-864e5)}}:{write:function(){},read:function(){return null},remove:function(){}}},function(e,t,r){\"use strict\";e.exports=function(e){return/^([a-z][a-z\\d\\+\\-\\.]*:)?\\/\\//i.test(e)}},function(e,t,r){\"use strict\";var n=r(0);e.exports=n.isStandardBrowserEnv()?function(){var e,t=/(msie|trident)/i.test(navigator.userAgent),r=document.createElement(\"a\");function o(e){var n=e;return t&&(r.setAttribute(\"href\",n),n=r.href),r.setAttribute(\"href\",n),{href:r.href,protocol:r.protocol?r.protocol.replace(/:$/,\"\"):\"\",host:r.host,search:r.search?r.search.replace(/^\\?/,\"\"):\"\",hash:r.hash?r.hash.replace(/^#/,\"\"):\"\",hostname:r.hostname,port:r.port,pathname:\"/\"===r.pathname.charAt(0)?r.pathname:\"/\"+r.pathname}}return e=o(window.location.href),function(t){var r=n.isString(t)?o(t):t;return r.protocol===e.protocol&&r.host===e.host}}():function(){return!0}},function(e,t,r){\"use strict\";var n=r(0);e.exports=function(e,t){n.forEach(e,function(r,n){n!==t&&n.toUpperCase()===t.toUpperCase()&&(e[t]=r,delete e[n])})}},function(e,t,r){\"use strict\";var n=r(0),o=[\"age\",\"authorization\",\"content-length\",\"content-type\",\"etag\",\"expires\",\"from\",\"host\",\"if-modified-since\",\"if-unmodified-since\",\"last-modified\",\"location\",\"max-forwards\",\"proxy-authorization\",\"referer\",\"retry-after\",\"user-agent\"];e.exports=function(e){var t,r,i,u={};return e?(n.forEach(e.split(\"\\n\"),function(e){if(i=e.indexOf(\":\"),t=n.trim(e.substr(0,i)).toLowerCase(),r=n.trim(e.substr(i+1)),t){if(u[t]&&o.indexOf(t)>=0)return;u[t]=\"set-cookie\"===t?(u[t]?u[t]:[]).concat([r]):u[t]?u[t]+\", \"+r:r}}),u):u}},function(e,t,r){\"use strict\";e.exports=function(e){return function(t){return e.apply(null,t)}}},function(e,t,r){e.exports={default:r(116),__esModule:!0}},function(e,t,r){e.exports={default:r(117),__esModule:!0}},function(e,t,r){e.exports={default:r(118),__esModule:!0}},function(e,t,r){\"use strict\";t.__esModule=!0;var n,o=r(48),i=(n=o)&&n.__esModule?n:{default:n};t.default=function(e){return function(){var t=e.apply(this,arguments);return new i.default(function(e,r){return function n(o,u){try{var s=t[o](u),a=s.value}catch(e){return void r(e)}if(!s.done)return i.default.resolve(a).then(function(e){n(\"next\",e)},function(e){n(\"throw\",e)});e(a)}(\"next\")})}}},function(e,t,r){\"use strict\";t.__esModule=!0;var n,o=r(111),i=(n=o)&&n.__esModule?n:{default:n};t.default=i.default||function(e){for(var t=1;tf;)if((s=a[f++])!=s)return!0}else for(;c>f;f++)if((e||f in a)&&a[f]===r)return e||f||0;return!e&&-1}}},function(e,t,r){var n=r(16),o=r(127),i=r(126),u=r(4),s=r(61),a=r(146),c={},f={};(t=e.exports=function(e,t,r,l,p){var d,h,v,y,g=p?function(){return e}:a(e),m=n(r,l,t?2:1),x=0;if(\"function\"!=typeof g)throw TypeError(e+\" is not iterable!\");if(i(g)){for(d=s(e.length);d>x;x++)if((y=t?m(u(h=e[x])[0],h[1]):m(e[x]))===c||y===f)return y}else for(v=g.call(e);!(h=v.next()).done;)if((y=o(v,m,h.value,t))===c||y===f)return y}).BREAK=c,t.RETURN=f},function(e,t,r){e.exports=!r(5)&&!r(29)(function(){return 7!=Object.defineProperty(r(28)(\"div\"),\"a\",{get:function(){return 7}}).a})},function(e,t){e.exports=function(e,t,r){var n=void 0===r;switch(t.length){case 0:return n?e():e.call(r);case 1:return n?e(t[0]):e.call(r,t[0]);case 2:return n?e(t[0],t[1]):e.call(r,t[0],t[1]);case 3:return n?e(t[0],t[1],t[2]):e.call(r,t[0],t[1],t[2]);case 4:return n?e(t[0],t[1],t[2],t[3]):e.call(r,t[0],t[1],t[2],t[3])}return e.apply(r,t)}},function(e,t,r){var n=r(10),o=r(2)(\"iterator\"),i=Array.prototype;e.exports=function(e){return void 0!==e&&(n.Array===e||i[o]===e)}},function(e,t,r){var n=r(4);e.exports=function(e,t,r,o){try{return o?t(n(r)[0],r[1]):t(r)}catch(t){var i=e.return;throw void 0!==i&&n(i.call(e)),t}}},function(e,t,r){\"use strict\";var n=r(133),o=r(57),i=r(32),u={};r(7)(u,r(2)(\"iterator\"),function(){return this}),e.exports=function(e,t,r){e.prototype=n(u,{next:o(1,r)}),i(e,t+\" Iterator\")}},function(e,t,r){var n=r(2)(\"iterator\"),o=!1;try{var i=[7][n]();i.return=function(){o=!0},Array.from(i,function(){throw 2})}catch(e){}e.exports=function(e,t){if(!t&&!o)return!1;var r=!1;try{var i=[7],u=i[n]();u.next=function(){return{done:r=!0}},i[n]=function(){return u},e(i)}catch(e){}return r}},function(e,t){e.exports=function(e,t){return{value:t,done:!!e}}},function(e,t,r){var n=r(1),o=r(60).set,i=n.MutationObserver||n.WebKitMutationObserver,u=n.process,s=n.Promise,a=\"process\"==r(15)(u);e.exports=function(){var e,t,r,c=function(){var n,o;for(a&&(n=u.domain)&&n.exit();e;){o=e.fn,e=e.next;try{o()}catch(n){throw e?r():t=void 0,n}}t=void 0,n&&n.enter()};if(a)r=function(){u.nextTick(c)};else if(!i||n.navigator&&n.navigator.standalone)if(s&&s.resolve){var f=s.resolve(void 0);r=function(){f.then(c)}}else r=function(){o.call(n,c)};else{var l=!0,p=document.createTextNode(\"\");new i(c).observe(p,{characterData:!0}),r=function(){p.data=l=!l}}return function(n){var o={fn:n,next:void 0};t&&(t.next=o),e||(e=o,r()),t=o}}},function(e,t,r){\"use strict\";var n=r(54),o=r(135),i=r(138),u=r(62),s=r(52),a=Object.assign;e.exports=!a||r(29)(function(){var e={},t={},r=Symbol(),n=\"abcdefghijklmnopqrst\";return e[r]=7,n.split(\"\").forEach(function(e){t[e]=e}),7!=a({},e)[r]||Object.keys(a({},t)).join(\"\")!=n})?function(e,t){for(var r=u(e),a=arguments.length,c=1,f=o.f,l=i.f;a>c;)for(var p,d=s(arguments[c++]),h=f?n(d).concat(f(d)):n(d),v=h.length,y=0;v>y;)l.call(d,p=h[y++])&&(r[p]=d[p]);return r}:a},function(e,t,r){var n=r(4),o=r(134),i=r(50),u=r(33)(\"IE_PROTO\"),s=function(){},a=function(){var e,t=r(28)(\"iframe\"),n=i.length;for(t.style.display=\"none\",r(51).appendChild(t),t.src=\"javascript:\",(e=t.contentWindow.document).open(),e.write(\" 45 | -------------------------------------------------------------------------------- /resources/js/components/FormField.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 158 | -------------------------------------------------------------------------------- /resources/js/field.js: -------------------------------------------------------------------------------- 1 | Nova.booting((Vue, router) => { 2 | Vue.component('detail-nova-dependency-container', require('./components/DetailField')); 3 | Vue.component('form-nova-dependency-container', require('./components/FormField')); 4 | }) 5 | -------------------------------------------------------------------------------- /src/ActionHasDependencies.php: -------------------------------------------------------------------------------- 1 | fields() as $field) { 17 | if ($field instanceof NovaDependencyContainer) { 18 | // do not add any fields for validation if container is not satisfied 19 | if ($field->areDependenciesSatisfied($request)) { 20 | $availableFields[] = $field; 21 | $this->extractChildFields($field->meta['fields']); 22 | } 23 | } else { 24 | $availableFields[] = $field; 25 | } 26 | } 27 | 28 | if ($this->childFieldsArr) { 29 | $availableFields = array_merge($availableFields, $this->childFieldsArr); 30 | } 31 | } 32 | 33 | /** 34 | * Validate action fields. Mostly a copy paste from Nova 35 | * 36 | * Uses the above to validate only on fields that have satisfied dependencies. 37 | * 38 | * @param \Laravel\Nova\Http\Requests\ActionRequest $request 39 | * @return void 40 | */ 41 | public function validateFields(ActionRequest $request) 42 | { 43 | $fields = collect($this->fieldsForValidation($request)); 44 | 45 | return Validator::make( 46 | $request->all(), 47 | $fields->mapWithKeys(function ($field) use ($request) { 48 | return $field->getCreationRules($request); 49 | })->all(), 50 | [], 51 | $fields->reject(function ($field) { 52 | return empty($field->name); 53 | })->mapWithKeys(function ($field) { 54 | return [$field->attribute => $field->name]; 55 | })->all() 56 | )->after(function ($validator) use ($request) { 57 | $this->afterValidation($request, $validator); 58 | })->validate(); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/FieldServiceProvider.php: -------------------------------------------------------------------------------- 1 | bind( 23 | \Laravel\Nova\Http\Controllers\ActionController::class, 24 | \Epartment\NovaDependencyContainer\Http\Controllers\ActionController::class 25 | ); 26 | }); 27 | 28 | Nova::serving(function (ServingNova $event) { 29 | Nova::script('nova-dependency-container', __DIR__.'/../dist/js/field.js'); 30 | }); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/HasChildFields.php: -------------------------------------------------------------------------------- 1 | extractChildFields($childField->meta['fields']); 18 | } else { 19 | if (array_search($childField->attribute, array_column($this->childFieldsArr, 'attribute')) === false) { 20 | // @todo: we should not randomly apply rules to child-fields. 21 | $childField = $this->applyRulesForChildFields($childField); 22 | $this->childFieldsArr[] = $childField; 23 | } 24 | } 25 | } 26 | } 27 | 28 | /** 29 | * @param [array] $childField 30 | * @return [array] $childField 31 | */ 32 | protected function applyRulesForChildFields($childField) 33 | { 34 | if (isset($childField->rules)) { 35 | $childField->rules[] = "sometimes:required:".$childField->attribute; 36 | } 37 | if (isset($childField->creationRules)) { 38 | $childField->creationRules[] = "sometimes:required:".$childField->attribute; 39 | } 40 | if (isset($childField->updateRules)) { 41 | $childField->updateRules[] = "sometimes:required:".$childField->attribute; 42 | } 43 | return $childField; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/HasDependencies.php: -------------------------------------------------------------------------------- 1 | fieldsMethod($request); 21 | 22 | // needs to be filtered once to resolve Panels 23 | $fields = $this->filter($this->{$method}($request)); 24 | $availableFields = []; 25 | 26 | foreach ($fields as $field) { 27 | if ($field instanceof NovaDependencyContainer) { 28 | $availableFields[] = $this->filterFieldForRequest($field, $request); 29 | if ($field->areDependenciesSatisfied($request) || $this->extractableRequest($request, $this->model())) { 30 | if ($this->doesRouteRequireChildFields()) { 31 | $this->extractChildFields($field->meta['fields']); 32 | } 33 | } 34 | } else { 35 | $availableFields[] = $this->filterFieldForRequest($field, $request); 36 | } 37 | } 38 | 39 | if ($this->childFieldsArr) { 40 | $availableFields = array_merge($availableFields, $this->childFieldsArr); 41 | } 42 | 43 | $availableFields = new FieldCollection(array_values($this->filter($availableFields))); 44 | 45 | return $availableFields; 46 | } 47 | 48 | /** 49 | * Check if request needs to extract child fields 50 | * 51 | * @param NovaRequest $request 52 | * @param mixed $model 53 | * @return bool 54 | */ 55 | protected function extractableRequest(NovaRequest $request, $model) 56 | { 57 | // if form was submitted to update (method === 'PUT') 58 | if ($request->isUpdateOrUpdateAttachedRequest() && $request->method() == 'PUT') { 59 | return false; 60 | } 61 | 62 | // if form was submitted to create and new resource 63 | if ($request->isCreateOrAttachRequest() && $model->id === null) { 64 | return false; 65 | } 66 | 67 | return true; 68 | } 69 | 70 | /** 71 | * @param mixed $field 72 | * @param NovaRequest $request 73 | * @return mixed 74 | * 75 | * @todo: implement 76 | */ 77 | public function filterFieldForRequest($field, NovaRequest $request) { 78 | // @todo: filter fields for request, e.g. show/hideOnIndex, create, update or whatever 79 | return $field; 80 | } 81 | 82 | /** 83 | * @return bool 84 | */ 85 | protected function doesRouteRequireChildFields() : bool 86 | { 87 | return Str::endsWith(Route::currentRouteAction(), [ 88 | 'FieldDestroyController@handle', 89 | 'ResourceUpdateController@handle', 90 | 'ResourceStoreController@handle', 91 | 'AssociatableController@index', 92 | 'MorphableController@index', 93 | ]); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/Http/Controllers/ActionController.php: -------------------------------------------------------------------------------- 1 | action()->fields() as $field) { 22 | if ($field instanceof NovaDependencyContainer) { 23 | // do not add any fields for validation if container is not satisfied 24 | if ($field->areDependenciesSatisfied($this)) { 25 | $availableFields[] = $field; 26 | $this->extractChildFields($field->meta['fields']); 27 | } 28 | } else { 29 | $availableFields[] = $field; 30 | } 31 | } 32 | 33 | if ($this->childFieldsArr) { 34 | $availableFields = array_merge($availableFields, $this->childFieldsArr); 35 | } 36 | 37 | $this->validate(collect($availableFields)->mapWithKeys(function ($field) { 38 | return $field->getCreationRules($this); 39 | })->all()); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/NovaDependencyContainer.php: -------------------------------------------------------------------------------- 1 | withMeta(['fields' => $fields]); 36 | $this->withMeta(['dependencies' => []]); 37 | } 38 | 39 | /** 40 | * Adds a dependency 41 | * 42 | * @param $field 43 | * @param $value 44 | * @return $this 45 | */ 46 | public function dependsOn($field, $value) 47 | { 48 | return $this->withMeta([ 49 | 'dependencies' => array_merge($this->meta['dependencies'], [ 50 | $this->getFieldLayout($field, $value) 51 | ]) 52 | ]); 53 | } 54 | 55 | /** 56 | * Adds a dependency for not 57 | * 58 | * @param $field 59 | * @return NovaDependencyContainer 60 | */ 61 | public function dependsOnNot($field, $value) 62 | { 63 | return $this->withMeta([ 64 | 'dependencies' => array_merge($this->meta['dependencies'], [ 65 | array_merge($this->getFieldLayout($field), ['not' => $value]) 66 | ]) 67 | ]); 68 | } 69 | 70 | /** 71 | * Adds a dependency for not empty 72 | * 73 | * @param $field 74 | * @return NovaDependencyContainer 75 | */ 76 | public function dependsOnEmpty($field) 77 | { 78 | return $this->withMeta([ 79 | 'dependencies' => array_merge($this->meta['dependencies'], [ 80 | array_merge($this->getFieldLayout($field), ['empty' => true]) 81 | ]) 82 | ]); 83 | } 84 | 85 | /** 86 | * Adds a dependency for not empty 87 | * 88 | * @param $field 89 | * @return NovaDependencyContainer 90 | */ 91 | public function dependsOnNotEmpty($field) 92 | { 93 | return $this->withMeta([ 94 | 'dependencies' => array_merge($this->meta['dependencies'], [ 95 | array_merge($this->getFieldLayout($field), ['notEmpty' => true]) 96 | ]) 97 | ]); 98 | } 99 | 100 | /** 101 | * Adds a dependency for null or zero (0) 102 | * 103 | * @param $field 104 | * @param $value 105 | * @return $this 106 | */ 107 | public function dependsOnNullOrZero($field) 108 | { 109 | return $this->withMeta([ 110 | 'dependencies' => array_merge($this->meta['dependencies'], [ 111 | array_merge($this->getFieldLayout($field), ['nullOrZero' => true]) 112 | ]) 113 | ]); 114 | } 115 | 116 | /** 117 | * Get layout for a specified field. Dot notation will result in {field}.{property}. If no dot was found it will 118 | * result in {field}.{field}, as it was in previous versions by default. 119 | * 120 | * @param $field 121 | * @param $value 122 | * @return array 123 | */ 124 | protected function getFieldLayout($field, $value = null) 125 | { 126 | if (count( ($field = explode('.', $field)) ) === 1) { 127 | // backwards compatibility, property becomes field 128 | $field[1] = $field[0]; 129 | } 130 | return [ 131 | // literal form input name 132 | 'field' => $field[0], 133 | // property to compare 134 | 'property' => $field[1], 135 | // value to compare 136 | 'value' => $value, 137 | ]; 138 | } 139 | 140 | /** 141 | * Resolve dependency fields for display 142 | * 143 | * @param mixed $resource 144 | * @param null $attribute 145 | */ 146 | public function resolveForDisplay($resource, $attribute = null) 147 | { 148 | foreach ($this->meta['fields'] as $field) { 149 | $field->resolveForDisplay($resource); 150 | } 151 | 152 | foreach ($this->meta['dependencies'] as $index => $dependency) { 153 | 154 | $this->meta['dependencies'][$index]['satisfied'] = false; 155 | 156 | if (array_key_exists('empty', $dependency) && empty($resource->{$dependency['property']})) { 157 | $this->meta['dependencies'][$index]['satisfied'] = true; 158 | continue; 159 | } 160 | // inverted `empty()` 161 | if (array_key_exists('notEmpty', $dependency) && !empty($resource->{$dependency['property']})) { 162 | $this->meta['dependencies'][$index]['satisfied'] = true; 163 | continue; 164 | } 165 | // inverted 166 | if (array_key_exists('nullOrZero', $dependency) && in_array($resource->{$dependency['property']}, [null, 0, '0'], true)) { 167 | $this->meta['dependencies'][$index]['satisfied'] = true; 168 | continue; 169 | } 170 | 171 | if (array_key_exists('not', $dependency) && $resource->{$dependency['property']} != $dependency['not']) { 172 | $this->meta['dependencies'][$index]['satisfied'] = true; 173 | continue; 174 | } 175 | 176 | if (array_key_exists('value', $dependency)) { 177 | if (is_array($resource)) { 178 | if (isset($resource[$dependency['property']]) && $dependency['value'] == $resource[$dependency['property']]) { 179 | $this->meta['dependencies'][$index]['satisfied'] = true; 180 | } 181 | continue; 182 | } elseif ($dependency['value'] == $resource->{$dependency['property']}) { 183 | $this->meta['dependencies'][$index]['satisfied'] = true; 184 | continue; 185 | } 186 | // @todo: quickfix for MorphTo 187 | $morphable_attribute = $resource->getAttribute($dependency['property'].'_type'); 188 | if ($morphable_attribute !== null && Str::endsWith($morphable_attribute, '\\'.$dependency['value'])) { 189 | $this->meta['dependencies'][$index]['satisfied'] = true; 190 | continue; 191 | } 192 | } 193 | 194 | } 195 | } 196 | 197 | /** 198 | * Resolve dependency fields 199 | * 200 | * @param mixed $resource 201 | * @param string $attribute 202 | * @return array|mixed 203 | */ 204 | public function resolve($resource, $attribute = null) 205 | { 206 | foreach ($this->meta['fields'] as $field) { 207 | $field->resolve($resource, $attribute); 208 | } 209 | } 210 | 211 | /** 212 | * Forward fillInto request for each field in this container 213 | * 214 | * @trace fill/fillForAction -> fillInto -> * 215 | * 216 | * @param NovaRequest $request 217 | * @param $model 218 | * @param $attribute 219 | * @param null $requestAttribute 220 | */ 221 | public function fillInto(NovaRequest $request, $model, $attribute, $requestAttribute = null) 222 | { 223 | foreach($this->meta['fields'] as $field) { 224 | $field->fill($request, $model); 225 | } 226 | } 227 | 228 | /** 229 | * Checks whether to add validation rules 230 | * 231 | * @param NovaRequest $request 232 | * @return bool 233 | */ 234 | public function areDependenciesSatisfied(NovaRequest $request) 235 | { 236 | if (!isset($this->meta['dependencies']) 237 | || !is_array($this->meta['dependencies'])) { 238 | return false; 239 | } 240 | 241 | $satisfiedCounts = 0; 242 | foreach ($this->meta['dependencies'] as $index => $dependency) { 243 | 244 | if (array_key_exists('empty', $dependency) && empty($request->has($dependency['property']))) { 245 | $satisfiedCounts++; 246 | } 247 | 248 | if (array_key_exists('notEmpty', $dependency) && !empty($request->has($dependency['property']))) { 249 | $satisfiedCounts++; 250 | } 251 | 252 | // inverted 253 | if (array_key_exists('nullOrZero', $dependency) && in_array($request->get($dependency['property']), [null, 0, '0'], true)) { 254 | $satisfiedCounts++; 255 | } 256 | 257 | if (array_key_exists('not', $dependency) && $dependency['not'] != $request->get($dependency['property'])) { 258 | $satisfiedCounts++; 259 | } 260 | 261 | if (array_key_exists('value', $dependency) && $dependency['value'] == $request->get($dependency['property'])) { 262 | $satisfiedCounts++; 263 | } 264 | } 265 | 266 | return $satisfiedCounts == count($this->meta['dependencies']); 267 | } 268 | 269 | /** 270 | * Get a rule set based on field property name 271 | * 272 | * @param NovaRequest $request 273 | * @param string $propertyName 274 | * @return array 275 | */ 276 | protected function getSituationalRulesSet(NovaRequest $request, string $propertyName = 'rules') 277 | { 278 | $fieldsRules = [$this->attribute => []]; 279 | if (!$this->areDependenciesSatisfied($request) 280 | || !isset($this->meta['fields']) 281 | || !is_array($this->meta['fields'])) { 282 | return $fieldsRules; 283 | } 284 | 285 | /** @var Field $field */ 286 | foreach ($this->meta['fields'] as $field) { 287 | $fieldsRules[$field->attribute] = is_callable($field->{$propertyName}) 288 | ? call_user_func($field->{$propertyName}, $request) 289 | : $field->{$propertyName}; 290 | } 291 | 292 | return $fieldsRules; 293 | } 294 | 295 | /** 296 | * Get the validation rules for this field. 297 | * 298 | * @param NovaRequest $request 299 | * @return array 300 | */ 301 | public function getRules(NovaRequest $request) 302 | { 303 | return $this->getSituationalRulesSet($request); 304 | } 305 | 306 | /** 307 | * Get the creation rules for this field. 308 | * 309 | * @param NovaRequest $request 310 | * @return array|string 311 | */ 312 | public function getCreationRules(NovaRequest $request) 313 | { 314 | $fieldsRules = $this->getSituationalRulesSet($request, 'creationRules'); 315 | 316 | return array_merge_recursive( 317 | $this->getRules($request), 318 | $fieldsRules 319 | ); 320 | } 321 | 322 | /** 323 | * Get the update rules for this field. 324 | * 325 | * @param NovaRequest $request 326 | * @return array 327 | */ 328 | public function getUpdateRules(NovaRequest $request) 329 | { 330 | $fieldsRules = $this->getSituationalRulesSet($request, 'updateRules'); 331 | 332 | return array_merge_recursive( 333 | $this->getRules($request), 334 | $fieldsRules 335 | ); 336 | } 337 | } 338 | -------------------------------------------------------------------------------- /webpack.mix.js: -------------------------------------------------------------------------------- 1 | let mix = require('laravel-mix') 2 | 3 | mix.js('resources/js/field.js', 'dist/js') 4 | .webpackConfig({ 5 | resolve: { 6 | symlinks: false 7 | } 8 | }) 9 | --------------------------------------------------------------------------------