@afeefa/vue-app 0.0.61 → 0.0.64

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. package/.afeefa/package/release/version.txt +1 -1
  2. package/README.md +3 -1
  3. package/package.json +1 -1
  4. package/src/api-resources/ApiAction.js +87 -0
  5. package/src/api-resources/ApiActions2.js +13 -0
  6. package/src/api-resources/DeleteAction.js +21 -0
  7. package/src/api-resources/GetAction.js +18 -0
  8. package/src/api-resources/ListAction.js +27 -0
  9. package/src/api-resources/SaveAction.js +15 -0
  10. package/src/components/AModal.vue +21 -3
  11. package/src/components/ASearchSelect.vue +2 -2
  12. package/src/components/ATableRow.vue +4 -0
  13. package/src/components/flying-context/FlyingContextEvent.js +5 -0
  14. package/src/components/form/EditForm.vue +30 -8
  15. package/src/components/form/EditModal.vue +50 -35
  16. package/src/components/form/FormFieldMixin.js +1 -1
  17. package/src/components/form/NestedEditForm.vue +4 -0
  18. package/src/components/list/ListViewMixin.js +2 -2
  19. package/src/events.js +1 -0
  20. package/src-admin/bootstrap.js +1 -0
  21. package/src-admin/components/App.vue +5 -1
  22. package/src-admin/components/FlyingContext.vue +77 -0
  23. package/src-admin/components/FlyingContextContainer.vue +85 -0
  24. package/src-admin/components/app/AppBarButton.vue +10 -2
  25. package/src-admin/components/controls/SearchSelectFormField.vue +1 -1
  26. package/src-admin/components/form/EditFormButtons.vue +40 -0
  27. package/src-admin/components/form/RemoveButton.vue +71 -0
  28. package/src-admin/components/index.js +7 -8
  29. package/src-admin/components/list/ListView.vue +19 -5
  30. package/src-admin/components/pages/EditPage.vue +48 -134
  31. package/src-admin/components/routes/DataRouteMixin.js +84 -0
  32. package/src-admin/config/routing.js +0 -11
  33. package/src-admin/directives/index.js +26 -0
  34. package/src-admin/models/Model.js +3 -3
  35. package/src-admin/components/pages/CreatePage.vue +0 -114
  36. package/src-admin/components/pages/DetailPage.vue +0 -143
  37. package/src-admin/components/pages/EditPageMixin.js +0 -96
  38. package/src-admin/components/pages/ListPage.vue +0 -55
  39. package/src-admin/components/routes/CreateRoute.vue +0 -15
  40. package/src-admin/components/routes/DetailRoute.vue +0 -85
  41. package/src-admin/components/routes/EditRoute.vue +0 -78
  42. package/src-admin/components/routes/ListRoute.vue +0 -110
@@ -1,114 +0,0 @@
1
- <template>
2
- <div class="createPage">
3
- <app-bar-title
4
- :icon="_icon"
5
- :title="_title"
6
- />
7
-
8
- <app-bar-button>
9
- <v-btn
10
- :to="_listLink"
11
- small
12
- >
13
- Liste
14
- </v-btn>
15
- </app-bar-button>
16
-
17
- <edit-form
18
- :model="modelToEdit"
19
- :valid.sync="valid"
20
- :changed.sync="changed"
21
- >
22
- <template #fields>
23
- <slot
24
- name="fields"
25
- :model="modelToEdit"
26
- />
27
- </template>
28
- </edit-form>
29
-
30
- <a-row class="mt-6">
31
- <v-btn
32
- :disabled="!changed || !valid"
33
- color="green white--text"
34
- @click="save"
35
- >
36
- Anlegen
37
- </v-btn>
38
-
39
- <v-btn
40
- v-if="changed"
41
- text
42
- @click="reset"
43
- >
44
- Zurücksetzen
45
- </v-btn>
46
- </a-row>
47
- </div>
48
- </template>
49
-
50
- <script>
51
- import { Component, Mixins } from '@a-vue'
52
- import { EditPageMixin } from './EditPageMixin'
53
-
54
- @Component({
55
- props: ['icon', 'title', 'createModel', 'listLink']
56
- })
57
- export default class CreatePage extends Mixins(EditPageMixin) {
58
- created () {
59
- if (!this.$parent.constructor.getCreateRouteConfig) {
60
- console.warn('<create-page> owner must provide a static createRouteConfig method.')
61
- }
62
-
63
- this.reset()
64
- }
65
-
66
- get editConfig () {
67
- return this.$parent.constructor.getCreateRouteConfig(this.$route)
68
- }
69
-
70
- get modelUpateAction () {
71
- return this.editConfig.createAction || this.ModelClass.getAction('save')
72
- }
73
-
74
- get _icon () {
75
- return this.icon || this.modelToEdit.getIcon()
76
- }
77
-
78
- get _title () {
79
- const title = this.modelToEdit.getTitle()
80
- if (title) {
81
- return title
82
- }
83
-
84
- if (this.title) {
85
- return this.title
86
- }
87
-
88
- return this.$t('Admin.Types', this.ModelClass.type, null, 'TITLE_NEW', 'de')
89
- }
90
-
91
- get _listLink () {
92
- if (this.listLink) {
93
- if (typeof this.listLink === 'function') {
94
- return this.listLink()
95
- } else {
96
- return this.listLink
97
- }
98
- }
99
- return this.modelToEdit.getLink('list')
100
- }
101
-
102
- createModelToEdit () {
103
- if (this.createModel) {
104
- return this.createModel(this.fields)
105
- }
106
- return this.ModelClass.createForNew(this.fields)
107
- }
108
-
109
- saved (model) {
110
- this.ignoreChanged = true
111
- this.$router.push(model.getLink('edit'))
112
- }
113
- }
114
- </script>
@@ -1,143 +0,0 @@
1
- <template>
2
- <div class="detailPage ml-4 mt-12">
3
- <app-bar-title
4
- :icon="_icon"
5
- :title="_title"
6
- />
7
-
8
- <app-bar-button v-if="$has.remove">
9
- <v-btn
10
- small
11
- color="red white--text"
12
- class="removeButton"
13
- @click="remove"
14
- >
15
- Löschen
16
- </v-btn>
17
- </app-bar-button>
18
-
19
- <app-bar-button v-if="$has.edit">
20
- <a-icon-button
21
- :to="model.getLink('edit')"
22
- icon="$pencilIcon"
23
- text="Bearbeiten"
24
- color="green white--text"
25
- />
26
- </app-bar-button>
27
-
28
- <slot
29
- name="model"
30
- :model="model"
31
- />
32
-
33
- <a-dialog
34
- id="detailPageRemoveDialog"
35
- :anchor="[document, '.removeButton']"
36
- :active="protectRemove ? removeKey === removeConfirmed : true"
37
- >
38
- <template v-if="protectRemove">
39
- <div>Bitte folgenden Key eingeben: <strong class="removeKey">{{ removeKey }}</strong></div>
40
-
41
- <a-text-field
42
- v-model="removeConfirmed"
43
- label="Key"
44
- :focus="true"
45
- width="100"
46
- />
47
- </template>
48
- </a-dialog>
49
- </div>
50
- </template>
51
-
52
-
53
- <script>
54
- import { Component, Vue, Watch } from '@a-vue'
55
- import { RemoveAction } from '@a-vue/api-resources/ApiActions'
56
-
57
- @Component({
58
- props: ['model', 'title', 'icon', 'protectRemove', 'listLink']
59
- })
60
- export default class DetailPage extends Vue {
61
- $hasOptions = ['edit', 'remove', 'list']
62
-
63
- removeKey = null
64
- removeConfirmed = null
65
-
66
- created () {
67
- if (!this.$parent.constructor.getDetailRouteConfig) {
68
- console.warn('<detail-page> owner must provide a static getDetailRouteConfig method.')
69
- }
70
- this.$emit('model', this.model)
71
- }
72
-
73
- @Watch('model')
74
- modelChanged () {
75
- this.$emit('model', this.model)
76
- }
77
-
78
- get _title () {
79
- return this.title || this.model.getTitle()
80
- }
81
-
82
- get detailConfig () {
83
- return this.$parent.constructor.getDetailRouteConfig(this.$route)
84
- }
85
-
86
- get document () {
87
- return document
88
- }
89
-
90
- get ModelClass () {
91
- return this.detailConfig.ModelClass
92
- }
93
-
94
- get _listLink () {
95
- if (this.listLink) {
96
- if (typeof this.listLink === 'function') {
97
- return this.listLink()
98
- } else {
99
- return this.listLink
100
- }
101
- }
102
- return this.model.getLink('list')
103
- }
104
-
105
- get _icon () {
106
- if (this.icon) {
107
- return this.icon
108
- }
109
- return this.model.getIcon()
110
- }
111
-
112
- get _deleteAction () {
113
- return this.detailConfig.removeAction || this.ModelClass.getAction('save')
114
- }
115
-
116
- async remove () {
117
- this.removeKey = [...Array(6)].map(() => Math.floor(Math.random() * 16).toString(16)).join('')
118
-
119
- const result = await new RemoveAction()
120
- .setAction(this._deleteAction)
121
- .setId(this.model.id)
122
- .setDialog({
123
- id: 'detailPageRemoveDialog',
124
- title: this.model.getTitle() + ' löschen?',
125
- message: 'Soll ' + this.model.getTitle() + ' gelöscht werden?',
126
- yesButton: 'Löschen',
127
- yesColor: 'red white--text'
128
- })
129
- .delete()
130
-
131
- if (result) {
132
- this.$router.push(this.model.getLink('list'))
133
- }
134
- }
135
- }
136
- </script>
137
-
138
-
139
- <style lang="scss" scoped>
140
- .removeKey {
141
- user-select: none;
142
- }
143
- </style>
@@ -1,96 +0,0 @@
1
- import { Component, Vue } from '@a-vue'
2
- import { SaveAction } from '@a-vue/api-resources/ApiActions'
3
- import { DialogEvent } from '@a-vue/events'
4
-
5
- @Component({
6
- props: ['saveAction']
7
- })
8
- export class EditPageMixin extends Vue {
9
- valid = false
10
- changed = false
11
- modelToEdit = null
12
- ignoreChanged = false
13
-
14
- unregisterRouterHook = null
15
-
16
- created () {
17
- this.unregisterRouterHook = this.$router.beforeEach(async (to, from, next) => {
18
- if (!this.ignoreChanged && this.changed) {
19
- const result = await this.$events.dispatch(new DialogEvent(DialogEvent.SHOW, {
20
- title: 'Änderungen verwerfen?',
21
- message: 'Im Formular sind nicht gespeicherte Änderungen. Sollen diese verworfen werden?',
22
- yesButton: 'Verwerfen'
23
- }))
24
- if (result === DialogEvent.RESULT_YES) {
25
- next()
26
- }
27
- return
28
- }
29
- next()
30
- })
31
- }
32
-
33
- destroyed () {
34
- this.unregisterRouterHook()
35
- }
36
-
37
- createModelToEdit () {
38
- return null
39
- }
40
-
41
- get editConfig () {
42
- return null
43
- }
44
-
45
- get ModelClass () {
46
- return this.editConfig.ModelClass
47
- }
48
-
49
- get _saveAction () {
50
- if (this.saveAction) {
51
- return this.saveAction
52
- }
53
- return this.modelUpateAction
54
- }
55
-
56
- get modelUpateAction () {
57
- return null
58
- }
59
-
60
- get fields () {
61
- return this.editConfig.fields
62
- }
63
-
64
- get saveParams () {
65
- return {}
66
- }
67
-
68
- async save () {
69
- const model = await new SaveAction()
70
- .setAction(this._saveAction)
71
- .setFields(this.fields)
72
- .setId(this.modelToEdit.id)
73
- .setData(this.modelToEdit.serialize(this.fields))
74
- .setAfterSaveHook(this.afterSave)
75
- .save()
76
-
77
- this.saved(model)
78
- }
79
-
80
- reset () {
81
- const modelToEdit = this.createModelToEdit()
82
- if (this.editConfig.createModelToEdit) {
83
- this.editConfig.createModelToEdit(modelToEdit)
84
- }
85
- this.modelToEdit = modelToEdit // this assignment makes modelToEdit recursively reactive
86
- this.$emit('model', this.modelToEdit)
87
- }
88
-
89
- afterSave (_model) {
90
- // e.g. reload model
91
- }
92
-
93
- saved (_model) {
94
- // e.g. redirect after save
95
- }
96
- }
@@ -1,55 +0,0 @@
1
- <template>
2
- <div class="listPage">
3
- <app-bar-title
4
- :icon="_icon"
5
- :title="_title"
6
- />
7
-
8
- <app-bar-button v-if="$has.add">
9
- <a-icon-button
10
- v-if="$has.add"
11
- :to="_newLink"
12
- icon="$plusIcon"
13
- :text="_newTitle"
14
- color="green white--text"
15
- />
16
- </app-bar-button>
17
-
18
- <slot />
19
- </div>
20
- </template>
21
-
22
- <script>
23
- import { Component, Vue } from '@a-vue'
24
-
25
- @Component({
26
- props: ['icon', 'title', 'newTitle', 'newLink', 'Model']
27
- })
28
- export default class ListPage extends Vue {
29
- $hasOptions = ['add']
30
-
31
- get _icon () {
32
- return this.icon || this.Model.icon
33
- }
34
-
35
- get _title () {
36
- if (this.title) {
37
- return this.title
38
- }
39
-
40
- return this.$t('Admin.Types', this.Model.type, null, 'TITLE_PLURAL', 'de')
41
- }
42
-
43
- get _newTitle () {
44
- if (this.newTitle) {
45
- return this.newTitle
46
- }
47
-
48
- return this.$t('Admin.Types', this.Model.type, null, 'TITLE_SINGULAR', 'de')
49
- }
50
-
51
- get _newLink () {
52
- return this.newLink || this.Model.getLink('new')
53
- }
54
- }
55
- </script>
@@ -1,15 +0,0 @@
1
- <template>
2
- <component :is="Component" />
3
- </template>
4
-
5
-
6
- <script>
7
- import { Component, Vue } from '@a-vue'
8
-
9
- @Component
10
- export default class CreateRoute extends Vue {
11
- get Component () {
12
- return this.$routeDefinition.config.new
13
- }
14
- }
15
- </script>
@@ -1,85 +0,0 @@
1
- <template>
2
- <component
3
- :is="Component"
4
- v-if="model"
5
- :model="model"
6
- />
7
- </template>
8
-
9
- <script>
10
- import { Component, Vue, Watch } from '@a-vue'
11
- import { GetAction } from '@a-vue/api-resources/ApiActions'
12
-
13
- Component.registerHooks([
14
- 'beforeRouteEnter',
15
- 'beforeRouteUpdate'
16
- ])
17
-
18
- function load (route) {
19
- const routeDefinition = route.meta.routeDefinition
20
- const Component = routeDefinition.config.detail
21
-
22
- if (!Component.getDetailRouteConfig) {
23
- console.warn('A detail route component must implement a static getDetailRouteConfig property.')
24
- }
25
-
26
- const detailConfig = Component.getDetailRouteConfig(route)
27
- const action = detailConfig.action || detailConfig.ModelClass.getAction('get')
28
-
29
- return new GetAction()
30
- .setAction(action)
31
- .setFields(detailConfig.fields)
32
- .setId(detailConfig.id || route.params[routeDefinition.idKey])
33
- .load()
34
- }
35
-
36
- let routerHookCalled = false
37
-
38
- @Component
39
- export default class DetailRoute extends Vue {
40
- model = null
41
-
42
- /**
43
- * triggered, when the route name changes
44
- * not triggered, when only route params change
45
- */
46
- async beforeRouteEnter (to, from, next) {
47
- routerHookCalled = true
48
- const result = await load(to)
49
- next(vm => {
50
- if (result !== false) {
51
- vm.model = result
52
- }
53
- routerHookCalled = false
54
- })
55
- }
56
-
57
- /**
58
- * triggered both, if route name or route params change
59
- */
60
- @Watch('$route.params')
61
- async routeParamsChanged () {
62
- if (routerHookCalled) {
63
- // set model to null in order to not recreate detail route's
64
- // child components with the stale model which is still active
65
- // in between resolving the route with next() + creating the
66
- // route detail component and resetting vm.model later in the callback
67
- this.model = null
68
- return
69
- }
70
- this.model = await load(this.$route)
71
- }
72
-
73
- // probably not needed
74
- // @Watch('$route.name')
75
- // async routeNameChanged () {
76
- // if (routerHookCalled) {
77
- // // this.model = null
78
- // }
79
- // }
80
-
81
- get Component () {
82
- return this.$routeDefinition.config.detail
83
- }
84
- }
85
- </script>
@@ -1,78 +0,0 @@
1
- <template>
2
- <component
3
- :is="Component"
4
- v-if="model"
5
- :model="model"
6
- />
7
- </template>
8
-
9
-
10
- <script>
11
- import { Component, Vue, Watch } from '@a-vue'
12
- import { GetAction } from '@a-vue/api-resources/ApiActions'
13
-
14
- Component.registerHooks([
15
- 'beforeRouteEnter',
16
- 'beforeRouteUpdate'
17
- ])
18
-
19
- function load (route) {
20
- const routeDefinition = route.meta.routeDefinition
21
- const Component = routeDefinition.config.edit
22
-
23
- if (!Component.getEditRouteConfig) {
24
- console.warn('An edit route component must implement a static getEditRouteConfig property.')
25
- }
26
-
27
- const editConfig = Component.getEditRouteConfig(route)
28
- const action = editConfig.getAction || editConfig.ModelClass.getAction('get')
29
-
30
- return new GetAction()
31
- .setAction(action)
32
- .setFields(editConfig.fields)
33
- .setId(editConfig.id || route.params[routeDefinition.idKey])
34
- .load()
35
- }
36
-
37
- let routerHookCalled = false
38
-
39
- @Component
40
- export default class EditRoute extends Vue {
41
- model = null
42
-
43
- /**
44
- * triggered, when the route name changes
45
- * not triggered, when only route params change
46
- */
47
- async beforeRouteEnter (to, from, next) {
48
- routerHookCalled = true
49
- const result = await load(to)
50
- next(vm => {
51
- if (result !== false) {
52
- vm.model = result
53
- }
54
- routerHookCalled = false
55
- })
56
- }
57
-
58
- /**
59
- * triggered both, if route name or route params change
60
- */
61
- @Watch('$route.params')
62
- async routeParamsChanged () {
63
- if (routerHookCalled) {
64
- // set model to null in order to not recreate detail route's
65
- // child components with the stale model which is still active
66
- // in between resolving the route with next() + creating the
67
- // route edit component and resetting vm.model later in the callback
68
- this.model = null
69
- return
70
- }
71
- this.model = await load(this.$route)
72
- }
73
-
74
- get Component () {
75
- return this.$routeDefinition.config.edit
76
- }
77
- }
78
- </script>
@@ -1,110 +0,0 @@
1
- <template>
2
- <component
3
- :is="Component"
4
- v-if="isLoaded"
5
- :models="models"
6
- :meta="meta"
7
- />
8
- </template>
9
-
10
- <script>
11
- import { Component, Vue, Watch } from '@a-vue'
12
- import { ListAction } from '@a-vue/api-resources/ApiActions'
13
- import { NextRouteFilterSource } from '@a-vue/components/list/NextRouteFilterSource'
14
- import { ListViewModel } from '@afeefa/api-resources-client'
15
-
16
- Component.registerHooks([
17
- 'beforeRouteEnter',
18
- 'beforeRouteUpdate'
19
- ])
20
-
21
- /**
22
- * keep track 'this' in beforeRouteEnter
23
- * in order to avoid rendering list pages with a stale set
24
- * of models because next(vm => ...) will first create the
25
- * list page with the existing set of models and update the
26
- * models afterwards.
27
- */
28
- let lastVm = null
29
-
30
- function load (route) {
31
- const routeDefinition = route.meta.routeDefinition
32
- const Component = routeDefinition.config.list
33
-
34
- if (!Component.getListRouteConfig) {
35
- console.warn('A list route component must implement a static getListRouteConfig property.')
36
- }
37
-
38
- const request = new ListViewModel(Component.getListRouteConfig(route))
39
- // read from next route query string, but do not push
40
- // list component will be init with used_filters
41
- .filterSource(new NextRouteFilterSource(route), false)
42
- // read from history, but do not push
43
- // list component will be init with used_filters
44
- .historyKey(route.path, false)
45
- .initFilters({
46
- source: true,
47
- history: true
48
- })
49
- .getApiRequest()
50
-
51
- return new ListAction()
52
- .setRequest(request)
53
- .load()
54
- }
55
-
56
- let routerHookCalled = false
57
-
58
- @Component
59
- export default class ListRoute extends Vue {
60
- models = null
61
- meta = null
62
- isLoaded = false
63
-
64
- async beforeRouteEnter (to, from, next) {
65
- routerHookCalled = true
66
- const result = await load(to)
67
-
68
- if (lastVm) {
69
- lastVm.isLoaded = false
70
- }
71
-
72
- next(vm => {
73
- if (result !== false) {
74
- const {models, meta} = result
75
- vm.models = models
76
- vm.meta = meta
77
- vm.isLoaded = true
78
- }
79
-
80
- lastVm = vm
81
- routerHookCalled = false
82
- })
83
- }
84
-
85
- /**
86
- * triggered both, if route name or route params change
87
- */
88
- @Watch('$route.params')
89
- async routeParamsChanged () {
90
- if (routerHookCalled) {
91
- return
92
- }
93
-
94
- if (!this.isLoaded) {
95
- const result = await load(this.$route)
96
-
97
- if (result !== false) {
98
- const {models, meta} = result
99
- this.models = models
100
- this.meta = meta
101
- this.isLoaded = true
102
- }
103
- }
104
- }
105
-
106
- get Component () {
107
- return this.$routeDefinition.config.list
108
- }
109
- }
110
- </script>