@afeefa/vue-app 0.0.63 → 0.0.66

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. package/.afeefa/package/release/version.txt +1 -1
  2. package/package.json +1 -1
  3. package/src/components/ABreadcrumbs.vue +75 -18
  4. package/src/components/ADatePicker.vue +1 -1
  5. package/src/components/AIcon.vue +3 -6
  6. package/src/components/AIconButton.vue +1 -2
  7. package/src/components/AModal.vue +21 -3
  8. package/src/components/ARichTextArea.vue +95 -85
  9. package/src/components/ARow.vue +0 -7
  10. package/src/components/ATableRow.vue +4 -0
  11. package/src/components/flying-context/FlyingContextEvent.js +5 -0
  12. package/src/components/form/EditForm.vue +13 -3
  13. package/src/components/form/EditModal.vue +52 -35
  14. package/src/components/form/fields/FormFieldRichTextArea.vue +5 -3
  15. package/src/components/list/ListViewMixin.js +25 -2
  16. package/src/components/mixins/ClickOutsideMixin.js +5 -1
  17. package/src/components/search-select/SearchSelectList.vue +0 -1
  18. package/src/components/vue/Component.js +9 -2
  19. package/src/events.js +2 -0
  20. package/src-admin/bootstrap.js +1 -0
  21. package/src-admin/components/App.vue +58 -59
  22. package/src-admin/components/FlyingContext.vue +77 -0
  23. package/src-admin/components/FlyingContextContainer.vue +85 -0
  24. package/src-admin/components/Sidebar.vue +66 -0
  25. package/src-admin/components/SidebarItem.vue +59 -0
  26. package/src-admin/components/StickyFooter.vue +42 -0
  27. package/src-admin/components/StickyFooterContainer.vue +66 -0
  28. package/src-admin/components/StickyHeader.vue +73 -0
  29. package/src-admin/components/app/AppBarButtons.vue +0 -7
  30. package/src-admin/components/app/AppBarTitle.vue +55 -11
  31. package/src-admin/components/app/AppBarTitleContainer.vue +2 -3
  32. package/src-admin/components/controls/SearchSelectFormField.vue +1 -0
  33. package/src-admin/components/detail/DetailProperty.vue +20 -16
  34. package/src-admin/components/form/EditFormButtons.vue +25 -6
  35. package/src-admin/components/form/RemoveButton.vue +17 -8
  36. package/src-admin/components/index.js +6 -7
  37. package/src-admin/components/list/ListView.vue +22 -9
  38. package/src-admin/components/pages/EditPage.vue +17 -8
  39. package/src-admin/components/routes/DataRouteMixin.js +24 -15
  40. package/src-admin/config/routing.js +0 -11
  41. package/src-admin/config/vuetify.js +22 -2
  42. package/src-admin/directives/index.js +26 -0
  43. package/src-admin/styles.scss +21 -4
  44. package/src-admin/components/pages/CreatePage.vue +0 -114
  45. package/src-admin/components/pages/DetailPage.vue +0 -143
  46. package/src-admin/components/pages/EditPageMixin.js +0 -96
  47. package/src-admin/components/pages/ListPage.vue +0 -55
  48. package/src-admin/components/routes/CreateRoute.vue +0 -15
  49. package/src-admin/components/routes/DetailRoute.vue +0 -85
  50. package/src-admin/components/routes/EditRoute.vue +0 -78
  51. package/src-admin/components/routes/ListRoute.vue +0 -110
@@ -1,4 +1,4 @@
1
- import { Component, Vue, Watch } from '@a-vue'
1
+ import { Component, Vue } from '@a-vue'
2
2
 
3
3
  Component.registerHooks([
4
4
  'beforeRouteEnter',
@@ -7,6 +7,7 @@ Component.registerHooks([
7
7
 
8
8
  let onLoadCallback = () => {}
9
9
  let routerHookCalled = false
10
+ let lastResult = null // cache last result because of hmr reload
10
11
 
11
12
  function onLoad (callback) {
12
13
  onLoadCallback = callback
@@ -52,24 +53,32 @@ export class DataRouteMixin extends Vue {
52
53
 
53
54
  /**
54
55
  * triggered both, if route name or route params change
55
- */
56
- @Watch('$route.params')
57
- async routeParamsChanged () {
58
- if (routerHookCalled) {
59
- return
60
- }
56
+ @Watch('$route.params')
57
+ async routeParamsChanged () {
58
+ if (routerHookCalled) {
59
+ return
60
+ }
61
61
 
62
- if (!this.drm_isLoaded) {
63
- const result = await load(this.$route)
62
+ if (!this.drm_isLoaded) {
63
+ const result = await load(this.$route)
64
64
 
65
- if (result !== false) {
66
- this.drm_onLoad(result)
67
- this.drm_isLoaded = true
68
- }
69
- }
70
- }
65
+ if (result !== false) {
66
+ this.drm_onLoad(result)
67
+ this.drm_isLoaded = true
68
+ }
69
+ }
70
+ }
71
+ */
71
72
 
72
73
  drm_onLoad (result) {
73
74
  onLoadCallback(this, result)
75
+ lastResult = result
76
+ }
77
+
78
+ created () {
79
+ // hmr reload creates vm but not triggers route enter
80
+ if (!routerHookCalled) {
81
+ onLoadCallback(this, lastResult)
82
+ }
74
83
  }
75
84
  }
@@ -1,7 +1,3 @@
1
- import CreateRoute from '@a-admin/components/routes/CreateRoute'
2
- import DetailRoute from '@a-admin/components/routes/DetailRoute'
3
- import EditRoute from '@a-admin/components/routes/EditRoute'
4
- import ListRoute from '@a-admin/components/routes/ListRoute'
5
1
  import { routeConfigPlugin } from '@a-vue/plugins/route-config/RouteConfigPlugin'
6
2
 
7
3
  export default routeConfigPlugin
@@ -9,13 +5,6 @@ export default routeConfigPlugin
9
5
  linkActiveClass: 'active'
10
6
  })
11
7
 
12
- .defaultComponents({
13
- list: ListRoute,
14
- new: CreateRoute,
15
- detail: DetailRoute,
16
- edit: EditRoute
17
- })
18
-
19
8
  .defaultBreadcrumbTitles({
20
9
  edit: 'Bearbeiten',
21
10
  new: 'Neu'
@@ -1,17 +1,27 @@
1
1
  import {
2
2
  mdiAlarmLightOutline,
3
+ mdiArrowLeft,
3
4
  mdiCalendar,
5
+ mdiCheck,
6
+ mdiCheckBold,
4
7
  mdiChevronRight,
5
8
  mdiClose,
9
+ mdiCloseThick,
6
10
  mdiDelete,
7
11
  mdiDotsHorizontal,
8
12
  mdiDotsVertical,
9
13
  mdiLock,
10
14
  mdiLogoutVariant,
11
15
  mdiMagnify,
16
+ mdiMenuDown,
17
+ mdiMenuUp,
12
18
  mdiPencil,
13
19
  mdiPlus,
14
- mdiThumbUpOutline
20
+ mdiThumbUpOutline,
21
+ mdiAccountGroup,
22
+ mdiShopping,
23
+ mdiMessage,
24
+ mdiPencilBoxMultiple
15
25
  } from '@mdi/js'
16
26
  import Vue from 'vue'
17
27
  import Vuetify from 'vuetify/lib'
@@ -26,6 +36,7 @@ export default new Vuetify({
26
36
  thumbsUpIcon: mdiThumbUpOutline,
27
37
  alarmIcon: mdiAlarmLightOutline,
28
38
  closeIcon: mdiClose,
39
+ closeBoldIcon: mdiCloseThick,
29
40
  dotsVerticalIcon: mdiDotsVertical,
30
41
  dotsHorizontalIcon: mdiDotsHorizontal,
31
42
  logoutIcon: mdiLogoutVariant,
@@ -34,7 +45,16 @@ export default new Vuetify({
34
45
  trashCanIcon: mdiDelete,
35
46
  calendarIcon: mdiCalendar,
36
47
  searchIcon: mdiMagnify,
37
- lockIcon: mdiLock
48
+ lockIcon: mdiLock,
49
+ checkIcon: mdiCheck,
50
+ checkBoldIcon: mdiCheckBold,
51
+ arrowLeftIcon: mdiArrowLeft,
52
+ caretDownIcon: mdiMenuDown,
53
+ caretUpIcon: mdiMenuUp,
54
+ householdMembers: mdiAccountGroup,
55
+ shop: mdiShopping,
56
+ annotation: mdiMessage,
57
+ duplicates: mdiPencilBoxMultiple
38
58
  }
39
59
  },
40
60
  breakpoint: {
@@ -0,0 +1,26 @@
1
+ import { Vue } from '@a-vue'
2
+
3
+ Vue.directive('flying-context-trigger', {
4
+ bind: function (el, bindings) {
5
+ if (bindings.value) {
6
+ el.$flyingContextObserver = new MutationObserver(() => {
7
+ if (!el.classList.contains('flyingContextTrigger')) {
8
+ el.classList.add('flyingContextTrigger')
9
+ }
10
+ })
11
+
12
+ el.$flyingContextObserver.observe(el, {
13
+ attributes: true,
14
+ attributeFilter: ['class']
15
+ })
16
+
17
+ el.classList.add('flyingContextTrigger')
18
+ }
19
+ },
20
+
21
+ unbind: function (el) {
22
+ if (el.$flyingContextObserver) {
23
+ el.$flyingContextObserver.disconnect()
24
+ }
25
+ }
26
+ })
@@ -15,6 +15,7 @@
15
15
  .contextButton {
16
16
  color: #AAAAAA !important;
17
17
  cursor: pointer;
18
+
18
19
  &:hover {
19
20
  color: #333333 !important;
20
21
  }
@@ -27,14 +28,30 @@
27
28
  }
28
29
  }
29
30
 
30
- .v-main {
31
- margin-bottom: 2rem;
32
- }
33
-
34
31
  .theme--light.v-btn.v-btn--has-bg {
35
32
  background-color: #E9E9E9;
36
33
  }
37
34
 
35
+ .theme--light.v-btn.v-btn--disabled,
36
+ .theme--light.v-btn.v-btn--disabled .v-icon,
37
+ .theme--light.v-btn.v-btn--disabled .v-btn__loading {
38
+ color: white !important;
39
+ }
40
+
41
+ .theme--light.v-btn.v-btn--disabled.v-btn--has-bg {
42
+ background-color: #EEEEEE !important;
43
+ }
44
+
45
+ .v-btn {
46
+ box-shadow: none !important;
47
+ }
48
+
49
+ // @for $i from 1 through 10 {
50
+ // .gap-{$i} {
51
+ // gap: 0.25rem * $i;
52
+ // }
53
+ // }
54
+
38
55
  .gap-0 {
39
56
  gap: 0;
40
57
  }
@@ -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>