@afeefa/vue-app 0.0.139 → 0.0.141

Sign up to get free protection for your applications and to get access to all the features.
@@ -1 +1 @@
1
- 0.0.139
1
+ 0.0.141
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@afeefa/vue-app",
3
- "version": "0.0.139",
3
+ "version": "0.0.141",
4
4
  "description": "",
5
5
  "author": "Afeefa Kollektiv <kollektiv@afeefa.de>",
6
6
  "license": "MIT",
@@ -1,8 +1,9 @@
1
1
  <template>
2
2
  <div class="contextEditor">
3
+ <!-- click.stop prevents possible surrounding v-input to focus -->
3
4
  <div
4
5
  class="activator"
5
- @click="open"
6
+ @click.stop="open"
6
7
  >
7
8
  <slot name="activator">
8
9
  <a-icon class="contextButton">
@@ -11,7 +11,11 @@
11
11
  @click:clear="clear"
12
12
  @blur="sanitizeInternalValue"
13
13
  v-on="listeners"
14
- />
14
+ >
15
+ <template #append>
16
+ <slot name="append" />
17
+ </template>
18
+ </v-text-field>
15
19
  </template>
16
20
 
17
21
 
@@ -54,7 +54,7 @@ export class FormFieldMixin extends Vue {
54
54
 
55
55
  if (field.hasOptionsRequest()) {
56
56
  const request = field
57
- .getOptionsRequest()
57
+ .createOptionsRequest()
58
58
  .addParams(this.optionRequestParams || {})
59
59
  .addFilters(filters)
60
60
 
@@ -95,7 +95,7 @@ export default class FormFieldSearchSelect extends Mixins(FormFieldMixin) {
95
95
 
96
96
  get listAction () {
97
97
  const request = this.field
98
- .getOptionsRequest()
98
+ .createOptionsRequest()
99
99
  .addParams(this.optionRequestParams || {})
100
100
  return ListAction.fromRequest(request)
101
101
  }
@@ -2,6 +2,7 @@ import { Component, Vue, Watch } from '@a-vue'
2
2
  import { ListAction } from '@a-vue/api-resources/ApiActions'
3
3
  import { sleep } from '@a-vue/utils/timeout'
4
4
  import { ListViewModel } from '@afeefa/api-resources-client'
5
+ import axios from 'axios'
5
6
 
6
7
  import { CurrentRouteFilterSource } from './CurrentRouteFilterSource'
7
8
  import { FilterSourceType } from './FilterSourceType'
@@ -11,7 +12,6 @@ import { FilterSourceType } from './FilterSourceType'
11
12
  'models', 'meta', // given, if already loaded
12
13
  'listAction',
13
14
  'filterHistoryKey',
14
- 'checkBeforeLoad',
15
15
  {
16
16
  filterSource: FilterSourceType.QUERY_STRING,
17
17
  loadOnlyIfKeyword: false,
@@ -27,6 +27,7 @@ export class ListViewMixin extends Vue {
27
27
  models_ = []
28
28
  meta_ = {}
29
29
  isLoading = false
30
+ cancelSource = null
30
31
 
31
32
  created () {
32
33
  this.init()
@@ -123,16 +124,6 @@ export class ListViewMixin extends Vue {
123
124
  }
124
125
 
125
126
  async load () {
126
- if (this.checkBeforeLoad) {
127
- const canLoad = await this.checkBeforeLoad()
128
- if (!canLoad) {
129
- if (this.meta_.used_filters) {
130
- this.listViewModel.initFromUsedFilters(this.meta_.used_filters, this.meta_.count_search)
131
- }
132
- return
133
- }
134
- }
135
-
136
127
  if (this.loadOnlyIfKeyword && !this.filters.q.value) {
137
128
  this.models_ = []
138
129
  this.meta_ = {}
@@ -143,10 +134,16 @@ export class ListViewMixin extends Vue {
143
134
  this.isLoading = true
144
135
  this.$emit('update:isLoading', this.isLoading)
145
136
 
137
+ if (this.cancelSource) {
138
+ this.cancelSource.cancel()
139
+ }
140
+
141
+ this.cancelSource = axios.CancelToken.source()
146
142
  const request = this.listViewModel.getApiRequest()
147
143
 
148
144
  const {models, meta} = await ListAction
149
145
  .fromRequest(request)
146
+ .cancelSource(this.cancelSource)
150
147
  .dispatchGlobalLoadingEvents(this.events)
151
148
  .load()
152
149
 
@@ -1,16 +1,47 @@
1
1
  <template>
2
- <a-text-field
3
- ref="input"
4
- v-model="filter.value"
5
- :maxWidth="$attrs.maxWidth || maxWidth_"
6
- :label="label || 'Suche'"
7
- :debounce="500"
8
- v-bind="$attrs"
9
- clearable
10
- hide-details
11
- @keyup.esc="clearValue"
12
- v-on="$listeners"
13
- />
2
+ <div>
3
+ <a-text-field
4
+ ref="input"
5
+ v-model="filter.value"
6
+ :maxWidth="$attrs.maxWidth || maxWidth_"
7
+ :label="label_"
8
+ :debounce="500"
9
+ v-bind="$attrs"
10
+ clearable
11
+ hide-details
12
+ @keyup.esc="clearValue"
13
+ v-on="$listeners"
14
+ >
15
+ <template
16
+ v-if="hasQFieldOptions()"
17
+ #append
18
+ >
19
+ <a-context-menu>
20
+ <template #activator>
21
+ <!-- click.prevent brings hand cursor -->
22
+ <!-- mousedown.stop will prevent the input focused -->
23
+ <a-icon
24
+ @click.prevent
25
+ @mousedown.stop
26
+ >
27
+ {{ appendIcon }}
28
+ </a-icon>
29
+ </template>
30
+
31
+ <a-context-menu-item
32
+ v-for="option in qFieldOptions"
33
+ :key="option.title"
34
+ @click="filters.qfield.value = option.value"
35
+ >
36
+ <a-icon :class="{selected: filters.qfield.value === option.value}">
37
+ $checkIcon
38
+ </a-icon>
39
+ {{ option.title }}
40
+ </a-context-menu-item>
41
+ </a-context-menu>
42
+ </template>
43
+ </a-text-field>
44
+ </div>
14
45
  </template>
15
46
 
16
47
 
@@ -33,5 +64,39 @@ export default class ListFilterSearch extends Mixins(ListFilterMixin) {
33
64
  setFocus (force) {
34
65
  this.$refs.input.setFocus(force)
35
66
  }
67
+
68
+ get appendIcon () {
69
+ if (this.hasQFieldOptions()) {
70
+ return '$filterIcon'
71
+ }
72
+ }
73
+
74
+ hasQFieldOptions () {
75
+ return this.filters.qfield && this.filters.qfield.hasOptions()
76
+ }
77
+
78
+ get qFieldOptions () {
79
+ return this.filters.qfield.options
80
+ }
81
+
82
+ get label_ () {
83
+ const label = this.label || 'Suche'
84
+
85
+ if (this.hasQFieldOptions() && !this.filters.qfield.hasDefaultValueSet()) {
86
+ const selected = this.qFieldOptions.filter(o => o.value === this.filters.qfield.value)[0]
87
+ if (selected) {
88
+ return `${label} (${selected.title})`
89
+ }
90
+ }
91
+
92
+ return label
93
+ }
36
94
  }
37
95
  </script>
96
+
97
+
98
+ <style lang="scss" scoped>
99
+ .contextMenuItem > *:not(.selected) {
100
+ opacity: 0;
101
+ }
102
+ </style>
@@ -5,7 +5,7 @@
5
5
  :items="_items"
6
6
  itemText="itemTitle"
7
7
  itemValue="itemValue"
8
- :clearable="filter.value !== filter.defaultValue"
8
+ :clearable="filter.hasDefaultValue() && !filter.hasDefaultValueSet()"
9
9
  :defaultValue="filter.defaultValue"
10
10
  hide-details
11
11
  v-bind="$attrs"
@@ -36,44 +36,13 @@ export default class ListFilterSelect extends Mixins(ListFilterMixin) {
36
36
  return this.$attrs.items || this.items || []
37
37
  }
38
38
 
39
- get showNullOption () {
40
- // either null is a selectable option, than it should be shown in the list
41
- // or the default is null, so the list should offer a 'null' option for the unselected state
42
- return this.filter.nullIsOption || this.filter.defaultValue === null
43
- }
44
-
45
- createOptions () {
46
- const options = []
47
-
48
- if (this.filter.allIsOption) {
49
- options.push({
50
- itemTitle: 'Alle',
51
- itemValue: 'all'
52
- })
53
- } else if (this.showNullOption) {
54
- options.push({
55
- itemTitle: 'Alle',
56
- itemValue: null
57
- })
58
- }
59
-
60
- if (this.filter.noneIsOption) {
61
- options.push({
62
- itemTitle: 'Keine',
63
- itemValue: 'none'
64
- })
65
- }
66
-
67
- return options
68
- }
69
-
70
39
  async loadRequestOptions () {
71
40
  const {models} = await ListAction
72
41
  .fromRequest(this.filter.createOptionsRequest())
73
42
  .load()
74
43
 
75
44
  return [
76
- ...this.createOptions(),
45
+ ...this.getOptions(),
77
46
  ...models.map(model => {
78
47
  let itemValue
79
48
  if (this.itemValue) {
@@ -93,13 +62,13 @@ export default class ListFilterSelect extends Mixins(ListFilterMixin) {
93
62
 
94
63
  getOptions () {
95
64
  return [
96
- ...this.createOptions(),
97
65
  ...this.filter.options
98
- .filter(o => o !== null) // null is already set in options (if any)
99
- .map(o => ({
100
- itemTitle: o ? 'Ja' : 'Nein',
101
- itemValue: o
102
- }))
66
+ .map(o => {
67
+ return {
68
+ itemTitle: o.title,
69
+ itemValue: o.value
70
+ }
71
+ })
103
72
  ]
104
73
  }
105
74
  }
@@ -94,7 +94,7 @@
94
94
  top
95
95
  left
96
96
  class="loadingIndicator"
97
- :isLoading="isLoading"
97
+ :isLoading="!!numLoadingRequests"
98
98
  :color="loaderColor"
99
99
  />
100
100
 
@@ -119,7 +119,7 @@
119
119
  >
120
120
  <sticky-header />
121
121
 
122
- <router-view :class="{isLoading}" />
122
+ <router-view :class="{isLoading: !!numLoadingRequests}" />
123
123
  </v-container>
124
124
 
125
125
  <sticky-footer-container />
@@ -164,7 +164,7 @@ export default class App extends Vue {
164
164
 
165
165
  drawer = true
166
166
  closeMenuIcon = mdiBackburger
167
- isLoading = false
167
+ numLoadingRequests = 0
168
168
 
169
169
  created () {
170
170
  this.$events.on(LoadingEvent.START_LOADING, this.startLoading)
@@ -200,11 +200,11 @@ export default class App extends Vue {
200
200
  }
201
201
 
202
202
  startLoading () {
203
- this.isLoading = true
203
+ this.numLoadingRequests++
204
204
  }
205
205
 
206
206
  stopLoading () {
207
- this.isLoading = false
207
+ this.numLoadingRequests--
208
208
  }
209
209
 
210
210
  toggleDrawer () {
@@ -12,6 +12,7 @@ import {
12
12
  mdiDelete,
13
13
  mdiDotsHorizontal,
14
14
  mdiDotsVertical,
15
+ mdiFilter,
15
16
  mdiLock,
16
17
  mdiLogoutVariant,
17
18
  mdiMagnify,
@@ -58,7 +59,8 @@ export default new Vuetify({
58
59
  printerIcon: mdiPrinter,
59
60
  euroSymbol: mdiCurrencyEur,
60
61
  paletteIcon: mdiPalette,
61
- addIcon: mdiPlusCircle
62
+ addIcon: mdiPlusCircle,
63
+ filterIcon: mdiFilter
62
64
  }
63
65
  },
64
66
  breakpoint: {