@afeefa/vue-app 0.0.53 → 0.0.56

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.
Files changed (92) hide show
  1. package/.afeefa/package/release/version.txt +1 -1
  2. package/package.json +3 -10
  3. package/src/api-resources/ApiActions.js +31 -0
  4. package/src/components/AAlert.vue +1 -1
  5. package/src/components/AAutocomplete.vue +1 -1
  6. package/src/components/ABadge.vue +1 -1
  7. package/src/components/ABreadcrumbs.vue +1 -1
  8. package/src/components/ACheckbox.vue +35 -0
  9. package/src/components/AContextMenu.vue +2 -2
  10. package/src/components/AContextMenuItem.vue +2 -2
  11. package/src/components/ADatePicker.vue +1 -1
  12. package/src/components/ADialog.vue +3 -1
  13. package/src/components/AGrid.vue +2 -1
  14. package/src/components/AIcon.vue +1 -1
  15. package/src/components/AIconButton.vue +1 -1
  16. package/src/components/ALoadingIndicator.vue +1 -1
  17. package/src/components/AModal.vue +1 -1
  18. package/src/components/APagination.vue +1 -1
  19. package/src/components/ARadioGroup.vue +1 -1
  20. package/src/components/ARichTextArea.vue +257 -0
  21. package/src/components/ARow.vue +1 -1
  22. package/src/components/ASaveIndicator.vue +1 -1
  23. package/src/components/ASearchSelect.vue +34 -18
  24. package/src/components/ASelect.vue +1 -1
  25. package/src/components/ATable.vue +1 -1
  26. package/src/components/ATableHeader.vue +1 -1
  27. package/src/components/ATableRow.vue +1 -1
  28. package/src/components/ATextArea.vue +1 -1
  29. package/src/components/ATextField.vue +1 -1
  30. package/src/components/form/EditForm.vue +2 -6
  31. package/src/components/form/EditModal.vue +23 -18
  32. package/src/components/form/FormFieldMixin.js +2 -3
  33. package/src/components/form/fields/FormFieldCheckbox.vue +18 -0
  34. package/src/components/form/fields/FormFieldDate.vue +1 -1
  35. package/src/components/form/fields/FormFieldRadioGroup.vue +1 -1
  36. package/src/components/form/fields/FormFieldRichTextArea.vue +14 -0
  37. package/src/components/form/fields/FormFieldSearchSelect.vue +1 -1
  38. package/src/components/form/fields/FormFieldSelect.vue +1 -1
  39. package/src/components/form/fields/FormFieldSelect2.vue +1 -1
  40. package/src/components/form/fields/FormFieldText.vue +1 -1
  41. package/src/components/form/fields/FormFieldTextArea.vue +1 -1
  42. package/src/components/index.js +4 -0
  43. package/src/components/list/ListFilterMixin.js +1 -1
  44. package/src/components/list/ListFilterRow.vue +1 -1
  45. package/src/components/list/ListViewMixin.js +7 -4
  46. package/src/components/list/filters/ListFilterPage.vue +1 -1
  47. package/src/components/list/filters/ListFilterSearch.vue +1 -1
  48. package/src/components/list/filters/ListFilterSelect.vue +1 -1
  49. package/src/components/mixins/ClickOutsideMixin.js +1 -1
  50. package/src/components/mixins/ComponentWidthMixin.js +1 -1
  51. package/src/components/search-select/SearchSelectFilters.vue +1 -1
  52. package/src/components/search-select/SearchSelectList.vue +13 -3
  53. package/src/components/vue/Component.js +46 -0
  54. package/src/index.js +4 -0
  55. package/src/plugins/api-resources/ApiResourcesPlugin.js +12 -0
  56. package/src/plugins/route-config/RouteConfigPlugin.js +25 -1
  57. package/src/services/escape/CancelOnEscMixin.js +1 -1
  58. package/src/services/position/UsesPositionServiceMixin.js +1 -1
  59. package/src/styles/forms.scss +8 -0
  60. package/src/styles/vue-app.scss +1 -0
  61. package/src-admin/bootstrap.js +2 -5
  62. package/src-admin/components/App.vue +1 -1
  63. package/src-admin/components/NotFound.vue +65 -0
  64. package/src-admin/components/SidebarMenu.vue +1 -1
  65. package/src-admin/components/Splash.vue +34 -34
  66. package/src-admin/components/Start.vue +2 -2
  67. package/src-admin/components/app/AppBarButton.vue +1 -1
  68. package/src-admin/components/app/AppBarButtons.vue +1 -1
  69. package/src-admin/components/app/AppBarTitle.vue +1 -1
  70. package/src-admin/components/app/AppBarTitleContainer.vue +1 -1
  71. package/src-admin/components/controls/SearchSelectFormField.vue +223 -0
  72. package/src-admin/components/detail/DetailProperty.vue +2 -4
  73. package/src-admin/components/list/ListColumnHeader.vue +5 -4
  74. package/src-admin/components/list/ListTitle.vue +1 -1
  75. package/src-admin/components/list/ListView.vue +12 -10
  76. package/src-admin/components/menu/SidebarMenuItem.vue +1 -1
  77. package/src-admin/components/model/ModelCount.vue +1 -1
  78. package/src-admin/components/model/ModelIcon.vue +1 -1
  79. package/src-admin/components/pages/CreatePage.vue +2 -3
  80. package/src-admin/components/pages/DetailPage.vue +4 -4
  81. package/src-admin/components/pages/EditPage.vue +5 -6
  82. package/src-admin/components/pages/EditPageMixin.js +1 -1
  83. package/src-admin/components/pages/ListPage.vue +3 -4
  84. package/src-admin/components/routes/CreateRoute.vue +1 -1
  85. package/src-admin/components/routes/DetailRoute.vue +4 -4
  86. package/src-admin/components/routes/EditRoute.vue +4 -4
  87. package/src-admin/components/routes/ListRoute.vue +4 -4
  88. package/src-admin/config/vuetify.js +3 -1
  89. package/src-admin/models/Model.js +13 -0
  90. package/src-admin/models/ModelAdminConfig.js +20 -0
  91. package/src-components/AMdiIcon.vue +18 -0
  92. package/src/utils/props-helper.js +0 -21
@@ -1 +1 @@
1
- 0.0.53
1
+ 0.0.56
package/package.json CHANGED
@@ -1,20 +1,13 @@
1
1
  {
2
2
  "name": "@afeefa/vue-app",
3
- "version": "0.0.53",
3
+ "version": "0.0.56",
4
4
  "description": "",
5
5
  "author": "Afeefa Kollektiv <kollektiv@afeefa.de>",
6
6
  "license": "MIT",
7
- "scripts": {
8
- "typings": "tsc"
9
- },
10
7
  "devDependencies": {
11
- "core-js": "^3.9.1",
12
- "typescript": "^4.2.3",
13
- "vue": "^2.6.12",
8
+ "core-js": "^3.21.1",
9
+ "vue": "^2.6.14",
14
10
  "vue-class-component": "^7.2.6",
15
11
  "vue-property-decorator": "^9.1.2"
16
- },
17
- "dependencies": {
18
- "moment": "^2.29.1"
19
12
  }
20
13
  }
@@ -228,14 +228,38 @@ export class RemoveAction {
228
228
  }
229
229
 
230
230
  export class ListAction {
231
+ action = null
231
232
  request = null
233
+ params = {}
234
+ fields = {}
235
+ filters = {}
232
236
  events = true
233
237
 
238
+ setAction (action) {
239
+ this.action = action
240
+ return this
241
+ }
242
+
234
243
  setRequest (request) {
235
244
  this.request = request
236
245
  return this
237
246
  }
238
247
 
248
+ setParams (params) {
249
+ this.params = params
250
+ return this
251
+ }
252
+
253
+ setFields (fields) {
254
+ this.fields = fields
255
+ return this
256
+ }
257
+
258
+ setFilters (filters) {
259
+ this.filters = filters
260
+ return this
261
+ }
262
+
239
263
  noEvents (noEvents) {
240
264
  this.events = noEvents === undefined ? false : !noEvents
241
265
  return this
@@ -246,6 +270,13 @@ export class ListAction {
246
270
  eventBus.dispatch(new LoadingEvent(LoadingEvent.START_LOADING))
247
271
  }
248
272
 
273
+ if (!this.request) {
274
+ this.request = this.action.createRequest()
275
+ .params(this.params)
276
+ .fields(this.fields)
277
+ .filters(this.filters)
278
+ }
279
+
249
280
  const result = await this.request.send()
250
281
 
251
282
  if (result.error) {
@@ -35,7 +35,7 @@
35
35
  </template>
36
36
 
37
37
  <script>
38
- import { Component, Vue } from 'vue-property-decorator'
38
+ import { Component, Vue } from '@a-vue'
39
39
  import { AlertEvent } from './alert/AlertEvent'
40
40
 
41
41
  @Component
@@ -18,7 +18,7 @@
18
18
 
19
19
 
20
20
  <script>
21
- import { Component, Vue, Watch } from 'vue-property-decorator'
21
+ import { Component, Vue, Watch } from '@a-vue'
22
22
  import { Model } from '@afeefa/api-resources-client'
23
23
  import { debounce } from '@a-vue/utils/debounce'
24
24
 
@@ -7,7 +7,7 @@
7
7
 
8
8
 
9
9
  <script>
10
- import { Component, Vue, Watch } from 'vue-property-decorator'
10
+ import { Component, Vue, Watch } from '@a-vue'
11
11
 
12
12
  @Component({
13
13
  props: ['content']
@@ -19,7 +19,7 @@
19
19
 
20
20
 
21
21
  <script>
22
- import { Component, Vue, Watch } from 'vue-property-decorator'
22
+ import { Component, Vue, Watch } from '@a-vue'
23
23
  import { SaveEvent } from './save-indicator/SaveEvent'
24
24
  import { routeConfigPlugin } from '@a-vue/plugins/route-config/RouteConfigPlugin'
25
25
 
@@ -0,0 +1,35 @@
1
+ <template>
2
+ <v-checkbox
3
+ ref="checkbox"
4
+ v-bind="$attrs"
5
+ :inputValue="$attrs.value"
6
+ @change="$emit('input', $event || false)"
7
+ />
8
+ </template>
9
+
10
+
11
+ <script>
12
+ import { Component, Vue } from '@a-vue'
13
+
14
+ @Component({
15
+ props: ['validator']
16
+ })
17
+ export default class ACheckbox extends Vue {
18
+ created () {
19
+ this.init()
20
+ }
21
+
22
+ async init () {
23
+ if (this.validator) {
24
+ this.$nextTick(() => {
25
+ this.$refs.checkbox.validate(true)
26
+ })
27
+ }
28
+ }
29
+
30
+ get validationRules () {
31
+ const label = this.$attrs.label
32
+ return (this.validator && this.validator.getRules(label)) || []
33
+ }
34
+ }
35
+ </script>
@@ -25,7 +25,7 @@
25
25
  </template>
26
26
 
27
27
  <script>
28
- import { Component, Mixins, Watch } from 'vue-property-decorator'
28
+ import { Component, Mixins, Watch } from '@a-vue'
29
29
  import { UsesPositionServiceMixin } from '../services/position/UsesPositionServiceMixin'
30
30
  import { Positions, PositionConfig } from '../services/PositionService'
31
31
  import { randomCssClass } from '../utils/random'
@@ -140,7 +140,7 @@ export default class AContextMenu extends Mixins(UsesPositionServiceMixin) {
140
140
  .popUpContent {
141
141
  min-height: 2.2rem;
142
142
  position: absolute;
143
- z-index: 200;
143
+ z-index: 400;
144
144
  display: block;
145
145
  background-color: white;
146
146
  padding: 0.5rem;
@@ -8,7 +8,7 @@
8
8
  </template>
9
9
 
10
10
  <script>
11
- import { Component, Vue } from 'vue-property-decorator'
11
+ import { Component, Vue } from '@a-vue'
12
12
 
13
13
  @Component({
14
14
  props: ['to']
@@ -29,7 +29,7 @@ export default class AContextMenuItem extends Vue {
29
29
  this.contextMenu.close()
30
30
  if (this.to) {
31
31
  this.$router.push(this.to)
32
- .catch(() => null) // prevent duplicated navigation
32
+ .catch(() => null) // prevent duplicated navigation warning
33
33
  } else {
34
34
  this.$emit('click')
35
35
  }
@@ -29,7 +29,7 @@
29
29
 
30
30
 
31
31
  <script>
32
- import { Component, Mixins, Watch } from 'vue-property-decorator'
32
+ import { Component, Mixins, Watch } from '@a-vue'
33
33
  import { formatDate } from '@a-vue/utils/format-date'
34
34
  import { ComponentWidthMixin } from './mixins/ComponentWidthMixin'
35
35
 
@@ -54,7 +54,7 @@
54
54
  </template>
55
55
 
56
56
  <script>
57
- import { Component, Mixins, Watch } from 'vue-property-decorator'
57
+ import { Component, Mixins, Watch } from '@a-vue'
58
58
  import { DialogEvent } from './dialog/DialogEvent'
59
59
  import { PositionConfig } from '../services/PositionService'
60
60
  import { UsesPositionServiceMixin } from '../services/position/UsesPositionServiceMixin'
@@ -132,6 +132,8 @@ export default class ADialog extends Mixins(UsesPositionServiceMixin) {
132
132
  if (!Array.isArray(anchor)) {
133
133
  if (typeof anchor === 'string') {
134
134
  anchor = [document.documentElement, anchor]
135
+ } else if (typeof anchor === 'object') { // dom element or vue ref
136
+ anchor = [anchor]
135
137
  } else {
136
138
  anchor = [document.documentElement]
137
139
  }
@@ -6,7 +6,7 @@
6
6
 
7
7
 
8
8
  <script>
9
- import { Component, Vue } from 'vue-property-decorator'
9
+ import { Component, Vue } from '@a-vue'
10
10
 
11
11
  @Component({
12
12
  props: ['fullWidth', 'gap', 'hGap', 'vGap', 'cols', 'even', 'breakMobile']
@@ -91,6 +91,7 @@ export default class AGrid extends Vue {
91
91
  grid-template-columns: repeat(5, 1fr);
92
92
  }
93
93
  }
94
+
94
95
  &.breakMobile {
95
96
  @media (max-width: 900px), (orientation : portrait) {
96
97
  grid-template-columns: 1fr;
@@ -10,7 +10,7 @@
10
10
 
11
11
 
12
12
  <script>
13
- import { Component, Vue } from 'vue-property-decorator'
13
+ import { Component, Vue } from '@a-vue'
14
14
 
15
15
  @Component({
16
16
  props: ['button']
@@ -16,7 +16,7 @@
16
16
 
17
17
 
18
18
  <script>
19
- import { Component, Vue } from 'vue-property-decorator'
19
+ import { Component, Vue } from '@a-vue'
20
20
 
21
21
  @Component({
22
22
  props: ['icon', 'text']
@@ -9,7 +9,7 @@
9
9
  </template>
10
10
 
11
11
  <script>
12
- import { Component, Vue, Watch } from 'vue-property-decorator'
12
+ import { Component, Vue, Watch } from '@a-vue'
13
13
 
14
14
  @Component({
15
15
  props: ['isLoading']
@@ -33,7 +33,7 @@
33
33
  </template>
34
34
 
35
35
  <script>
36
- import { Component, Mixins, Watch } from 'vue-property-decorator'
36
+ import { Component, Mixins, Watch } from '@a-vue'
37
37
  import { PositionConfig } from '../services/PositionService'
38
38
  import { UsesPositionServiceMixin } from '@a-vue/services/position/UsesPositionServiceMixin'
39
39
  import { randomCssClass } from '../utils/random'
@@ -13,7 +13,7 @@
13
13
 
14
14
 
15
15
  <script>
16
- import { Component, Vue } from 'vue-property-decorator'
16
+ import { Component, Vue } from '@a-vue'
17
17
 
18
18
  @Component({
19
19
  props: ['content']
@@ -18,7 +18,7 @@
18
18
 
19
19
 
20
20
  <script>
21
- import { Component, Vue, Watch } from 'vue-property-decorator'
21
+ import { Component, Vue, Watch } from '@a-vue'
22
22
 
23
23
  @Component({
24
24
  props: ['options', 'validator']
@@ -0,0 +1,257 @@
1
+ <template>
2
+ <div :class="['a-rich-text-editor a-text-input', {'a-text-input-focused': focus}]">
3
+ <div
4
+ v-if="editor"
5
+ class="menu-bar"
6
+ >
7
+ <v-btn
8
+ small
9
+ :class="['menu-button', {'is-active': focus && editor.isActive('bold')}]"
10
+ @click="editor.chain().focus().toggleBold().run()"
11
+ >
12
+ <v-icon>{{ boldIcon }}</v-icon>
13
+ </v-btn>
14
+
15
+ <v-btn
16
+ small
17
+ :class="['menu-button', {'is-active': focus && editor.isActive('italic')}]"
18
+ @click="editor.chain().focus().toggleItalic().run()"
19
+ >
20
+ <v-icon>{{ italicIcon }}</v-icon>
21
+ </v-btn>
22
+
23
+ <v-btn
24
+ small
25
+ :class="['menu-button', 'strike', {'is-active': focus && editor.isActive('strike')}]"
26
+ @click="editor.chain().focus().toggleStrike().run()"
27
+ >
28
+ <v-icon>{{ strikeIcon }}</v-icon>
29
+ </v-btn>
30
+
31
+ <v-btn
32
+ small
33
+ :class="['menu-button', {'is-active': focus && editor.isActive('heading', {level: 1})}]"
34
+ @click="editor.chain().focus().toggleHeading({level: 1}).run()"
35
+ >
36
+ <v-icon>{{ h1Icon }}</v-icon>
37
+ </v-btn>
38
+
39
+ <v-btn
40
+ small
41
+ :class="['menu-button', {'is-active': focus && editor.isActive('heading', {level: 2})}]"
42
+ @click="editor.chain().focus().toggleHeading({level: 2}).run()"
43
+ >
44
+ <v-icon>{{ h2Icon }}</v-icon>
45
+ </v-btn>
46
+
47
+ <v-btn
48
+ small
49
+ :class="['menu-button', {'is-active': focus && editor.isActive('bulletList')}]"
50
+ @click="editor.chain().focus().toggleBulletList().run()"
51
+ >
52
+ <v-icon>{{ ulIcon }}</v-icon>
53
+ </v-btn>
54
+
55
+ <v-btn
56
+ small
57
+ :class="['menu-button', {'is-active': focus && editor.isActive('orderedList')}]"
58
+ @click="editor.chain().focus().toggleOrderedList().run()"
59
+ >
60
+ <v-icon>{{ olIcon }}</v-icon>
61
+ </v-btn>
62
+
63
+ <v-btn
64
+ small
65
+ :class="['menu-button', {'is-active': focus && editor.isActive('blockquote')}]"
66
+ @click="editor.chain().focus().toggleBlockquote().run()"
67
+ >
68
+ <v-icon>{{ commentIcon }}</v-icon>
69
+ </v-btn>
70
+
71
+ <v-btn
72
+ small
73
+ class="menu-button"
74
+ @click="editor.chain().focus().undo().run()"
75
+ >
76
+ <v-icon>{{ undoIcon }}</v-icon>
77
+ </v-btn>
78
+
79
+ <v-btn
80
+ small
81
+ class="menu-button"
82
+ @click="editor.chain().focus().redo().run()"
83
+ >
84
+ <v-icon>{{ redoIcon }}</v-icon>
85
+ </v-btn>
86
+ </div>
87
+
88
+ <editor-content
89
+ :editor="editor"
90
+ :class="['a-rich-text-editor', {focus}]"
91
+ />
92
+ </div>
93
+ </template>
94
+
95
+
96
+ <script>
97
+ import { Component, Vue, Watch } from '@a-vue'
98
+ import { Editor, EditorContent } from '@tiptap/vue-2'
99
+ import StarterKit from '@tiptap/starter-kit'
100
+ import {
101
+ mdiFormatBold,
102
+ mdiFormatItalic,
103
+ mdiFormatStrikethroughVariant,
104
+ mdiFormatHeader1,
105
+ mdiFormatHeader2,
106
+ mdiFormatListBulleted,
107
+ mdiFormatListNumbered,
108
+ mdiFormatQuoteClose,
109
+ mdiRotateLeft,
110
+ mdiRotateRight
111
+ } from '@mdi/js'
112
+
113
+ @Component({
114
+ props: ['value', 'validator'],
115
+ components: {
116
+ EditorContent
117
+ }
118
+ })
119
+ export default class ARichTextArea extends Vue {
120
+ editor = null
121
+ internalValue = null
122
+ focus = false
123
+
124
+ boldIcon = mdiFormatBold
125
+ italicIcon = mdiFormatItalic
126
+ strikeIcon = mdiFormatStrikethroughVariant
127
+ h1Icon = mdiFormatHeader1
128
+ h2Icon = mdiFormatHeader2
129
+ ulIcon = mdiFormatListBulleted
130
+ olIcon = mdiFormatListNumbered
131
+ commentIcon = mdiFormatQuoteClose
132
+ undoIcon = mdiRotateLeft
133
+ redoIcon = mdiRotateRight
134
+
135
+ created () {
136
+ this.internalValue = this.value
137
+ }
138
+
139
+ mounted () {
140
+ if (this.validator) {
141
+ this.$refs.input.validate(true)
142
+ }
143
+
144
+ this.editor = new Editor({
145
+ content: this.internalValue,
146
+ extensions: [
147
+ StarterKit
148
+ ],
149
+ onUpdate: () => {
150
+ this.$emit('input', this.editor.getHTML())
151
+ },
152
+ onFocus: ({ editor, event }) => {
153
+ this.focus = true
154
+ },
155
+ onBlur: ({ editor, event }) => {
156
+ this.focus = false
157
+ }
158
+ })
159
+
160
+ this.editor.commands.setContent(this.internalValue, false)
161
+ }
162
+
163
+ beforeDestroy () {
164
+ this.editor.destroy()
165
+ }
166
+
167
+ @Watch('value')
168
+ valueChanged () {
169
+ this.internalValue = this.value
170
+
171
+ const isSame = this.editor.getHTML() === this.internalValue
172
+ if (!isSame) {
173
+ this.editor.commands.setContent(this.internalValue, false)
174
+ }
175
+ }
176
+
177
+ get validationRules () {
178
+ const label = this.$attrs.label
179
+ return (this.validator && this.validator.getRules(label)) || []
180
+ }
181
+
182
+ get counter () {
183
+ if (!this.validator) {
184
+ return false
185
+ }
186
+ return this.validator.getParams().max || false
187
+ }
188
+ }
189
+ </script>
190
+
191
+
192
+ <style lang="scss" scoped>
193
+ .v-input:not(.v-input--is-focused) ::v-deep .v-counter {
194
+ display: none;
195
+ }
196
+
197
+ .a-rich-text-editor {
198
+ ::v-deep .ProseMirror {
199
+ &-focused {
200
+ outline: none;
201
+ }
202
+ }
203
+ }
204
+
205
+ .menu-bar {
206
+ margin: -.2rem 0 .5rem -.2rem;
207
+ }
208
+
209
+ .menu-button {
210
+ padding: 0 !important;
211
+ width: 30px !important;
212
+ height: 32px !important;
213
+ min-width: unset !important;
214
+ text-align: center;
215
+ font-size: 1rem;
216
+ background: white !important;
217
+ border: none;
218
+ box-shadow: none;
219
+ border-radius: 0;
220
+
221
+ ::v-deep .v-icon {
222
+ font-size: 20px;
223
+ width: 20px;
224
+ height: 20px;
225
+ }
226
+
227
+ &.strike {
228
+ ::v-deep .v-icon {
229
+ width: 15px;
230
+ }
231
+ }
232
+
233
+ svg {
234
+ width: unset;
235
+ }
236
+
237
+ &.is-active {
238
+ background: #ECECEC !important;
239
+ }
240
+ }
241
+
242
+ ::v-deep .ProseMirror {
243
+ min-height: 200px;
244
+
245
+ > :last-child {
246
+ margin: 0;
247
+ }
248
+
249
+ li p {
250
+ margin: 0;
251
+ }
252
+
253
+ ul {
254
+ margin: 16px 0;
255
+ }
256
+ }
257
+ </style>
@@ -6,7 +6,7 @@
6
6
 
7
7
 
8
8
  <script>
9
- import { Component, Vue } from 'vue-property-decorator'
9
+ import { Component, Vue } from '@a-vue'
10
10
 
11
11
  @Component({
12
12
  props: ['fullWidth', 'gap', 'start', 'stretch', 'center', 'vertical', 'right']
@@ -14,7 +14,7 @@
14
14
 
15
15
 
16
16
  <script>
17
- import { Component, Vue } from 'vue-property-decorator'
17
+ import { Component, Vue } from '@a-vue'
18
18
  import { SaveEvent } from './save-indicator/SaveEvent'
19
19
 
20
20
  @Component