@afeefa/vue-app 0.0.61 → 0.0.62
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.afeefa/package/release/version.txt +1 -1
- package/package.json +1 -1
- package/src/api-resources/ApiAction.js +87 -0
- package/src/api-resources/ApiActions2.js +13 -0
- package/src/api-resources/DeleteAction.js +21 -0
- package/src/api-resources/GetAction.js +18 -0
- package/src/api-resources/ListAction.js +27 -0
- package/src/api-resources/SaveAction.js +15 -0
- package/src/components/ASearchSelect.vue +2 -2
- package/src/components/form/EditForm.vue +29 -8
- package/src/components/form/FormFieldMixin.js +1 -1
- package/src/components/list/ListViewMixin.js +2 -2
- package/src-admin/components/app/AppBarButton.vue +10 -2
- package/src-admin/components/controls/SearchSelectFormField.vue +1 -1
- package/src-admin/components/form/EditFormButtons.vue +38 -0
- package/src-admin/components/form/RemoveButton.vue +71 -0
- package/src-admin/components/index.js +5 -1
- package/src-admin/components/pages/EditPage.vue +40 -136
- package/src-admin/components/routes/DataRouteMixin.js +75 -0
- package/src-admin/models/Model.js +3 -3
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.62
|
package/package.json
CHANGED
@@ -0,0 +1,87 @@
|
|
1
|
+
import { AlertEvent, LoadingEvent } from '@a-vue/events'
|
2
|
+
import { eventBus } from '@a-vue/plugins/event-bus/EventBus'
|
3
|
+
import { sleep } from '@a-vue/utils/timeout'
|
4
|
+
import { ApiAction as ApiResourcesApiAction } from '@afeefa/api-resources-client'
|
5
|
+
|
6
|
+
import { SaveEvent } from '../events'
|
7
|
+
|
8
|
+
export class ApiAction extends ApiResourcesApiAction {
|
9
|
+
_dispatchGlobalLoadingEvents = false
|
10
|
+
_dispatchGlobalSaveEvents = false
|
11
|
+
_minDuration = 100
|
12
|
+
_startTime = 0
|
13
|
+
|
14
|
+
id (id) {
|
15
|
+
this.param('id', id)
|
16
|
+
return this
|
17
|
+
}
|
18
|
+
|
19
|
+
dispatchGlobalLoadingEvents (dispatch = true) {
|
20
|
+
this._dispatchGlobalLoadingEvents = dispatch
|
21
|
+
return this
|
22
|
+
}
|
23
|
+
|
24
|
+
dispatchGlobalSaveEvents (dispatch = true) {
|
25
|
+
this._dispatchGlobalSaveEvents = dispatch
|
26
|
+
return this
|
27
|
+
}
|
28
|
+
|
29
|
+
async beforeRequest () {
|
30
|
+
this._startTime = Date.now()
|
31
|
+
|
32
|
+
if (this._dispatchGlobalLoadingEvents) {
|
33
|
+
eventBus.dispatch(new LoadingEvent(LoadingEvent.START_LOADING))
|
34
|
+
}
|
35
|
+
|
36
|
+
if (this._dispatchGlobalSaveEvents) {
|
37
|
+
eventBus.dispatch(new SaveEvent(SaveEvent.START_SAVING))
|
38
|
+
}
|
39
|
+
}
|
40
|
+
|
41
|
+
async beforeBulkRequest () {
|
42
|
+
if (this._dispatchGlobalLoadingEvents) {
|
43
|
+
eventBus.dispatch(new LoadingEvent(LoadingEvent.START_LOADING))
|
44
|
+
}
|
45
|
+
|
46
|
+
if (this._dispatchGlobalSaveEvents) {
|
47
|
+
eventBus.dispatch(new SaveEvent(SaveEvent.START_SAVING))
|
48
|
+
}
|
49
|
+
}
|
50
|
+
|
51
|
+
async afterRequest () {
|
52
|
+
if (this._minDuration) {
|
53
|
+
const diffTime = Date.now() - this._startTime
|
54
|
+
const restTime = Math.max(0, this._minDuration - diffTime)
|
55
|
+
if (restTime) {
|
56
|
+
await sleep(restTime / 1000)
|
57
|
+
}
|
58
|
+
}
|
59
|
+
|
60
|
+
if (this._dispatchGlobalLoadingEvents) {
|
61
|
+
eventBus.dispatch(new LoadingEvent(LoadingEvent.STOP_LOADING))
|
62
|
+
}
|
63
|
+
|
64
|
+
if (this._dispatchGlobalSaveEvents) {
|
65
|
+
eventBus.dispatch(new SaveEvent(SaveEvent.STOP_SAVING))
|
66
|
+
}
|
67
|
+
}
|
68
|
+
|
69
|
+
async afterBulkRequest () {
|
70
|
+
if (this._dispatchGlobalLoadingEvents) {
|
71
|
+
eventBus.dispatch(new LoadingEvent(LoadingEvent.STOP_LOADING))
|
72
|
+
}
|
73
|
+
|
74
|
+
if (this._dispatchGlobalSaveEvents) {
|
75
|
+
eventBus.dispatch(new SaveEvent(SaveEvent.STOP_SAVING))
|
76
|
+
}
|
77
|
+
}
|
78
|
+
|
79
|
+
alert (message) {
|
80
|
+
eventBus.dispatch(new AlertEvent(AlertEvent.MESSAGE, {
|
81
|
+
message
|
82
|
+
}))
|
83
|
+
}
|
84
|
+
}
|
85
|
+
|
86
|
+
export class BulkAction extends ApiAction {
|
87
|
+
}
|
@@ -0,0 +1,13 @@
|
|
1
|
+
import { BulkAction } from './ApiAction'
|
2
|
+
import { DeleteAction } from './DeleteAction'
|
3
|
+
import { GetAction } from './GetAction'
|
4
|
+
import { ListAction } from './ListAction'
|
5
|
+
import { SaveAction } from './SaveAction'
|
6
|
+
|
7
|
+
export {
|
8
|
+
BulkAction,
|
9
|
+
ListAction,
|
10
|
+
GetAction,
|
11
|
+
SaveAction,
|
12
|
+
DeleteAction
|
13
|
+
}
|
@@ -0,0 +1,21 @@
|
|
1
|
+
import { ApiAction } from './ApiAction'
|
2
|
+
|
3
|
+
export class DeleteAction extends ApiAction {
|
4
|
+
_minDuration = 400
|
5
|
+
|
6
|
+
delete () {
|
7
|
+
this.data(null)
|
8
|
+
|
9
|
+
return this.execute()
|
10
|
+
}
|
11
|
+
|
12
|
+
async afterRequest () {
|
13
|
+
await super.afterRequest()
|
14
|
+
|
15
|
+
this.alert('Die Daten wurden gelöscht.')
|
16
|
+
}
|
17
|
+
|
18
|
+
processResult () {
|
19
|
+
return true
|
20
|
+
}
|
21
|
+
}
|
@@ -0,0 +1,18 @@
|
|
1
|
+
import { AlertEvent } from '@a-vue/events'
|
2
|
+
import { eventBus } from '@a-vue/plugins/event-bus/EventBus'
|
3
|
+
|
4
|
+
import { ApiAction } from './ApiAction'
|
5
|
+
|
6
|
+
export class GetAction extends ApiAction {
|
7
|
+
load () {
|
8
|
+
return this.execute()
|
9
|
+
}
|
10
|
+
|
11
|
+
processError (result) {
|
12
|
+
eventBus.dispatch(new AlertEvent(AlertEvent.ERROR, {
|
13
|
+
headline: 'Die Daten konntent nicht geladen werden.',
|
14
|
+
message: result.message,
|
15
|
+
detail: result.detail
|
16
|
+
}))
|
17
|
+
}
|
18
|
+
}
|
@@ -0,0 +1,27 @@
|
|
1
|
+
import { NextRouteFilterSource } from '@a-vue/components/list/NextRouteFilterSource'
|
2
|
+
import { ListViewModel } from '@afeefa/api-resources-client'
|
3
|
+
|
4
|
+
import { ApiAction } from './ApiAction'
|
5
|
+
|
6
|
+
export class ListAction extends ApiAction {
|
7
|
+
load () {
|
8
|
+
return this.execute()
|
9
|
+
}
|
10
|
+
|
11
|
+
initFiltersForRoute (route) {
|
12
|
+
const request = new ListViewModel(this)
|
13
|
+
// read from next route query string, but do not push
|
14
|
+
// list component will be init with used_filters
|
15
|
+
.filterSource(new NextRouteFilterSource(route), false)
|
16
|
+
// read from history, but do not push
|
17
|
+
// list component will be init with used_filters
|
18
|
+
.historyKey(route.path, false)
|
19
|
+
.initFilters({
|
20
|
+
source: true,
|
21
|
+
history: true
|
22
|
+
})
|
23
|
+
.getApiRequest()
|
24
|
+
|
25
|
+
return ListAction.fromRequest(request)
|
26
|
+
}
|
27
|
+
}
|
@@ -0,0 +1,15 @@
|
|
1
|
+
import { ApiAction } from './ApiAction'
|
2
|
+
|
3
|
+
export class SaveAction extends ApiAction {
|
4
|
+
_minDuration = 400
|
5
|
+
|
6
|
+
save () {
|
7
|
+
return this.execute()
|
8
|
+
}
|
9
|
+
|
10
|
+
async afterRequest () {
|
11
|
+
await super.afterRequest()
|
12
|
+
|
13
|
+
this.alert('Die Daten wurden gespeichert.')
|
14
|
+
}
|
15
|
+
}
|
@@ -45,7 +45,7 @@
|
|
45
45
|
<div :class="listCssClass">
|
46
46
|
<search-select-list
|
47
47
|
v-if="isOpen"
|
48
|
-
:
|
48
|
+
:listAction="listAction"
|
49
49
|
:q="q"
|
50
50
|
:selectedItems="selectedItems"
|
51
51
|
:events="false"
|
@@ -96,7 +96,7 @@ import { ComponentWidthMixin } from './mixins/ComponentWidthMixin'
|
|
96
96
|
|
97
97
|
@Component({
|
98
98
|
props: [
|
99
|
-
'
|
99
|
+
'listAction',
|
100
100
|
'q',
|
101
101
|
'width',
|
102
102
|
'closeOnSelect',
|
@@ -3,12 +3,10 @@
|
|
3
3
|
v-model="valid"
|
4
4
|
autocomplete="off"
|
5
5
|
>
|
6
|
-
<slot name="fields" />
|
7
|
-
|
8
6
|
<slot
|
9
7
|
:changed="changed"
|
10
8
|
:valid="valid"
|
11
|
-
:model="
|
9
|
+
:model="modelToEdit"
|
12
10
|
/>
|
13
11
|
</v-form>
|
14
12
|
</template>
|
@@ -18,14 +16,31 @@
|
|
18
16
|
import { Component, Vue, Watch } from '@a-vue'
|
19
17
|
|
20
18
|
@Component({
|
21
|
-
props: [
|
19
|
+
props: [
|
20
|
+
'model',
|
21
|
+
'createModelToEdit'
|
22
|
+
]
|
22
23
|
})
|
23
24
|
export default class EditForm extends Vue {
|
24
25
|
EDIT_FORM = true
|
25
26
|
|
27
|
+
modelToEdit = null
|
26
28
|
valid = false
|
27
29
|
lastJson = null
|
28
30
|
|
31
|
+
created () {
|
32
|
+
this.reset()
|
33
|
+
}
|
34
|
+
|
35
|
+
reset () {
|
36
|
+
if (this.createModelToEdit) {
|
37
|
+
this.modelToEdit = this.createModelToEdit(this.model)
|
38
|
+
} else {
|
39
|
+
this.modelToEdit = this.model
|
40
|
+
}
|
41
|
+
this.lastJson = this.json
|
42
|
+
}
|
43
|
+
|
29
44
|
/**
|
30
45
|
* This will be triggered after the this.model has been set
|
31
46
|
* but before sub components may have changed model values
|
@@ -33,14 +48,20 @@ export default class EditForm extends Vue {
|
|
33
48
|
* Using the created() method would result in already having set
|
34
49
|
* the default date, hence not detecting a valid "change" anymore.
|
35
50
|
*/
|
36
|
-
@Watch('
|
51
|
+
// @Watch('modelToEdit', {immediate: true})
|
52
|
+
// @Watch('modelToEdit')
|
53
|
+
// modelToEditChanged () {
|
54
|
+
// this.lastJson = this.json
|
55
|
+
// this.$emit('update:changed', this.changed)
|
56
|
+
// }
|
57
|
+
|
58
|
+
@Watch('model')
|
37
59
|
modelChanged () {
|
38
|
-
this.
|
39
|
-
this.$emit('update:changed', this.changed)
|
60
|
+
this.reset()
|
40
61
|
}
|
41
62
|
|
42
63
|
get json () {
|
43
|
-
return JSON.stringify(this.
|
64
|
+
return JSON.stringify(this.modelToEdit)
|
44
65
|
}
|
45
66
|
|
46
67
|
get changed () {
|
@@ -8,7 +8,7 @@ import { FilterSourceType } from './FilterSourceType'
|
|
8
8
|
@Component({
|
9
9
|
props: [
|
10
10
|
'models', 'meta', // given, if already loaded
|
11
|
-
'
|
11
|
+
'listAction',
|
12
12
|
'filterHistoryKey',
|
13
13
|
'loadOnlyIfKeyword',
|
14
14
|
{
|
@@ -52,7 +52,7 @@ export class ListViewMixin extends Vue {
|
|
52
52
|
this.meta_ = this.meta
|
53
53
|
}
|
54
54
|
|
55
|
-
this.listViewModel = new ListViewModel(this.
|
55
|
+
this.listViewModel = new ListViewModel(this.listAction)
|
56
56
|
.filterSource(filterSource, !!filterSource)
|
57
57
|
.historyKey(historyKey, this.history)
|
58
58
|
.usedFilters(this.meta_.used_filters || null, this.meta_.count_search || 0)
|
@@ -8,12 +8,20 @@
|
|
8
8
|
import { Component, Vue } from '@a-vue'
|
9
9
|
|
10
10
|
@Component({
|
11
|
-
props:
|
11
|
+
props: {
|
12
|
+
prepend: {
|
13
|
+
type: Boolean
|
14
|
+
}
|
15
|
+
}
|
12
16
|
})
|
13
17
|
export default class AppBarButton extends Vue {
|
14
18
|
mounted () {
|
15
19
|
const section = this.getButtonBar()
|
16
|
-
|
20
|
+
if (this.prepend) {
|
21
|
+
section.prepend(this.$el)
|
22
|
+
} else {
|
23
|
+
section.append(this.$el)
|
24
|
+
}
|
17
25
|
}
|
18
26
|
|
19
27
|
destroyed () {
|
@@ -0,0 +1,38 @@
|
|
1
|
+
<template>
|
2
|
+
<a-row gap="2">
|
3
|
+
<v-btn
|
4
|
+
:small="small"
|
5
|
+
:disabled="!changed || !valid"
|
6
|
+
color="green white--text"
|
7
|
+
@click="$emit('save')"
|
8
|
+
>
|
9
|
+
Speichern
|
10
|
+
</v-btn>
|
11
|
+
|
12
|
+
<v-icon
|
13
|
+
v-if="changed"
|
14
|
+
:small="small"
|
15
|
+
text
|
16
|
+
title="Formular zurücksetzen"
|
17
|
+
@click="$emit('reset')"
|
18
|
+
>
|
19
|
+
{{ undoIcon }}
|
20
|
+
</v-icon>
|
21
|
+
</a-row>
|
22
|
+
</template>
|
23
|
+
|
24
|
+
<script>
|
25
|
+
import { Component, Vue } from '@a-vue'
|
26
|
+
import { mdiRotateLeft} from '@mdi/js'
|
27
|
+
|
28
|
+
@Component({
|
29
|
+
props: [
|
30
|
+
'changed',
|
31
|
+
'valid',
|
32
|
+
'small'
|
33
|
+
]
|
34
|
+
})
|
35
|
+
export default class EditFormButtons extends Vue {
|
36
|
+
undoIcon = mdiRotateLeft
|
37
|
+
}
|
38
|
+
</script>
|
@@ -0,0 +1,71 @@
|
|
1
|
+
<template>
|
2
|
+
<div>
|
3
|
+
<a-icon-button
|
4
|
+
small
|
5
|
+
color="red white--text"
|
6
|
+
:class="'removeButton-' + dialogId"
|
7
|
+
icon="$trashCanIcon"
|
8
|
+
text="Löschen"
|
9
|
+
@click="remove"
|
10
|
+
/>
|
11
|
+
|
12
|
+
<a-dialog
|
13
|
+
:id="dialogId"
|
14
|
+
:anchor="[document, '.removeButton-' + dialogId]"
|
15
|
+
:active="protect ? removeKey === removeConfirmed : true"
|
16
|
+
>
|
17
|
+
<template v-if="protect">
|
18
|
+
<div>Bitte folgenden Key eingeben: <strong class="removeKey">{{ removeKey }}</strong></div>
|
19
|
+
|
20
|
+
<a-text-field
|
21
|
+
v-model="removeConfirmed"
|
22
|
+
label="Key"
|
23
|
+
:focus="true"
|
24
|
+
width="100"
|
25
|
+
/>
|
26
|
+
</template>
|
27
|
+
</a-dialog>
|
28
|
+
</div>
|
29
|
+
</template>
|
30
|
+
|
31
|
+
|
32
|
+
<script>
|
33
|
+
import { Component, Vue } from '@a-vue'
|
34
|
+
import { DialogEvent } from '@a-vue/events'
|
35
|
+
import { randomCssClass } from '@a-vue/utils/random'
|
36
|
+
|
37
|
+
@Component({
|
38
|
+
props: ['itemTitle', 'protect']
|
39
|
+
})
|
40
|
+
export default class EditPage extends Vue {
|
41
|
+
dialogId = randomCssClass(10)
|
42
|
+
document = document
|
43
|
+
removeKey = null
|
44
|
+
removeConfirmed = null
|
45
|
+
|
46
|
+
async remove () {
|
47
|
+
if (this.protect) {
|
48
|
+
this.removeKey = [...Array(6)].map(() => Math.floor(Math.random() * 16).toString(16)).join('')
|
49
|
+
}
|
50
|
+
|
51
|
+
const result = await this.$events.dispatch(new DialogEvent(DialogEvent.SHOW, {
|
52
|
+
id: this.dialogId,
|
53
|
+
title: this.itemTitle + ' löschen?',
|
54
|
+
message: 'Soll ' + this.itemTitle + ' gelöscht werden?',
|
55
|
+
yesButton: 'Löschen',
|
56
|
+
yesColor: 'red white--text'
|
57
|
+
}))
|
58
|
+
|
59
|
+
if (result === DialogEvent.RESULT_YES) {
|
60
|
+
this.$emit('remove')
|
61
|
+
}
|
62
|
+
}
|
63
|
+
}
|
64
|
+
</script>
|
65
|
+
|
66
|
+
|
67
|
+
<style lang="scss" scoped>
|
68
|
+
.removeKey {
|
69
|
+
user-select: none;
|
70
|
+
}
|
71
|
+
</style>
|
@@ -7,7 +7,8 @@ import DetailContent from './detail/DetailContent'
|
|
7
7
|
import DetailMeta from './detail/DetailMeta'
|
8
8
|
import DetailProperty from './detail/DetailProperty'
|
9
9
|
import DetailTitle from './detail/DetailTitle'
|
10
|
-
import
|
10
|
+
import EditFormButtons from './form/EditFormButtons'
|
11
|
+
import RemoveButton from './form/RemoveButton'
|
11
12
|
import ListCard from './list/ListCard'
|
12
13
|
import ListColumnHeader from './list/ListColumnHeader'
|
13
14
|
import ListContent from './list/ListContent'
|
@@ -20,6 +21,7 @@ import CreatePage from './pages/CreatePage'
|
|
20
21
|
import DetailPage from './pages/DetailPage'
|
21
22
|
import EditPage from './pages/EditPage'
|
22
23
|
import ListPage from './pages/ListPage'
|
24
|
+
import Start from './Start.vue'
|
23
25
|
|
24
26
|
Vue.component('ListCard', ListCard)
|
25
27
|
Vue.component('ListColumnHeader', ListColumnHeader)
|
@@ -32,6 +34,8 @@ Vue.component('ListPage', ListPage)
|
|
32
34
|
Vue.component('CreatePage', CreatePage)
|
33
35
|
|
34
36
|
Vue.component('EditPage', EditPage)
|
37
|
+
Vue.component('EditFormButtons', EditFormButtons)
|
38
|
+
Vue.component('RemoveButton', RemoveButton)
|
35
39
|
|
36
40
|
Vue.component('ModelCount', ModelCount)
|
37
41
|
Vue.component('ModelIcon', ModelIcon)
|
@@ -1,151 +1,55 @@
|
|
1
1
|
<template>
|
2
|
-
<
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
:
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
Ansehen
|
23
|
-
</v-btn>
|
24
|
-
</app-bar-button>
|
25
|
-
|
26
|
-
<edit-form
|
27
|
-
:model="modelToEdit"
|
28
|
-
:valid.sync="valid"
|
29
|
-
:changed.sync="changed"
|
30
|
-
>
|
31
|
-
<template #fields>
|
32
|
-
<slot
|
33
|
-
name="fields"
|
34
|
-
:model="modelToEdit"
|
35
|
-
/>
|
36
|
-
</template>
|
37
|
-
</edit-form>
|
38
|
-
|
39
|
-
<a-row class="mt-8">
|
40
|
-
<v-btn
|
41
|
-
:disabled="!changed || !valid"
|
42
|
-
color="green white--text"
|
43
|
-
@click="save"
|
44
|
-
>
|
45
|
-
Speichern
|
46
|
-
</v-btn>
|
47
|
-
|
48
|
-
<v-btn
|
49
|
-
v-if="changed"
|
50
|
-
text
|
51
|
-
@click="reset"
|
52
|
-
>
|
53
|
-
Zurücksetzen
|
54
|
-
</v-btn>
|
55
|
-
</a-row>
|
56
|
-
</div>
|
2
|
+
<edit-form
|
3
|
+
ref="form"
|
4
|
+
:model="model"
|
5
|
+
:createModelToEdit="createModelToEdit"
|
6
|
+
>
|
7
|
+
<template #default="{model, changed, valid}">
|
8
|
+
<slot
|
9
|
+
:model="model"
|
10
|
+
:changed="changed"
|
11
|
+
:valid="valid"
|
12
|
+
/>
|
13
|
+
|
14
|
+
<edit-form-buttons
|
15
|
+
:changed="changed"
|
16
|
+
:valid="valid"
|
17
|
+
@save="$emit('save', model)"
|
18
|
+
@reset="$refs.form.reset()"
|
19
|
+
/>
|
20
|
+
</template>
|
21
|
+
</edit-form>
|
57
22
|
</template>
|
58
23
|
|
59
24
|
<script>
|
60
|
-
import { Component,
|
61
|
-
import {
|
25
|
+
import { Component, Vue } from '@a-vue'
|
26
|
+
import { DialogEvent } from '@a-vue/events'
|
62
27
|
|
63
28
|
@Component({
|
64
|
-
props: [
|
65
|
-
'model',
|
66
|
-
'icon',
|
67
|
-
'title',
|
68
|
-
'listLink',
|
69
|
-
'getAction'
|
70
|
-
]
|
29
|
+
props: ['model', 'createModelToEdit']
|
71
30
|
})
|
72
|
-
export default class EditPage extends
|
73
|
-
|
74
|
-
|
75
|
-
model_ = null
|
31
|
+
export default class EditPage extends Vue {
|
32
|
+
unregisterRouterHook = null
|
76
33
|
|
77
34
|
created () {
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
this.reset()
|
90
|
-
}
|
91
|
-
|
92
|
-
get editConfig () {
|
93
|
-
return this.$parent.constructor.getEditRouteConfig(this.$route)
|
94
|
-
}
|
95
|
-
|
96
|
-
get modelUpateAction () {
|
97
|
-
return this.editConfig.updateAction || this.ModelClass.getAction('save')
|
98
|
-
}
|
99
|
-
|
100
|
-
get _getAction () {
|
101
|
-
if (this.getAction) {
|
102
|
-
return this.getAction
|
103
|
-
}
|
104
|
-
return this.ModelClass.getAction('get')
|
105
|
-
}
|
106
|
-
|
107
|
-
get _icon () {
|
108
|
-
return this.icon || this.model.getIcon()
|
109
|
-
}
|
110
|
-
|
111
|
-
get _title () {
|
112
|
-
const title = this.modelToEdit.getTitle()
|
113
|
-
if (title) {
|
114
|
-
return title
|
115
|
-
}
|
116
|
-
|
117
|
-
if (this.title) {
|
118
|
-
return this.title
|
119
|
-
}
|
120
|
-
|
121
|
-
return this.$t('Admin.Types', this.ModelClass.type, null, 'TITLE_EMPTY', 'de')
|
122
|
-
}
|
123
|
-
|
124
|
-
get _listLink () {
|
125
|
-
if (this.listLink) {
|
126
|
-
if (typeof this.listLink === 'function') {
|
127
|
-
return this.listLink()
|
128
|
-
} else {
|
129
|
-
return this.listLink
|
35
|
+
this.unregisterRouterHook = this.$router.beforeEach(async (to, from, next) => {
|
36
|
+
if (this.$refs.form.changed) {
|
37
|
+
const result = await this.$events.dispatch(new DialogEvent(DialogEvent.SHOW, {
|
38
|
+
title: 'Änderungen verwerfen?',
|
39
|
+
message: 'Im Formular sind nicht gespeicherte Änderungen. Sollen diese verworfen werden?',
|
40
|
+
yesButton: 'Verwerfen'
|
41
|
+
}))
|
42
|
+
if (result === DialogEvent.RESULT_YES) {
|
43
|
+
next()
|
44
|
+
}
|
45
|
+
return
|
130
46
|
}
|
131
|
-
|
132
|
-
|
133
|
-
}
|
134
|
-
|
135
|
-
createModelToEdit () {
|
136
|
-
return this.model_.cloneForEdit(this.fields)
|
137
|
-
}
|
138
|
-
|
139
|
-
get saveParams () {
|
140
|
-
return {
|
141
|
-
id: this.model.id
|
142
|
-
}
|
47
|
+
next()
|
48
|
+
})
|
143
49
|
}
|
144
50
|
|
145
|
-
|
146
|
-
this.
|
147
|
-
this.reset()
|
148
|
-
this.$emit('saved', model)
|
51
|
+
destroyed () {
|
52
|
+
this.unregisterRouterHook()
|
149
53
|
}
|
150
54
|
}
|
151
55
|
</script>
|
@@ -0,0 +1,75 @@
|
|
1
|
+
import { Component, Vue, Watch } from '@a-vue'
|
2
|
+
|
3
|
+
Component.registerHooks([
|
4
|
+
'beforeRouteEnter',
|
5
|
+
'beforeRouteUpdate'
|
6
|
+
])
|
7
|
+
|
8
|
+
let onLoadCallback = () => {}
|
9
|
+
let routerHookCalled = false
|
10
|
+
|
11
|
+
function onLoad (callback) {
|
12
|
+
onLoadCallback = callback
|
13
|
+
}
|
14
|
+
|
15
|
+
function load (route) {
|
16
|
+
const Component = [...route.matched].pop().components.default
|
17
|
+
|
18
|
+
if (!Component.drm_getActions) {
|
19
|
+
console.warn('A data route component must implement a static drm_getActions() method.')
|
20
|
+
}
|
21
|
+
|
22
|
+
const request = Component.drm_getActions(route, onLoad)
|
23
|
+
if (Array.isArray(request)) {
|
24
|
+
return Promise.all(request.map(request => {
|
25
|
+
return request
|
26
|
+
.dispatchGlobalLoadingEvents()
|
27
|
+
.execute()
|
28
|
+
}))
|
29
|
+
} else {
|
30
|
+
return request
|
31
|
+
.dispatchGlobalLoadingEvents()
|
32
|
+
.execute()
|
33
|
+
}
|
34
|
+
}
|
35
|
+
|
36
|
+
@Component
|
37
|
+
export class DataRouteMixin extends Vue {
|
38
|
+
drm_isLoaded = false
|
39
|
+
|
40
|
+
async beforeRouteEnter (to, from, next) {
|
41
|
+
routerHookCalled = true
|
42
|
+
const result = await load(to)
|
43
|
+
|
44
|
+
next(vm => {
|
45
|
+
if (result !== false) {
|
46
|
+
vm.drm_onLoad(result)
|
47
|
+
vm.drm_isLoaded = true
|
48
|
+
}
|
49
|
+
routerHookCalled = false
|
50
|
+
})
|
51
|
+
}
|
52
|
+
|
53
|
+
/**
|
54
|
+
* triggered both, if route name or route params change
|
55
|
+
*/
|
56
|
+
@Watch('$route.params')
|
57
|
+
async routeParamsChanged () {
|
58
|
+
if (routerHookCalled) {
|
59
|
+
return
|
60
|
+
}
|
61
|
+
|
62
|
+
if (!this.drm_isLoaded) {
|
63
|
+
const result = await load(this.$route)
|
64
|
+
|
65
|
+
if (result !== false) {
|
66
|
+
this.drm_onLoad(result)
|
67
|
+
this.drm_isLoaded = true
|
68
|
+
}
|
69
|
+
}
|
70
|
+
}
|
71
|
+
|
72
|
+
drm_onLoad (result) {
|
73
|
+
onLoadCallback(this, result)
|
74
|
+
}
|
75
|
+
}
|
@@ -17,11 +17,11 @@ export class Model extends ApiResourcesModel {
|
|
17
17
|
return (new this()).getLink(action)
|
18
18
|
}
|
19
19
|
|
20
|
-
static getAction (
|
20
|
+
static getAction (actionName) {
|
21
21
|
if (this.resourceType) {
|
22
22
|
return apiResources.getAction({
|
23
|
-
|
24
|
-
|
23
|
+
resourceType: this.resourceType,
|
24
|
+
actionName
|
25
25
|
})
|
26
26
|
}
|
27
27
|
console.warn('You can\'t get an action out of a model without resourceType:', this.type)
|