@afeefa/vue-app 0.0.299 → 0.0.300

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.
@@ -1 +1 @@
1
- 0.0.299
1
+ 0.0.300
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@afeefa/vue-app",
3
- "version": "0.0.299",
3
+ "version": "0.0.300",
4
4
  "description": "",
5
5
  "author": "Afeefa Kollektiv <kollektiv@afeefa.de>",
6
6
  "license": "MIT",
@@ -81,6 +81,11 @@ export default class ADatePicker extends Mixins(ComponentWidthMixin, UsesPositio
81
81
  this.setFocus()
82
82
  }
83
83
 
84
+ @Watch('formattedDate')
85
+ formattedDateChanged () {
86
+ this.$emit('displayedDateChanged', this.formattedDate)
87
+ }
88
+
84
89
  get clearable () {
85
90
  if (this.validator && this.validator.getParam('filled')) {
86
91
  return false
@@ -1,5 +1,8 @@
1
1
  <template>
2
- <a-row gap="3">
2
+ <a-row
3
+ gap="3"
4
+ class="aPagination"
5
+ >
3
6
  <v-pagination
4
7
  ref="pagination"
5
8
  class="pagination-nav"
@@ -35,6 +38,7 @@ export default class APagination extends Vue {
35
38
  <style scoped lang="scss">
36
39
  :deep(.v-pagination) {
37
40
  gap: .3rem;
41
+
38
42
  .v-pagination__item,
39
43
  .v-pagination__more,
40
44
  .v-pagination__navigation {
@@ -8,6 +8,7 @@
8
8
  :multiple="multiple"
9
9
  v-bind="{...$attrs, dense, outlined}"
10
10
  v-on="$listeners"
11
+ @change="selectedItemTitleChanged"
11
12
  />
12
13
  </template>
13
14
 
@@ -47,6 +48,14 @@ export default class ASelect extends Mixins(ComponentWidthMixin) {
47
48
  this.init()
48
49
  }
49
50
 
51
+ @Watch('$attrs.value')
52
+ selectedItemTitleChanged () {
53
+ this.$nextTick(() => {
54
+ const title = this.$refs.select?.selectedItems[0]?.itemTitle
55
+ this.$emit('selectedItemTitleChanged', title)
56
+ })
57
+ }
58
+
50
59
  @Watch('items')
51
60
  itemsChanged () {
52
61
  this.init()
@@ -86,6 +95,8 @@ export default class ASelect extends Mixins(ComponentWidthMixin) {
86
95
  this.items_ = items
87
96
  }
88
97
 
98
+ this.selectedItemTitleChanged()
99
+
89
100
  if (this.validator) {
90
101
  this.$nextTick(() => {
91
102
  const valid = this.select.validate(true)
@@ -95,6 +106,8 @@ export default class ASelect extends Mixins(ComponentWidthMixin) {
95
106
  this.select.selectedItems = [{
96
107
  itemTitle: 'Ungültiger Wert'
97
108
  }]
109
+
110
+ this.selectedItemTitleChanged()
98
111
  }
99
112
  })
100
113
  }
@@ -21,6 +21,7 @@ import ListFilterSearch from './list/filters/ListFilterSearch'
21
21
  import ListFilterSearch2 from './list/filters/ListFilterSearch2'
22
22
  import ListFilterSearchSelect from './list/filters/ListFilterSearchSelect'
23
23
  import ListFilterSelect from './list/filters/ListFilterSelect'
24
+ import ListFilterBar from './list/ListFilterBar'
24
25
 
25
26
  Vue.component('EditForm', EditForm)
26
27
  Vue.component('NestedEditForm', NestedEditForm)
@@ -43,3 +44,4 @@ Vue.component('ListFilterSearch2', ListFilterSearch2)
43
44
  Vue.component('ListFilterSelect', ListFilterSelect)
44
45
  Vue.component('ListFilterSearchSelect', ListFilterSearchSelect)
45
46
  Vue.component('ListFilterDate', ListFilterDate)
47
+ Vue.component('ListFilterBar', ListFilterBar)
@@ -0,0 +1,177 @@
1
+ <template>
2
+ <div class="listFilterBar">
3
+ <a-row>
4
+ <list-filter-search2
5
+ label="Suche"
6
+ maxWidth="220"
7
+ :translateOption="title => {
8
+ return title
9
+ .replace('Sprint', $t('SPRINT'))
10
+ .replace('Kunde', $t('KUNDE'))
11
+ }"
12
+ />
13
+
14
+ <div
15
+ class="filterToggle"
16
+ @click="collapsed = !collapsed"
17
+ >
18
+ <a-row>
19
+ <v-icon
20
+ class="mr-2"
21
+ color="#CCCCCC"
22
+ >
23
+ $filterIcon
24
+ </v-icon>
25
+
26
+ <div>Filter {{ countSelectedFilters }}/{{ countFilters }}</div>
27
+
28
+ <v-icon
29
+ class="contextButton"
30
+ size="2rem"
31
+ >
32
+ {{ collapsed ? '$caretRightIcon' : '$caretDownIcon' }}
33
+ </v-icon>
34
+ </a-row>
35
+ </div>
36
+ </a-row>
37
+
38
+ <collapse-transition>
39
+ <div
40
+ v-show="!collapsed"
41
+ class="content"
42
+ >
43
+ <a-grid
44
+ ref="filterGrid"
45
+ gap="3"
46
+ cols="3"
47
+ even
48
+ class="mt-4 pa-4"
49
+ style="background: #F4F4F4;"
50
+ >
51
+ <slot />
52
+ </a-grid>
53
+ </div>
54
+ </collapse-transition>
55
+
56
+ <div
57
+ v-if="collapsed"
58
+ :class="['chip-container', selectedFilters.length ? 'mt-4' : '']"
59
+ >
60
+ <v-chip
61
+ v-for="filter in selectedFilters"
62
+ :key="filter.name"
63
+ color="#EEEEEE"
64
+ text-color="#666666"
65
+ close
66
+ @click:close="resetFilter(filter.name)"
67
+ >
68
+ <div>{{ filter.label }}: <b>{{ filter.value }}</b></div>
69
+ </v-chip>
70
+ </div>
71
+
72
+ <list-filter-page />
73
+ </div>
74
+ </template>
75
+
76
+
77
+ <script>
78
+ import { Component, Vue } from '@a-vue'
79
+ import { ListFilterEvent } from '@a-vue/events'
80
+
81
+ @Component
82
+ export default class ListFilterBar extends Vue {
83
+ collapsed = true
84
+ selectedFilters = []
85
+
86
+ created () {
87
+ this.$events.on(ListFilterEvent.CHANGE, this.listFilterChanged)
88
+ }
89
+
90
+ destroyed () {
91
+ this.$events.off(ListFilterEvent.CHANGE, this.listFilterChanged)
92
+ }
93
+
94
+ get listView () {
95
+ let parent = this.$parent
96
+ while (parent) {
97
+ if (parent.LIST_VIEW) {
98
+ return parent
99
+ }
100
+ parent = parent.$parent
101
+ }
102
+ return null
103
+ }
104
+
105
+ get filters () {
106
+ return this.listView.filters
107
+ }
108
+
109
+ get countFilters () {
110
+ return this.$slots.default.filter(vnode => !!vnode.tag).length
111
+ }
112
+
113
+ get countSelectedFilters () {
114
+ const coreFilters = ['q', 'qfield', 'page', 'page_size']
115
+ let minus = 0
116
+ for (const name of coreFilters) {
117
+ if (!this.filters[name].hasDefaultValueSet()) {
118
+ minus++
119
+ }
120
+ }
121
+ return Object.values(this.filters).filter(f => !f.hasDefaultValueSet()).length - minus
122
+ }
123
+
124
+ listFilterChanged ({payload: {name, label, value}}) {
125
+ this.setSelectedFilter(name, label, value)
126
+ }
127
+
128
+ setSelectedFilter (name, label, value) {
129
+ const hasValue = !this.filters[name].hasDefaultValueSet()
130
+
131
+ if (!hasValue) {
132
+ this.selectedFilters = this.selectedFilters.filter(f => f.name !== name)
133
+ } else {
134
+ if (this.selectedFilters.some(f => f.name === name)) {
135
+ this.selectedFilters = this.selectedFilters.map(f => {
136
+ if (f.name === name) {
137
+ return { name, label, value }
138
+ }
139
+ return f
140
+ })
141
+ } else {
142
+ this.selectedFilters.push({ name, label, value })
143
+ }
144
+ }
145
+ }
146
+
147
+ resetFilter (name) {
148
+ this.listView.resetFilter(name)
149
+ this.setSelectedFilter(name, null, null)
150
+ }
151
+ }
152
+ </script>
153
+
154
+
155
+ <style lang="scss" scoped>
156
+ .filterToggle {
157
+ cursor: pointer;
158
+ background: #F4F4F4;
159
+ padding: 0 4px;
160
+ margin-left: .5rem;
161
+ }
162
+
163
+ .chip-container {
164
+ display: flex;
165
+ flex-wrap: wrap;
166
+ gap: 4px;
167
+ }
168
+
169
+ ::v-deep(.aPagination) {
170
+ margin-top: 14px;
171
+ }
172
+
173
+ ::v-deep(.pageSizeSelect) {
174
+ margin-top: 15px;
175
+ }
176
+
177
+ </style>
@@ -0,0 +1,5 @@
1
+ import { BaseEvent } from '@a-vue/plugins/event-bus/BaseEvent'
2
+
3
+ export class ListFilterEvent extends BaseEvent {
4
+ static CHANGE = 'ListFilterEvent:change'
5
+ }
@@ -1,12 +1,23 @@
1
- import { Component, Vue } from '@a-vue'
1
+ import { Component, Vue, Watch } from '@a-vue'
2
+ import { ListFilterEvent } from '@a-vue/events'
2
3
 
3
4
  @Component({
4
5
  props: ['name', 'label', 'optionRequestParams']
5
6
  })
6
7
  export class ListFilterMixin extends Vue {
8
+ displayValue = null
7
9
  name_ = null
8
10
  maxWidth_ = null
9
11
 
12
+ @Watch('displayValue')
13
+ displayValueChanged () {
14
+ this.$events.dispatch(new ListFilterEvent(ListFilterEvent.CHANGE, {
15
+ name: this.name,
16
+ label: this.label,
17
+ value: this.displayValue
18
+ }))
19
+ }
20
+
10
21
  get _name () {
11
22
  return this.name || this.name_
12
23
  }
@@ -125,6 +125,11 @@ export class ListViewMixin extends Vue {
125
125
  this.load()
126
126
  }
127
127
 
128
+ resetFilter (filterName) {
129
+ this.filters[filterName].reset()
130
+ this.listViewModel.filterValueChanged(filterName)
131
+ }
132
+
128
133
  resetFilters () {
129
134
  this.listViewModel.resetFilters()
130
135
  }
@@ -8,6 +8,7 @@
8
8
  hide-details
9
9
  v-bind="$attrs"
10
10
  v-on="$listeners"
11
+ @displayedDateChanged="displayedDateChanged"
11
12
  />
12
13
  </template>
13
14
 
@@ -18,5 +19,8 @@ import { ListFilterMixin } from '../ListFilterMixin'
18
19
 
19
20
  @Component
20
21
  export default class ListFilterDate extends Mixins(ListFilterMixin) {
22
+ displayedDateChanged (formattedDate) {
23
+ this.displayValue = formattedDate
24
+ }
21
25
  }
22
26
  </script>
@@ -1,10 +1,10 @@
1
1
  <template>
2
2
  <a-row gap="8">
3
3
  <a-pagination
4
- v-if="count && numPages > 1"
4
+ v-if="$has.page && count && numPages > 1"
5
5
  v-model="filter.value"
6
6
  :length="numPages"
7
- :total-visible="_totalVisible"
7
+ :totalVisible="_totalVisible"
8
8
  >
9
9
  <template v-if="$has.page_number">
10
10
  <span class="pageNumber">{{ filter.value }} / {{ numPages }}</span>
@@ -14,6 +14,7 @@
14
14
  <a-select
15
15
  v-if="$has.page_size"
16
16
  v-model="pageSizeFilter.value"
17
+ class="pageSizeSelect"
17
18
  :label="label || 'Anzahl'"
18
19
  :items="pageSizeFilter.options"
19
20
  :defaultValue="pageSizeFilter.defaultValue"
@@ -32,7 +33,7 @@ import { ListFilterMixin } from '../ListFilterMixin'
32
33
  props: ['totalVisible']
33
34
  })
34
35
  export default class ListFilterPage extends Mixins(ListFilterMixin) {
35
- $hasOptions = ['page_size', {page_number: false}]
36
+ $hasOptions = ['page', 'page_size', {page_number: false}]
36
37
 
37
38
  name_ = 'page'
38
39
 
@@ -41,7 +42,7 @@ export default class ListFilterPage extends Mixins(ListFilterMixin) {
41
42
  }
42
43
 
43
44
  get _totalVisible () {
44
- return this.totalVisible === undefined ? 7 : this.totalVisible // allow 0 for totalVisible
45
+ return this.totalVisible === undefined ? 11 : this.totalVisible // allow 0 for totalVisible
45
46
  }
46
47
 
47
48
  get numPages () {
@@ -141,6 +141,11 @@ export default class ListFilterSearchSelect extends Mixins(ListFilterMixin) {
141
141
  }
142
142
  }
143
143
 
144
+ @Watch('inputModel')
145
+ inputModelChanged () {
146
+ this.displayValue = this.inputModel
147
+ }
148
+
144
149
  calculateSelectorSize () {
145
150
  const input = this.$refs.input.$el
146
151
  const inputWidth = input.offsetWidth
@@ -11,6 +11,7 @@
11
11
  hide-details
12
12
  v-bind="$attrs"
13
13
  v-on="$listeners"
14
+ @selectedItemTitleChanged="selectedItemTitleChanged"
14
15
  />
15
16
  </template>
16
17
 
@@ -34,6 +35,10 @@ export default class ListFilterSelect extends Mixins(ListFilterMixin) {
34
35
  this.reloadOptions()
35
36
  }
36
37
 
38
+ selectedItemTitleChanged (title) {
39
+ this.displayValue = title
40
+ }
41
+
37
42
  get clearable () {
38
43
  if (this.multiple) {
39
44
  return !!this.filter.value?.length
package/src/events.js CHANGED
@@ -4,3 +4,4 @@ export { SaveEvent } from './components/save-indicator/SaveEvent'
4
4
  export { AlertEvent } from './components/alert/AlertEvent'
5
5
  export { DialogEvent } from './components/dialog/DialogEvent'
6
6
  export { FlyingContextEvent } from './components/flying-context/FlyingContextEvent'
7
+ export { ListFilterEvent } from './components/list/ListFilterEvent'
@@ -6,13 +6,26 @@
6
6
  :class="['label', {collapsible}]"
7
7
  @click="collapseClick"
8
8
  >
9
- {{ label }}
10
-
11
- <template v-if="collapsible">
12
- <v-icon class="contextButton mt-n1 ml-n2">
13
- {{ collapsed_ ? '$caretRightIcon' : '$caretDownIcon' }}
9
+ <a-row>
10
+ <v-icon
11
+ v-if="icon"
12
+ class="mr-2"
13
+ color="#CCCCCC"
14
+ >
15
+ {{ icon }}
14
16
  </v-icon>
15
- </template>
17
+
18
+ <div>{{ label }}</div>
19
+
20
+ <template v-if="collapsible">
21
+ <v-icon
22
+ class="contextButton"
23
+ size="2rem"
24
+ >
25
+ {{ collapsed_ ? '$caretRightIcon' : '$caretDownIcon' }}
26
+ </v-icon>
27
+ </template>
28
+ </a-row>
16
29
  </div>
17
30
  </div>
18
31
  </template>
@@ -22,7 +35,7 @@
22
35
  import { Component, Vue, Watch } from '@a-vue'
23
36
 
24
37
  @Component({
25
- props: ['label', {first: false, collapsible: false, collapsed: false}]
38
+ props: ['label', 'icon', {first: false, collapsible: false, collapsed: false}]
26
39
  })
27
40
  export default class HSeparator extends Vue {
28
41
  collapsed_ = false
@@ -59,7 +72,7 @@ export default class HSeparator extends Vue {
59
72
 
60
73
  hr {
61
74
  border: none;
62
- border-top: 2px solid #EEEEEE;
75
+ border-top: 2px solid #DDDDDD;
63
76
  }
64
77
 
65
78
  .label {
@@ -67,12 +80,12 @@ hr {
67
80
  background: white;
68
81
  padding: 0 1rem;
69
82
  text-transform: uppercase;
70
- letter-spacing: 5px;
71
- color: #CCCCCC;
72
- font-size: .8rem;
83
+ letter-spacing: 3px;
84
+ color: #BBBBBB;
85
+ font-size: .9rem;
73
86
  white-space: nowrap;
74
87
 
75
- left: 45%;
88
+ left: 50%;
76
89
  transform: translateX(-50%);
77
90
 
78
91
  &.collapsible {
@@ -81,7 +94,7 @@ hr {
81
94
  &:hover {
82
95
  color: #333333;
83
96
 
84
- .v-icon {
97
+ .v-icon.contextButton {
85
98
  color: #333333 !important;
86
99
  }
87
100
  }
@@ -79,6 +79,10 @@ html {
79
79
  color: #616161 !important;
80
80
  }
81
81
 
82
+ .v-text-field {
83
+ background: white;
84
+ }
85
+
82
86
  .theme--light.v-btn.v-btn--disabled,
83
87
  .theme--light.v-btn.v-btn--disabled span,
84
88
  .theme--light.v-btn.v-btn--disabled .v-icon,