@afeefa/vue-app 0.0.76 → 0.0.79
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/SaveAction.js +1 -1
- package/src/components/AAlert.vue +8 -2
- package/src/components/ADialog.vue +4 -4
- package/src/components/AModal.vue +2 -2
- package/src/components/ARadioGroup.vue +6 -2
- package/src/components/ATextField.vue +6 -0
- package/src/components/form/EditForm.vue +10 -0
- package/src/components/form/FormFieldMixin.js +19 -2
- package/src/components/form/fields/FormFieldText.vue +1 -0
- package/src/utils/debounce.js +4 -0
- package/src-admin/components/App.vue +1 -0
- package/src-admin/components/StickyHeader.vue +1 -0
- package/src-admin/components/form/EditFormButtons.vue +30 -19
- package/src-admin/components/form/RemoveButton.vue +5 -6
- package/src-admin/components/pages/EditPage.vue +2 -1
- package/src-admin/styles.scss +28 -0
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.79
|
package/package.json
CHANGED
@@ -18,7 +18,7 @@ export class SaveAction extends ApiAction {
|
|
18
18
|
|
19
19
|
processError (result) {
|
20
20
|
eventBus.dispatch(new AlertEvent(AlertEvent.ERROR, {
|
21
|
-
headline: 'Die Daten
|
21
|
+
headline: 'Die Daten konnten nicht gespeichert werden.',
|
22
22
|
message: result.message,
|
23
23
|
detail: result.detail
|
24
24
|
}))
|
@@ -17,9 +17,10 @@
|
|
17
17
|
<h3>{{ _headline }}</h3>
|
18
18
|
|
19
19
|
<div v-html="message" />
|
20
|
+
|
20
21
|
<div
|
21
22
|
v-if="detail"
|
22
|
-
class="pt-
|
23
|
+
class="pt-1 details"
|
23
24
|
v-html="detail"
|
24
25
|
/>
|
25
26
|
</div>
|
@@ -126,7 +127,12 @@ export default class AAlert extends Vue {
|
|
126
127
|
|
127
128
|
h3 {
|
128
129
|
margin-bottom: .5rem;
|
129
|
-
font-size: 1.
|
130
|
+
font-size: 1.2rem;
|
131
|
+
line-height: 1.2;
|
132
|
+
}
|
133
|
+
|
134
|
+
.details {
|
135
|
+
font-size: .9rem;
|
130
136
|
}
|
131
137
|
|
132
138
|
.closeButton {
|
@@ -19,7 +19,7 @@
|
|
19
19
|
v-if="dialog"
|
20
20
|
class="pb-1"
|
21
21
|
>
|
22
|
-
<v-card-title>
|
22
|
+
<v-card-title class="pa-3">
|
23
23
|
{{ title }}
|
24
24
|
</v-card-title>
|
25
25
|
|
@@ -27,7 +27,7 @@
|
|
27
27
|
<span v-html="message" />
|
28
28
|
</v-card-text>
|
29
29
|
|
30
|
-
<v-card-text>
|
30
|
+
<v-card-text v-if="$slots.default">
|
31
31
|
<slot :props="props" />
|
32
32
|
</v-card-text>
|
33
33
|
|
@@ -209,11 +209,11 @@ export default class ADialog extends Mixins(UsesPositionServiceMixin, CancelOnEs
|
|
209
209
|
<style lang="scss" scoped>
|
210
210
|
.v-card__title {
|
211
211
|
background: #EEEEEE;
|
212
|
-
padding: .
|
212
|
+
padding: .6rem 1rem .3rem !important;
|
213
213
|
}
|
214
214
|
|
215
215
|
.v-card__text {
|
216
|
-
padding: .
|
216
|
+
padding: .8rem 1rem !important;
|
217
217
|
}
|
218
218
|
|
219
219
|
::v-deep .v-dialog {
|
@@ -181,11 +181,11 @@ export default class ADialog extends Mixins(UsesPositionServiceMixin, ComponentW
|
|
181
181
|
<style lang="scss" scoped>
|
182
182
|
.v-card__title {
|
183
183
|
background: #EEEEEE;
|
184
|
-
padding: .
|
184
|
+
padding: .6rem 1rem .3rem !important;
|
185
185
|
}
|
186
186
|
|
187
187
|
.v-card__text {
|
188
|
-
padding: .
|
188
|
+
padding: .8rem 1rem !important;
|
189
189
|
color: inherit !important;
|
190
190
|
}
|
191
191
|
|
@@ -9,9 +9,12 @@
|
|
9
9
|
<template v-for="option in options_">
|
10
10
|
<v-radio
|
11
11
|
:key="option.itemText"
|
12
|
-
:label="option.itemText"
|
13
12
|
:value="option.itemValue"
|
14
|
-
|
13
|
+
>
|
14
|
+
<template #label>
|
15
|
+
<div v-html="option.itemText" />
|
16
|
+
</template>
|
17
|
+
</v-radio>
|
15
18
|
</template>
|
16
19
|
</v-radio-group>
|
17
20
|
</template>
|
@@ -62,6 +65,7 @@ export default class ARadioGroup extends Vue {
|
|
62
65
|
|
63
66
|
<style lang="scss" scoped>
|
64
67
|
.v-input {
|
68
|
+
margin: 0;
|
65
69
|
|
66
70
|
&:not(.hasLabel) {
|
67
71
|
::v-deep legend {
|
@@ -22,6 +22,8 @@ import { ComponentWidthMixin } from './mixins/ComponentWidthMixin'
|
|
22
22
|
props: ['focus', 'debounce', 'validator', {password: false, number: false}]
|
23
23
|
})
|
24
24
|
export default class ATextField extends Mixins(ComponentWidthMixin) {
|
25
|
+
$hasOptions = ['counter']
|
26
|
+
|
25
27
|
showPassword = false
|
26
28
|
|
27
29
|
created () {
|
@@ -83,6 +85,10 @@ export default class ATextField extends Mixins(ComponentWidthMixin) {
|
|
83
85
|
}
|
84
86
|
|
85
87
|
get counter () {
|
88
|
+
if (!this.$has.counter) {
|
89
|
+
return false
|
90
|
+
}
|
91
|
+
|
86
92
|
if (!this.validator) {
|
87
93
|
return false
|
88
94
|
}
|
@@ -9,6 +9,7 @@
|
|
9
9
|
:valid="valid"
|
10
10
|
:modelToEdit="modelToEdit"
|
11
11
|
:model="model"
|
12
|
+
:getField="getField"
|
12
13
|
/>
|
13
14
|
</v-form>
|
14
15
|
</template>
|
@@ -35,6 +36,15 @@ export default class EditForm extends Vue {
|
|
35
36
|
this.reset()
|
36
37
|
}
|
37
38
|
|
39
|
+
getField = name => {
|
40
|
+
const modelType = this.$apiResources.getType(this.model.type)
|
41
|
+
const update = !!this.model.id
|
42
|
+
const fields = update
|
43
|
+
? modelType.getUpdateFields()
|
44
|
+
: modelType.getCreateFields()
|
45
|
+
return fields[name]
|
46
|
+
}
|
47
|
+
|
38
48
|
forceUnchanged () {
|
39
49
|
this.forcedUnchange = true
|
40
50
|
this.$emit('update:changed', false)
|
@@ -2,7 +2,7 @@ import { Component, Vue } from '@a-vue'
|
|
2
2
|
import { ListAction } from '@a-vue/api-resources/ApiActions'
|
3
3
|
|
4
4
|
@Component({
|
5
|
-
props: ['name', 'label']
|
5
|
+
props: ['name', 'label', 'additionalRules']
|
6
6
|
})
|
7
7
|
export class FormFieldMixin extends Vue {
|
8
8
|
get model () {
|
@@ -69,7 +69,18 @@ export class FormFieldMixin extends Vue {
|
|
69
69
|
}
|
70
70
|
|
71
71
|
if (field.hasOptions()) {
|
72
|
-
|
72
|
+
let options = field.getOptions()
|
73
|
+
|
74
|
+
if (!Array.isArray(options)) {
|
75
|
+
options = Object.entries(options).map(([key, title]) => {
|
76
|
+
return {
|
77
|
+
itemText: title,
|
78
|
+
itemValue: key
|
79
|
+
}
|
80
|
+
})
|
81
|
+
return options
|
82
|
+
}
|
83
|
+
|
73
84
|
return options.map((value, index) => {
|
74
85
|
if (typeof value === 'object') { // object option
|
75
86
|
return {
|
@@ -87,6 +98,12 @@ export class FormFieldMixin extends Vue {
|
|
87
98
|
}
|
88
99
|
|
89
100
|
get validator () {
|
101
|
+
const validator = this.field.getValidator()
|
102
|
+
if (this.additionalRules) {
|
103
|
+
this.additionalRules.forEach(validate => {
|
104
|
+
validator.addRule(validate)
|
105
|
+
})
|
106
|
+
}
|
90
107
|
return this.field.getValidator()
|
91
108
|
}
|
92
109
|
|
package/src/utils/debounce.js
CHANGED
@@ -11,6 +11,10 @@ export function debounce (callback, delay = 300, condition = () => true) {
|
|
11
11
|
clearTimeout(timeout)
|
12
12
|
}
|
13
13
|
|
14
|
+
/**
|
15
|
+
* fire immediately if condition falsy
|
16
|
+
* e.g. textfield content gets canceled using (x)
|
17
|
+
*/
|
14
18
|
if (!condition(...args)) {
|
15
19
|
callback(...args)
|
16
20
|
return
|
@@ -3,18 +3,32 @@
|
|
3
3
|
gap="1"
|
4
4
|
v-bind="$attrs"
|
5
5
|
>
|
6
|
-
<v-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
6
|
+
<v-tooltip bottom>
|
7
|
+
<template #activator="{ on }">
|
8
|
+
<div v-on="disabled ? on : null">
|
9
|
+
<v-btn
|
10
|
+
fab
|
11
|
+
small
|
12
|
+
:disabled="disabled"
|
13
|
+
color="green white--text"
|
14
|
+
title="Speichern"
|
15
|
+
@click="$emit('save')"
|
16
|
+
>
|
17
|
+
<v-icon>
|
18
|
+
$checkIcon
|
19
|
+
</v-icon>
|
20
|
+
</v-btn>
|
21
|
+
</div>
|
22
|
+
</template>
|
23
|
+
<span v-if="disabled">
|
24
|
+
<template v-if="!valid">
|
25
|
+
Daten berichtigen,<br>um zu speichern
|
26
|
+
</template>
|
27
|
+
<template v-else>
|
28
|
+
Daten ändern,<br>um zu speichern
|
29
|
+
</template>
|
30
|
+
</span>
|
31
|
+
</v-tooltip>
|
18
32
|
|
19
33
|
<v-hover
|
20
34
|
v-if="$has.reset && changed"
|
@@ -49,12 +63,9 @@ export default class EditFormButtons extends Vue {
|
|
49
63
|
$hasOptions = ['reset']
|
50
64
|
|
51
65
|
undoIcon = mdiRotateLeft
|
52
|
-
}
|
53
|
-
</script>
|
54
|
-
|
55
66
|
|
56
|
-
|
57
|
-
.
|
58
|
-
|
67
|
+
get disabled () {
|
68
|
+
return (this.$has.reset && !this.changed) || !this.valid
|
69
|
+
}
|
59
70
|
}
|
60
|
-
</
|
71
|
+
</script>
|
@@ -2,14 +2,14 @@
|
|
2
2
|
<div>
|
3
3
|
<v-hover v-slot="{ hover }">
|
4
4
|
<v-btn
|
5
|
-
:class="'removeButton-' + dialogId"
|
5
|
+
:class="'a-btn-standard removeButton-' + dialogId"
|
6
6
|
fab
|
7
7
|
x-small
|
8
8
|
:color="(hover ? 'red' : 'grey lighten-3')"
|
9
|
-
title="
|
9
|
+
:title="title"
|
10
10
|
@click="remove"
|
11
11
|
>
|
12
|
-
<v-icon
|
12
|
+
<v-icon class="white--hover">
|
13
13
|
$trashCanIcon
|
14
14
|
</v-icon>
|
15
15
|
</v-btn>
|
@@ -17,7 +17,7 @@
|
|
17
17
|
|
18
18
|
<a-dialog
|
19
19
|
:id="dialogId"
|
20
|
-
:anchor="
|
20
|
+
:anchor="'.removeButton-' + dialogId"
|
21
21
|
:active="protect ? removeKey === removeConfirmed : true"
|
22
22
|
>
|
23
23
|
<template v-if="protect">
|
@@ -41,11 +41,10 @@ import { DialogEvent } from '@a-vue/events'
|
|
41
41
|
import { randomCssClass } from '@a-vue/utils/random'
|
42
42
|
|
43
43
|
@Component({
|
44
|
-
props: ['itemTitle', 'protect']
|
44
|
+
props: ['title', 'itemTitle', 'protect']
|
45
45
|
})
|
46
46
|
export default class EditPage extends Vue {
|
47
47
|
dialogId = randomCssClass(10)
|
48
|
-
document = document
|
49
48
|
removeKey = null
|
50
49
|
removeConfirmed = null
|
51
50
|
|
@@ -8,11 +8,12 @@
|
|
8
8
|
:createModelToEdit="createModelToEdit"
|
9
9
|
v-on="$listeners"
|
10
10
|
>
|
11
|
-
<template #form="{modelToEdit, model, changed, valid}">
|
11
|
+
<template #form="{modelToEdit, model, getField, changed, valid}">
|
12
12
|
<slot
|
13
13
|
name="form"
|
14
14
|
:modelToEdit="modelToEdit"
|
15
15
|
:model="model"
|
16
|
+
:getField="getField"
|
16
17
|
:changed="changed"
|
17
18
|
:valid="valid"
|
18
19
|
/>
|
package/src-admin/styles.scss
CHANGED
@@ -28,11 +28,39 @@
|
|
28
28
|
}
|
29
29
|
}
|
30
30
|
|
31
|
+
.theme--light.v-btn.a-btn-standard {
|
32
|
+
background-color: #E9E9E9;
|
33
|
+
|
34
|
+
&:not(:hover) {
|
35
|
+
background-color: #EEEEEE !important;
|
36
|
+
border-color: #EEEEEE !important;
|
37
|
+
}
|
38
|
+
|
39
|
+
span,
|
40
|
+
.v-icon {
|
41
|
+
color: grey !important;
|
42
|
+
}
|
43
|
+
|
44
|
+
&:hover {
|
45
|
+
span,
|
46
|
+
.v-icon {
|
47
|
+
&.white--hover {
|
48
|
+
color: white !important;
|
49
|
+
}
|
50
|
+
}
|
51
|
+
}
|
52
|
+
}
|
53
|
+
|
31
54
|
.theme--light.v-btn.v-btn--has-bg {
|
32
55
|
background-color: #E9E9E9;
|
33
56
|
}
|
34
57
|
|
58
|
+
.theme--light.v-btn:focus::before {
|
59
|
+
opacity: .08;
|
60
|
+
}
|
61
|
+
|
35
62
|
.theme--light.v-btn.v-btn--disabled,
|
63
|
+
.theme--light.v-btn.v-btn--disabled span,
|
36
64
|
.theme--light.v-btn.v-btn--disabled .v-icon,
|
37
65
|
.theme--light.v-btn.v-btn--disabled .v-btn__loading {
|
38
66
|
color: white !important;
|