Files
site/nova/resources/js/views/Update.vue

358 lines
9.2 KiB
Vue
Executable File

<template>
<loading-view :loading="loading">
<custom-update-header
class="mb-3"
:resource-name="resourceName"
:resource-id="resourceId"
/>
<form
v-if="panels"
@submit="submitViaUpdateResource"
@change="onUpdateFormStatus"
autocomplete="off"
ref="form"
>
<form-panel
v-for="panel in panelsWithFields"
@update-last-retrieved-at-timestamp="updateLastRetrievedAtTimestamp"
@field-changed="onUpdateFormStatus"
@file-upload-started="handleFileUploadStarted"
@file-upload-finished="handleFileUploadFinished"
:panel="panel"
:name="panel.name"
:key="panel.name"
:resource-id="resourceId"
:resource-name="resourceName"
:fields="panel.fields"
mode="form"
class="mb-8"
:validation-errors="validationErrors"
:via-resource="viaResource"
:via-resource-id="viaResourceId"
:via-relationship="viaRelationship"
/>
<!-- Update Button -->
<div class="flex items-center">
<cancel-button @click="$router.back()" />
<progress-button
class="mr-3"
dusk="update-and-continue-editing-button"
@click.native="submitViaUpdateResourceAndContinueEditing"
:disabled="isWorking"
:processing="wasSubmittedViaUpdateResourceAndContinueEditing"
>
{{ __('Update & Continue Editing') }}
</progress-button>
<progress-button
dusk="update-button"
type="submit"
:disabled="isWorking"
:processing="wasSubmittedViaUpdateResource"
>
{{ updateButtonLabel }}
</progress-button>
</div>
</form>
</loading-view>
</template>
<script>
import {
mapProps,
Errors,
InteractsWithResourceInformation,
PreventsFormAbandonment,
} from 'laravel-nova'
import HandlesUploads from '@/mixins/HandlesUploads'
export default {
mixins: [
InteractsWithResourceInformation,
HandlesUploads,
PreventsFormAbandonment,
],
metaInfo() {
if (this.resourceInformation && this.title) {
return {
title: this.__('Update :resource: :title', {
resource: this.resourceInformation.singularLabel,
title: this.title,
}),
}
}
},
props: mapProps([
'resourceName',
'resourceId',
'viaResource',
'viaResourceId',
'viaRelationship',
]),
data: () => ({
relationResponse: null,
loading: true,
submittedViaUpdateResourceAndContinueEditing: false,
submittedViaUpdateResource: false,
title: null,
fields: [],
panels: [],
validationErrors: new Errors(),
lastRetrievedAt: null,
}),
async created() {
if (Nova.missingResource(this.resourceName))
return this.$router.push({ name: '404' })
// If this update is via a relation index, then let's grab the field
// and use the label for that as the one we use for the title and buttons
if (this.isRelation) {
const { data } = await Nova.request(
`/nova-api/${this.viaResource}/field/${this.viaRelationship}`
)
this.relationResponse = data
}
this.getFields()
this.updateLastRetrievedAtTimestamp()
},
watch: {
$route(to, from) {
if (
from.params.resourceName === to.params.resourceName &&
from.params.resourceId !== to.params.resourceId
) {
this.getFields()
this.validationErrors = new Errors()
this.submittedViaUpdateResource = false
this.submittedViaUpdateResourceAndContinueEditing = false
this.isWorking = false
}
},
},
methods: {
/**
* Get the available fields for the resource.
*/
async getFields() {
this.loading = true
this.panels = []
this.fields = []
const {
data: { title, panels, fields },
} = await Nova.request()
.get(
`/nova-api/${this.resourceName}/${this.resourceId}/update-fields`,
{
params: {
editing: true,
editMode: 'update',
viaResource: this.viaResource,
viaResourceId: this.viaResourceId,
viaRelationship: this.viaRelationship,
},
}
)
.catch(error => {
if (error.response.status == 404) {
this.$router.push({ name: '404' })
return
}
})
this.title = title
this.panels = panels
this.fields = fields
this.loading = false
Nova.$emit('resource-loaded')
},
async submitViaUpdateResource(e) {
e.preventDefault()
this.submittedViaUpdateResource = true
this.submittedViaUpdateResourceAndContinueEditing = false
this.canLeave = true
await this.updateResource()
},
async submitViaUpdateResourceAndContinueEditing() {
this.submittedViaUpdateResourceAndContinueEditing = true
this.submittedViaUpdateResource = false
this.canLeave = true
await this.updateResource()
},
/**
* Update the resource using the provided data.
*/
async updateResource() {
this.isWorking = true
if (this.$refs.form.reportValidity()) {
try {
const {
data: { redirect, id },
} = await this.updateRequest()
Nova.success(
this.__('The :resource was updated!', {
resource: this.resourceInformation.singularLabel.toLowerCase(),
})
)
await this.updateLastRetrievedAtTimestamp()
if (this.submittedViaUpdateResource) {
this.$router.push({ path: redirect }, () => {
window.scrollTo(0, 0)
})
} else {
if (id != this.resourceId) {
this.$router.push({
name: 'edit',
params: {
resourceId: id,
resourceName: this.resourceName,
},
})
} else {
// Reset the form by refetching the fields
this.getFields()
this.validationErrors = new Errors()
this.submittedViaUpdateResource = false
this.submittedViaUpdateResourceAndContinueEditing = false
this.isWorking = false
}
return
}
} catch (error) {
window.scrollTo(0, 0)
this.submittedViaUpdateResource = false
this.submittedViaUpdateResourceAndContinueEditing = false
if (this.resourceInformation.preventFormAbandonment) {
this.canLeave = false
}
if (error.response.status == 422) {
this.validationErrors = new Errors(error.response.data.errors)
Nova.error(this.__('There was a problem submitting the form.'))
}
if (error.response.status == 409) {
Nova.error(
this.__(
'Another user has updated this resource since this page was loaded. Please refresh the page and try again.'
)
)
}
}
}
this.submittedViaUpdateResource = false
this.submittedViaUpdateResourceAndContinueEditing = false
this.isWorking = false
},
/**
* Send an update request for this resource
*/
updateRequest() {
return Nova.request().post(
`/nova-api/${this.resourceName}/${this.resourceId}`,
this.updateResourceFormData,
{
params: {
viaResource: this.viaResource,
viaResourceId: this.viaResourceId,
viaRelationship: this.viaRelationship,
editing: true,
editMode: 'update',
},
}
)
},
/**
* Update the last retrieved at timestamp to the current UNIX timestamp.
*/
updateLastRetrievedAtTimestamp() {
this.lastRetrievedAt = Math.floor(new Date().getTime() / 1000)
},
/**
* Prevent accidental abandonment only if form was changed.
*/
onUpdateFormStatus() {
if (this.resourceInformation.preventFormAbandonment) {
this.updateFormStatus()
}
},
},
computed: {
wasSubmittedViaUpdateResourceAndContinueEditing() {
return this.isWorking && this.submittedViaUpdateResourceAndContinueEditing
},
wasSubmittedViaUpdateResource() {
return this.isWorking && this.submittedViaUpdateResource
},
/**
* Create the form data for creating the resource.
*/
updateResourceFormData() {
return _.tap(new FormData(), formData => {
_(this.fields).each(field => {
field.fill(formData)
})
formData.append('_method', 'PUT')
formData.append('_retrieved_at', this.lastRetrievedAt)
})
},
singularName() {
if (this.relationResponse) {
return this.relationResponse.singularLabel
}
return this.resourceInformation.singularLabel
},
updateButtonLabel() {
return this.resourceInformation.updateButtonLabel
},
isRelation() {
return Boolean(this.viaResourceId && this.viaRelationship)
},
panelsWithFields() {
return _.map(this.panels, panel => {
return {
...panel,
fields: _.filter(this.fields, field => field.panel == panel.name),
}
})
},
},
}
</script>