Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix the compatibility issues with nova v4.32+ #96

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion dist/js/card.js

Large diffs are not rendered by default.

14 changes: 7 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,16 @@
"scripts": {
"watch": "mix watch",
"production": "mix --production",
"nova:install": "npm --prefix='../vendor/laravel/nova' ci"
"nova:install": "npm --prefix='../../vendor/laravel/nova' ci"
},
"devDependencies": {
"@vue/compiler-sfc": "^3.3.4",
"@vue/compiler-sfc": "^3.4.15",
"laravel-mix": "^6.0.49",
"mix-tailwindcss": "^1.3.0",
"sass": "^1.68.0",
"sass-loader": "^13.3.2",
"tailwindcss": "^3.3.3",
"vue-collapsed": "^1.2.8",
"vue-loader": "^17.2.2"
"sass": "^1.70.0",
"sass-loader": "^14.1.0",
"tailwindcss": "^3.4.1",
"vue-collapsed": "^1.3.0",
"vue-loader": "^17.4.2"
}
}
6 changes: 3 additions & 3 deletions resources/js/card.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import MegaFilterCard from './components/MegaFilterCard.vue'
import { registerMixin } from './components/MegaFilter'
import { resetComputed } from './components/MegaFilter'

Nova.booting(app => {

const componentFn = app.component

app.component = function (name, component) {

if (name === 'FilterMenu') {
registerMixin(component)
if (name === 'ResourceTableToolbar') {
resetComputed(component)
}

return componentFn.call(this, name, component)
Expand Down
43 changes: 24 additions & 19 deletions resources/js/components/MegaFilter.js
Original file line number Diff line number Diff line change
@@ -1,40 +1,45 @@
import reduce from 'lodash/reduce'

export function filtersAreApplied(store, resourceName, filterFunction) {
function withoutMegaFilter(filter) {
return filter.megaFilter !== true
}

export function megaFilterOnly(filter) {
return filter.megaFilter === true
}

const filters = store.getters[ `${ resourceName }/filters` ].filter(filterFunction)
export function filtered(store, resource, callback) {
return store.getters[ `${ resource }/filters` ].filter(callback)
}

export function activeFilterCount(store, resource, filters) {

return reduce(filters, (result, filter) => {
const originalFilter = store.getters[ `${ resourceName }/getOriginalFilter` ](filter.class)

const originalFilter = store.getters[ `${ resource }/getOriginalFilter` ](filter.class)
const originalFilterCloneValue = JSON.stringify(originalFilter.currentValue)
const currentFilterCloneValue = JSON.stringify(filter.currentValue)
return currentFilterCloneValue === originalFilterCloneValue ? result : result + 1
}, 0)

}
return currentFilterCloneValue === originalFilterCloneValue
? result
: result + 1

export function withoutMegaFilter(filter) {
return filter.megaFilter !== true
}
}, 0)

export function megaFilterOnly(filter) {
return filter.megaFilter === true
}

export function registerMixin(component) {

const filters = component.computed.filters
export function resetComputed(component) {

component.computed.filters = function () {
return filters.call(this).filter(withoutMegaFilter)
}

component.computed.activeFilterCount = function () {
return filtersAreApplied(this.$store, this.resourceName, withoutMegaFilter)
return filtered(this.$store, this.resourceName, withoutMegaFilter)
}

component.computed.filtersAreApplied = function () {
return this.activeFilterCount > 0
}

component.computed.activeFilterCount = function () {
return activeFilterCount(this.$store, this.resourceName, this.filters)
}

}
63 changes: 19 additions & 44 deletions resources/js/components/MegaFilter.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,21 @@

<Card class="nova-mega-filter rounded p-1 overflow-hidden transition"
:style="{ '--columns-desktop': columns || 2 }"
:class="{ '--active': filtersAreApplied, '': !filtersAreApplied, '--expanded': collapsed }">
:class="{ '--active': filtersAreApplied, '--expanded': collapsed }">

<div :class="{ 'h-8': collapsed, 'h-14': !collapsed }"
class="w-full transition-all flex items-center flex cursor-pointer">
class="w-full transition-all flex items-center cursor-pointer">

<div class="toolbar-button pr-2 md:pr-3 flex flex-1 justify-between filter__header">

<button
v-if="!filtersAreApplied"
class="pb-1 pt-2 w-full block text-xs uppercase tracking-wide text-center font-bold focus:outline-none relative flex justify-end items-center"
class="pb-1 pt-2 w-full text-xs uppercase tracking-wide text-center font-bold focus:outline-none relative flex justify-end items-center"
@click="collapsed = !collapsed">

<div>
{{ __('Filters') }}
</div>
<span>
{{ label ?? __('Filters') }}
</span>

<Icon type="chevron-down" width="14" class="ml-1 transition-all"
:class="{ 'rotate-180': collapsed }"/>
Expand Down Expand Up @@ -85,60 +85,35 @@

<script>

import Filterable from '@/mixins/Filterable'
import InteractsWithQueryString from '@/mixins/InteractsWithQueryString'
import { Collapse } from 'vue-collapsed'
import { filtersAreApplied, megaFilterOnly } from './MegaFilter'

export default {
name: 'MegaFilter',
components: { Collapse },
mixins: [ Filterable, InteractsWithQueryString ],
emits: [ 'filter-changed' ],
props: [
'filters',
'columns',
'resourceName',
'viaResource',
'viaResourceId',
'viaRelationship',
emits: [
'filter-changed',
'clear-selected-filters',
],
props: {
filtersAreApplied: Boolean,
filters: Array,
columns: Number,
label: String,
resourceName: String,
lens: { type: String, default: '' },
},
data() {
return {
collapsed: false,
}
},
methods: {
clearFilters() {

this.clearSelectedFilters()

Nova.$emit('refresh-resources')

this.$emit('clear-selected-filters')
},
onChange() {

this.filterChanged()

Nova.$emit('refresh-resources')

},
},
computed: {
filtersAreApplied() {
return filtersAreApplied(this.$store, this.resourceName, megaFilterOnly)
this.$emit('filter-changed')
},
initialEncodedFilters() {
return this.queryStringParams[ this.filterParameter ] || ''
},
pageParameter() {
return this.viaRelationship
? this.viaRelationship + '_page'
: this.resourceName + '_page'
},
},
async created() {
await this.initializeState()
},
beforeMount() {
this.collapsed = this.filtersAreApplied
Expand Down
36 changes: 23 additions & 13 deletions resources/js/components/MegaFilterCard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,38 +3,48 @@
<MegaFilter
class="nova-mega-filter"
:lens="lens"
:filters="card.filters"
:filters="filters"
:columns="card.columns"
:label="card.label"
:resource-name="resourceName"
:via-resource="viaResource"
:via-resource-id="viaResourceId"
:via-relationship="viaRelationship"
:filters-are-applied="filtersAreApplied"
@filter-changed="filterChanged"
@clear-selected-filters="clearSelectedFilters(lens || null)"
/>

</template>

<script>

import Filterable from '@/mixins/Filterable'
import InteractsWithQueryString from '@/mixins/InteractsWithQueryString'
import MegaFilter from './MegaFilter.vue'
import { activeFilterCount, filtered, megaFilterOnly } from './MegaFilter'

export default {
name: 'MegaFilterCard',
components: { MegaFilter },
mixins: [ Filterable, InteractsWithQueryString ],
props: [
'card',
'lens',
'resourceName',
'viaResource',
'viaResourceId',
'viaRelationship',
],
computed: {
filters() {
return filtered(this.$store, this.resourceName, megaFilterOnly).filter(
filter => this.card.filters.includes(filter.class),
)
},
filtersAreApplied() {
return activeFilterCount(this.$store, this.resourceName, this.filters) > 0
},
initialEncodedFilters() {
return this.queryStringParams[ this.filterParameter ] || ''
},
},
created() {

const standardFilters = this.$store.getters[ `${ this.resourceName }/originalFilters` ]
const merged = standardFilters.concat(this.card.filters.map(filter => ({ ...filter, megaFilter: true })))

this.$store.commit(`${ this.resourceName }/storeFilters`, merged)

this.initializeState(this.lens || null)
},
}

Expand Down
47 changes: 30 additions & 17 deletions src/MegaFilter.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,40 +5,53 @@
namespace DigitalCreative\MegaFilter;

use Illuminate\Http\Resources\MergeValue;
use Laravel\Nova\Http\Controllers\FilterController;
use Laravel\Nova\Http\Controllers\LensFilterController;
use Laravel\Nova\Filters\Filter;
use Laravel\Nova\Http\Requests\CardRequest;
use Laravel\Nova\Http\Requests\NovaRequest;
use Laravel\Nova\Makeable;
use Laravel\Nova\Metable;

class MegaFilter extends MergeValue
{
use Makeable;
use Metable;
use Makeable, Metable;

public function __construct(array $data)
public function __construct(array $filters)
{
$controller = $this->request()->route()->getControllerClass();
parent::__construct(match (true) {
$this->isCardRequest() => $this->toFilterWrapper($filters),
default => $this->addFlagToFilters($filters),
});
}

if (in_array($controller, [ FilterController::class, LensFilterController::class ])) {
$data = [];
}
public function columns(int $columns): self
{
return $this->withMeta([ 'columns' => $columns ]);
}

if ($this->request() instanceof CardRequest) {
$data = [ new MegaFilterFilterWrapper($this, $data) ];
}
public function label(string $label): self
{
return $this->withMeta([ 'label' => $label ]);
}

parent::__construct($data);
private function isCardRequest(): bool
{
return resolve(NovaRequest::class) instanceof CardRequest;
}

public function columns(int $columns): self
private function toFilterWrapper(array $filters): array
{
return $this->withMeta([ 'columns' => $columns ]);
return [
new MegaFilterFilterWrapper(
megaFilter: $this,
filters: collect($filters)->map(fn (Filter $filter) => $filter::class)->toArray(),
),
];
}

private function request(): NovaRequest
private function addFlagToFilters(array $filters): array
{
return resolve(NovaRequest::class);
return collect($filters)
->map(fn (Filter $filter) => $filter->withMeta([ 'megaFilter' => true ]))
->all();
}
}
2 changes: 1 addition & 1 deletion src/MegaFilterCard.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public function component(): string
return 'mega-filter-card';
}

public function addFilters(array $filters): self
public function filters(array $filters): self
{
return $this->withMeta([ 'filters' => $filters ]);
}
Expand Down
6 changes: 3 additions & 3 deletions src/MegaFilterFilterWrapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,16 @@
class MegaFilterFilterWrapper
{
public function __construct(
private readonly MegaFilter $megaFilter,
private readonly array $filters,
private MegaFilter $megaFilter,
private array $filters,
)
{
}

public function toCard(): MegaFilterCard
{
return MegaFilterCard::make()
->addFilters($this->filters)
->filters($this->filters)
->withMeta($this->megaFilter->meta());
}
}
Loading