Skip to content

Commit

Permalink
Add Laravel Nova 4 Support
Browse files Browse the repository at this point in the history
  • Loading branch information
kongulov committed Apr 25, 2022
1 parent 72ce7df commit ad220b3
Show file tree
Hide file tree
Showing 15 changed files with 101 additions and 115 deletions.
5 changes: 3 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@
}
],
"require": {
"php": ">=7.1.0",
"spatie/laravel-translatable": ">=4.0"
"php": "^8.0",
"spatie/laravel-translatable": "^4.0",
"laravel/nova": "^4.0"
},
"autoload": {
"psr-4": {
Expand Down
2 changes: 1 addition & 1 deletion dist/css/field.css

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion dist/js/field.js

Large diffs are not rendered by default.

14 changes: 14 additions & 0 deletions dist/js/field.js.LICENSE.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/*!
* vuex v4.0.2
* (c) 2021 Evan You
* @license MIT
*/

/**
* @license
* Lodash <https://lodash.com/>
* Copyright OpenJS Foundation and other contributors <https://openjsf.org/>
* Released under MIT license <https://lodash.com/license>
* Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
* Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
*/
2 changes: 1 addition & 1 deletion dist/mix-manifest.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"/js/field.js": "/js/field.js",
"/css/field.css": "/css/field.css"
}
}
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())
27 changes: 16 additions & 11 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,24 @@
"private": true,
"scripts": {
"dev": "npm run development",
"development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --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 --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"
"production": "mix --production",
"nova:install": "npm --prefix='../../vendor/laravel/nova' ci"
},
"devDependencies": {
"cross-env": "^5.0.0",
"laravel-mix": "^1.0",
"laravel-nova": "^1.0"
"@vue/compiler-sfc": "^3.2.22",
"form-backend-validation": "^2.3.3",
"laravel-mix": "^6.0.41",
"lodash": "^4.17.21",
"postcss": "^8.3.11",
"resolve-url-loader": "^5.0.0",
"sass": "^1.50.1",
"sass-loader": "^12.6.0",
"vue-loader": "^16.8.3"
},
"dependencies": {
"vue": "^2.5.0"
}
"dependencies": {}
}
1 change: 0 additions & 1 deletion resources/js/components/DetailField.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
<div v-for="(component, index) in field.fields" v-show="selectedLang === component.locale && component.showOnDetail">
<component
:key="index"
:data-default="true"
:class="{'remove-bottom-border ': (index + 1) % field.originalFieldsCount !== 0}"
:is="resolveComponentName(component)"
:resource-name="resourceName"
Expand Down
5 changes: 2 additions & 3 deletions resources/js/components/FormField.vue
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
v-show="selectedLang === component.locale && checkVisibility(component)">
<component
:key="index"
:data-default="true"
:class="{'remove-bottom-border ': (index + 1) % field.originalFieldsCount !== 0}"
:is="resolveComponentName(component)"
:resource-name="resourceName"
Expand All @@ -34,11 +33,11 @@
</template>

<script>
import {FormField, HandlesValidationErrors, InteractsWithResourceInformation} from 'laravel-nova';
import {FormField, HandlesValidationErrors} from 'laravel-nova';
import IndexMixin from '../mixins/index'
export default {
mixins: [FormField, HandlesValidationErrors, InteractsWithResourceInformation, IndexMixin],
mixins: [FormField, HandlesValidationErrors, IndexMixin],
props: ['field', 'resourceId', 'resourceName', 'errors', 'viaResource', 'viaRelationship', 'viaResourceId'],
Expand Down
2 changes: 1 addition & 1 deletion resources/js/components/IndexField.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<div class="nova-tab-translatable-index w-full">
<div class="tab-items px-8">
<span class="tab-item" v-for="lang in field.languages"
:class="{'active':selectedLang === lang}" @click="switchLanguage(lang)">
:class="{'active':selectedLang === lang}" @click.stop="switchLanguage(lang)">
{{ lang }}
</span>
</div>
Expand Down
92 changes: 8 additions & 84 deletions resources/js/field.js
Original file line number Diff line number Diff line change
@@ -1,87 +1,11 @@
import {Errors} from "laravel-nova";
//import {Errors} from "laravel-nova";

Nova.booting((Vue, router, store) => {
Vue.component('index-nova-tab-translatable', require('./components/IndexField'))
Vue.component('detail-nova-tab-translatable', require('./components/DetailField'))
Vue.component('form-nova-tab-translatable', require('./components/FormField'))
import IndexField from './components/IndexField'
import DetailField from './components/DetailField'
import FormField from './components/FormField'

const BaseFormFileField = Vue.options.components["form-file-field"];
const CustomFormFileField = BaseFormFileField.extend({
props: [
'resourceId',
'relatedResourceName',
'relatedResourceId',
'viaRelationship',
'dataDefault',
],
methods: {
async removeFile() {
this.uploadErrors = new Errors()

const {
resourceName,
resourceId,
relatedResourceName,
relatedResourceId,
viaRelationship,
} = this
const attribute = this.field.attribute

var uri =
this.viaRelationship &&
this.relatedResourceName &&
this.relatedResourceId
? `/nova-api/kongulov/nova-tab-translatable/${resourceName}/${resourceId}/${relatedResourceName}/${relatedResourceId}/field/${attribute}?viaRelationship=${viaRelationship}`
: `/nova-api/kongulov/nova-tab-translatable/${resourceName}/${resourceId}/field/${attribute}`

if (!this.dataDefault){
uri =
this.viaRelationship &&
this.relatedResourceName &&
this.relatedResourceId
? `/nova-api/${resourceName}/${resourceId}/${relatedResourceName}/${relatedResourceId}/field/${attribute}?viaRelationship=${viaRelationship}`
: `/nova-api/${resourceName}/${resourceId}/field/${attribute}`
}

try {
await Nova.request().delete(uri)
this.closeRemoveModal()
this.deleted = true
this.$emit('file-deleted')
Nova.success(this.__('The file was deleted!'))
} catch (error) {
this.closeRemoveModal()

if (error.response.status == 422) {
this.uploadErrors = new Errors(error.response.data.errors)
}
}
},
}
})
Vue.component('form-file-field', CustomFormFileField)

const BaseDetailFileField = Vue.options.components["detail-file-field"];
const CustomDetailFileField = BaseDetailFileField.extend({
props: ['resource', 'resourceName', 'resourceId', 'field', 'dataDefault'],
methods: {
download() {
const { resourceName, resourceId } = this
const attribute = this.field.attribute

let link = document.createElement('a')

link.href = `/nova-api/kongulov/nova-tab-translatable/${resourceName}/${resourceId}/download/${attribute}`
if (!this.dataDefault) {
link.href = `/nova-api/${resourceName}/${resourceId}/download/${attribute}`
}

link.download = 'download'
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
},
}
})
Vue.component('detail-file-field', CustomDetailFileField)
Nova.booting((app, Vue, router, store) => {
app.component('index-nova-tab-translatable', IndexField)
app.component('detail-nova-tab-translatable', DetailField)
app.component('form-nova-tab-translatable', FormField)
})
6 changes: 3 additions & 3 deletions routes/api.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@
use Illuminate\Support\Facades\Route;

// Fields...
Route::get('/{resource}/{resourceId}/download/{field}', 'FieldDownloadController@show');
Route::delete('/{resource}/{resourceId}/field/{field}', 'FieldDestroyController@handle');
Route::delete('/{resource}/{resourceId}/{relatedResource}/{relatedResourceId}/field/{field}', 'PivotFieldDestroyController@handle');
Route::get('/nova-api/{resource}/{resourceId}/download/{field}', 'FieldDownloadController@show')->where('field', 'translations_(.*)_(.*)');
Route::delete('/nova-api/{resource}/{resourceId}/field/{field}', 'FieldDestroyController@handle')->where('field', 'translations_(.*)_(.*)');
Route::delete('/nova-api/{resource}/{resourceId}/{relatedResource}/{relatedResourceId}/field/{field}', 'PivotFieldDestroyController@handle')->where('field', 'translations_(.*)_(.*)');
3 changes: 0 additions & 3 deletions src/FieldServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,7 @@ protected function routes()
return;
}



Route::middleware(['nova'])
->prefix('nova-api/kongulov/nova-tab-translatable')
->namespace('Kongulov\NovaTabTranslatable\Http\Controllers')
->group(__DIR__.'/../routes/api.php');
}
Expand Down
3 changes: 2 additions & 1 deletion src/NovaTabTranslatable.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use Laravel\Nova\Fields\Field;
use Laravel\Nova\Fields\File;
use Laravel\Nova\Fields\Image;
use Laravel\Nova\Fields\Slug;
use Laravel\Nova\Http\Requests\NovaRequest;
Expand Down Expand Up @@ -122,7 +123,7 @@ protected function createTranslatedField(Field $originalField, string $locale):
return $model->translations[$originalAttribute][$locale] ?? '';
});

if ($originalField instanceof Image){
if ($originalField instanceof Image || $originalField instanceof File){
$translatedField
->store(function ($request, $model, $attribute, $requestAttribute) use ($locale, $originalAttribute, $translatedField) {
$file = $request->file($requestAttribute)->store($translatedField->getStorageDir(), $translatedField->getStorageDisk());
Expand Down
11 changes: 8 additions & 3 deletions webpack.mix.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
let mix = require('laravel-mix')
let path = require('path')

require('./nova.mix')

mix
.setPublicPath('dist')
.js('resources/js/field.js', 'js')
.sass('resources/sass/field.scss', 'css')
.setPublicPath('dist')
.js('resources/js/field.js', 'js')
.vue({ version: 3 })
.sass('resources/sass/field.scss', 'css')
.nova('kongulov/nova-tab-translatable')

0 comments on commit ad220b3

Please sign in to comment.