Skip to content

Commit

Permalink
nova 4 support
Browse files Browse the repository at this point in the history
  • Loading branch information
Benjacho committed Feb 24, 2023
1 parent 8b51d07 commit 443cdeb
Show file tree
Hide file tree
Showing 13 changed files with 2,337 additions and 2,262 deletions.
20 changes: 19 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
# Belongs To Many Field Nova With Dependant

Belongs To Many field to represent many to many relationship in field. This Field allow attaching relationships easily.
Belongs To Many field to represent a many to many relationship in just a field. This field allow attaching relationships easily.

- Use version 3 for Nova 4
- Use version 2 for Nova 3

Also you can:

- Pass query to the multiple select
Expand Down Expand Up @@ -145,3 +149,17 @@ This package come with the following translation for the vue-multiselect plugin.
To translate validations use Laravel validation translations.

Credits to: https://github.com/manmohanjit/nova-belongs-to-dependency


### TODO

This project was my first Open Source project, so I wanted to add a roadmap.

I migrated this package to use Nova 4, this migration considered only the detail, index and form views. It means that it can have bugs with other features.

- Add Tests to the Project, adding test will add a certain level of quality code. Also it will help to achieve the other features.
- Test all functions implemented and improve wiki.
- Implement native dependability from Nova, this considers only to have dependsOn a BelongsTo field
- Implement translations with Spatie Translatable to es, fr, de
- Support for inline creation via native Nova 4
- builtin theme inherited from nova theme
11 changes: 9 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,15 @@
"Many to Many Field"
],
"license": "MIT",
"require": {
"php": ">=7.1.0"
"authors": [
{
"name": "Benjamin Flores",
"email": "[email protected]",
"homepage": "https://github.com/Benjacho"
}
],
"require": {
"php": "^8.1"
},
"autoload": {
"psr-4": {
Expand Down
2 changes: 1 addition & 1 deletion dist/js/field.js

Large diffs are not rendered by default.

7 changes: 3 additions & 4 deletions dist/js/field.js.LICENSE.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
/*!
* Determine if an object is a Buffer
*
* @author Feross Aboukhadijeh <https://feross.org>
* @license MIT
* vuex v4.0.2
* (c) 2021 Evan You
* @license MIT
*/

/**
Expand Down
40 changes: 40 additions & 0 deletions nova.mix.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
const mix = require('laravel-mix')
const webpack = require('webpack')
const path = require('path')

class NovaExtension {
name() {
return 'nova-extension'
}

register(name) {
this.name = name
}

webpackPlugins() {
return new webpack.ProvidePlugin({
_: 'lodash',
Errors: 'form-backend-validation',
})
}

webpackConfig(webpackConfig) {
webpackConfig.externals = {
vue: 'Vue',
}

webpackConfig.resolve.alias = {
...(webpackConfig.resolve.alias || {}),
'laravel-nova': path.join(
__dirname,
'../../vendor/laravel/nova/resources/js/mixins/packages.js'
),
}

webpackConfig.output = {
uniqueName: this.name,
}
}
}

mix.extend('nova', new NovaExtension())
22 changes: 11 additions & 11 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,26 @@
"private": true,
"scripts": {
"dev": "npm run development",
"development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --config=node_modules/laravel-mix/setup/webpack.config.js",
"watch": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --watch --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
"watch-poll": "npm run watch -- --watch-poll",
"hot": "cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js",
"development": "mix",
"watch": "mix watch",
"watch-poll": "mix watch -- --watch-options-poll=1000",
"hot": "mix watch --hot",
"prod": "npm run production",
"production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --progress --config=node_modules/laravel-mix/setup/webpack.config.js"
"production": "mix --production",
"nova:install": "npm --prefix='../../vendor/laravel/nova' ci"
},
"devDependencies": {
"@vue/compiler-sfc": "^3.2.22",
"cross-env": "^7.0.3",
"form-backend-validation": "^2.3.3",
"laravel-mix": "^6.0",
"laravel-nova": "^1.12",
"resolve-url-loader": "^4.0.0",
"lodash": "^4.17.21",
"sass": "^1.38.0",
"sass-loader": "^12.1.0",
"vue-loader": "^15.9.7",
"vue-template-compiler": "^2.6.14"
"vue-loader": "^16.8.3"
},
"dependencies": {
"lodash.get": "^4.4.2",
"vue": "^2.6.14",
"vue-multiselect": "^2.1.6"
"vue-multiselect": "^3.0.0-beta.1"
}
}
48 changes: 16 additions & 32 deletions resources/js/components/DetailField.vue
Original file line number Diff line number Diff line change
@@ -1,64 +1,48 @@
<template>
<panel-item :field="field">
<div slot="value">
<PanelItem :field="field" :index="index">
<template #value>
<div v-if="field.showAsList">
<div class="relative rounded-lg bg-white shadow border border-60">
<div class="overflow-hidden rounded-b-lg rounded-t-lg">
<div class="border-b border-50 cursor-text font-mono text-sm py-2 px-4"
v-for="(resource, key) in field.value"
:key="key">
<router-link
:to="{
name: 'detail',
params: {
resourceName: field.resourceNameRelationship,
resourceId: resource.id,
},
}"
class="no-underline dim text-primary font-bold"
<Link
@click.stop
:href="$url(`/resources/${field.resourceNameRelationship}/${resource.id}`)"
class="link-default"
v-if="field.viewable"
>{{get(resource, field.optionsLabel)}}
</router-link>
</Link>
<span v-else>{{get(resource, field.optionsLabel)}}</span>
</div>
</div>
</div>
</div>
<div v-else>
<span v-for="(resource, key) in field.value" class="single">
<router-link
:to="{
name: 'detail',
params: {
resourceName: field.resourceNameRelationship,
resourceId: resource.id,
},
}"
class="no-underline dim text-primary font-bold"
<Link
@click.stop
:href="$url(`/resources/${field.resourceNameRelationship}/${resource.id}`)"
class="link-default"
v-if="field.viewable"
>{{get(resource, field.optionsLabel)}}</router-link>
>{{get(resource, field.optionsLabel)}}</Link>
<span v-else>{{get(resource, field.optionsLabel)}}</span>
</span>
</div>
</div>
</panel-item>
</template>
</PanelItem>
</template>

<script>
import get from 'lodash.get'
export default {
props: ["resource", "resourceName", "resourceId", "field"],
props: ["index", "resource", "resourceName", "resourceId", "field"],
methods: {
get(object, path, defaultValue) {
return get(object, path, defaultValue);
return _.get(object, path, defaultValue);
}
},
mounted() {
if (this.field.showAsList) {
console.log(this.field)
}
}
};
</script>

Expand Down
26 changes: 16 additions & 10 deletions resources/js/components/FormField.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template>
<default-field :field="field" :errors="errors" :show-help-text="true">
<template slot="field">
<DefaultField :field="field" :errors="errors" :show-help-text="true">
<template #field>
<div
:style="{ height: field.height ? field.height : 'auto' }"
class="relative"
Expand All @@ -9,7 +9,7 @@
v-if="loading"
class="py-6 px-8 flex justify-center items-center absolute pin z-50 bg-white"
>
<loader class="text-60" />
<Loader class="text-60" />
</div>
<div v-if="this.field.selectAll" class="mb-2">
<input
Expand All @@ -21,7 +21,7 @@
<label for="checkbox">{{ this.field.messageSelectAll }}</label>
</div>
<!-- <label v-if="this.field.selectAll"><input type="checkbox" class="checkbox mb-2 mr-2">{{this.field.messageSelectAll}}</label>-->
<multi-select
<MultiSelect
ref="multiselect"
@open="() => repositionDropdown(true)"
:options="options"
Expand All @@ -34,16 +34,15 @@
<template slot="noResult">{{
field.multiselectSlots.noResult
}}</template>
</multi-select>
</MultiSelect>
</div>
</template>
</default-field>
</DefaultField>
</template>

<script>
import { FormField, HandlesValidationErrors } from "laravel-nova";
import MultiSelect from "vue-multiselect";
import get from "lodash.get";
export default {
mixins: [FormField, HandlesValidationErrors],
Expand Down Expand Up @@ -82,7 +81,7 @@ export default {
multiSelectProps() {
return {
multiple: true,
customLabel: (el) => get(el, this.optionsLabel),
customLabel: (el) => _.get(el, this.optionsLabel),
trackBy: this.trackBy,
preselectFirst: false,
class: this.errorClasses,
Expand Down Expand Up @@ -175,7 +174,7 @@ export default {
this.trackBy = this.field.trackBy ? this.field.trackBy : "id";
this.value = this.field.value.map((el) => ({
...el,
[this.optionsLabel]: get(el, this.optionsLabel),
[this.optionsLabel]: _.get(el, this.optionsLabel),
}));
this.fetchOptions();
},
Expand Down Expand Up @@ -245,8 +244,15 @@ export default {
};
</script>

<style src="vue-multiselect/dist/vue-multiselect.min.css"></style>
<style src="vue-multiselect/dist/vue-multiselect.css"></style>
<style type="text/css">
.multiselect{
justify-content: normal !important;
}
.multiselect__tags{
border:none !important;
}
.multiselect__placeholder {
font-size: 1rem;
color: var(--70) !important;
Expand Down
21 changes: 8 additions & 13 deletions resources/js/components/IndexField.vue
Original file line number Diff line number Diff line change
@@ -1,31 +1,26 @@
<template>
<div>
<span v-for="(resource, key) in field.value" class="single">
<router-link
:to="{
name: 'detail',
params: {
resourceName: field.resourceNameRelationship,
resourceId: resource.id,
},
}"
class="no-underline dim text-primary font-bold"
<Link
@click.stop
:href="$url(`/resources/${field.resourceNameRelationship}/${resource.id}`)"
class="link-default"
v-if="field.viewable"
>{{ get(resource, field.optionsLabel) }}</router-link
>
>
{{ get(resource, field.optionsLabel) }}
</Link>
<span v-else>{{ get(resource, field.optionsLabel) }}</span>
</span>
</div>
</template>

<script>
import get from "lodash.get";
export default {
name: "IndexField",
props: ["resourceName", "field"],
methods: {
get(object, path, defaultValue) {
return get(object, path, defaultValue);
return _.get(object, path, defaultValue);
},
},
};
Expand Down
9 changes: 4 additions & 5 deletions resources/js/field.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import IndexField from "./components/IndexField";
import DetailField from "./components/DetailField";
import FormField from "./components/FormField";

Nova.booting((Vue, router, store) => {
Vue.component("index-BelongsToManyField", IndexField);
Vue.component("detail-BelongsToManyField", DetailField);
Vue.component("form-BelongsToManyField", FormField);
Nova.booting((app, router, store) => {
app.component("index-BelongsToManyField", IndexField);
app.component("detail-BelongsToManyField", DetailField);
app.component("form-BelongsToManyField", FormField);
});
3 changes: 2 additions & 1 deletion src/BelongsToManyField.php
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ public function resolve($resource, $attribute = null)
}
}

public function jsonSerialize()
public function jsonSerialize() : array
{
$this->resolveOptions();

Expand All @@ -204,6 +204,7 @@ public function jsonSerialize()
'textAlign' => $this->textAlign,
'value' => $this->value,
'viewable' => $this->viewable,
'visible' => $this->visible,
'validationKey' => $this->validationKey(),
], $this->meta());
}
Expand Down
11 changes: 7 additions & 4 deletions webpack.mix.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
let mix = require("laravel-mix");

require('./nova.mix')

mix
.setPublicPath("dist")
.js("resources/js/field.js", "js")
.vue()
.sass("resources/sass/field.scss", "css");
.setPublicPath("dist")
.js("resources/js/field.js", "js")
.vue({version: 3})
.sass("resources/sass/field.scss", "css")
.nova('benjacho/belongs-to-many-field-nova');
Loading

0 comments on commit 443cdeb

Please sign in to comment.