@afeefa/vue-app 0.0.43 → 0.0.47

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 (35) hide show
  1. package/.afeefa/package/release/version.txt +1 -1
  2. package/package.json +1 -1
  3. package/src/api-resources/ApiActions.js +4 -55
  4. package/src/components/APagination.vue +0 -4
  5. package/src/components/ARow.vue +1 -3
  6. package/src/components/ASearchSelect.vue +2 -2
  7. package/src/components/ATableHeader.vue +1 -1
  8. package/src/components/list/FilterSourceType.js +10 -0
  9. package/src/components/list/ListViewMixin.js +16 -17
  10. package/src/components/list/ListViewRequest.js +124 -0
  11. package/src/components/list/{RouteParamsFilterSource.js → RouteQueryFilterSource.js} +1 -1
  12. package/src/plugins/api-resources/ApiResourcesPlugin.js +13 -0
  13. package/src-admin/bootstrap.js +3 -1
  14. package/src-admin/components/{Index.vue → Start.vue} +0 -0
  15. package/src-admin/components/detail/DetailProperty.vue +5 -5
  16. package/src-admin/components/index.js +2 -2
  17. package/src-admin/components/list/ListView.vue +35 -49
  18. package/src-admin/components/pages/CreatePage.vue +6 -9
  19. package/src-admin/components/pages/DetailPage.vue +2 -2
  20. package/src-admin/components/pages/EditPage.vue +7 -10
  21. package/src-admin/components/pages/ListPage.vue +7 -122
  22. package/src-admin/components/routes/DetailRoute.vue +1 -7
  23. package/src-admin/components/routes/EditRoute.vue +1 -7
  24. package/src-admin/components/routes/ListRoute.vue +9 -10
  25. package/src-admin/fonts/ibm-plex-sans-v9-latin-700.woff +0 -0
  26. package/src-admin/fonts/ibm-plex-sans-v9-latin-700.woff2 +0 -0
  27. package/src-admin/fonts/ibm-plex-sans-v9-latin-700italic.woff +0 -0
  28. package/src-admin/fonts/ibm-plex-sans-v9-latin-700italic.woff2 +0 -0
  29. package/src-admin/fonts/ibm-plex-sans-v9-latin-italic.woff +0 -0
  30. package/src-admin/fonts/ibm-plex-sans-v9-latin-italic.woff2 +0 -0
  31. package/src-admin/fonts/ibm-plex-sans-v9-latin-regular.woff +0 -0
  32. package/src-admin/fonts/ibm-plex-sans-v9-latin-regular.woff2 +0 -0
  33. package/src-admin/models/Model.js +10 -7
  34. package/src-admin/styles/ibm-plex-sans.scss +43 -0
  35. package/src/components/list/QuerySourceType.js +0 -4
@@ -1 +1 @@
1
- 0.0.43
1
+ 0.0.47
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@afeefa/vue-app",
3
- "version": "0.0.43",
3
+ "version": "0.0.47",
4
4
  "description": "",
5
5
  "author": "Afeefa Kollektiv <kollektiv@afeefa.de>",
6
6
  "license": "MIT",
@@ -1,8 +1,6 @@
1
- import { RouteParamsFilterSource } from '@a-vue/components/list/RouteParamsFilterSource'
2
1
  import { AlertEvent, DialogEvent, LoadingEvent, SaveEvent } from '@a-vue/events'
3
2
  import { eventBus } from '@a-vue/plugins/event-bus/EventBus'
4
3
  import { sleep } from '@a-vue/utils/timeout'
5
- import { RequestFilters } from '@afeefa/api-resources-client'
6
4
 
7
5
  export class GetAction {
8
6
  action = null
@@ -35,7 +33,7 @@ export class GetAction {
35
33
  eventBus.dispatch(new LoadingEvent(LoadingEvent.START_LOADING))
36
34
  }
37
35
 
38
- const result = await this.action.request()
36
+ const result = await this.action.createRequest()
39
37
  .params({
40
38
  id: this.id
41
39
  })
@@ -111,7 +109,7 @@ export class SaveAction {
111
109
 
112
110
  const startTime = Date.now()
113
111
 
114
- const result = await this.action.request()
112
+ const result = await this.action.createRequest()
115
113
  .params({
116
114
  id: this.id || undefined
117
115
  })
@@ -195,7 +193,7 @@ export class RemoveAction {
195
193
 
196
194
  const startTime = Date.now()
197
195
 
198
- const result = await this.action.request()
196
+ const result = await this.action.createRequest()
199
197
  .params({
200
198
  id: this.id
201
199
  })
@@ -230,11 +228,6 @@ export class RemoveAction {
230
228
 
231
229
  export class ListAction {
232
230
  request = null
233
- action = null
234
- fields = null
235
- scopes = {}
236
- filters = {}
237
- route = null
238
231
  events = true
239
232
 
240
233
  setRequest (request) {
@@ -242,31 +235,6 @@ export class ListAction {
242
235
  return this
243
236
  }
244
237
 
245
- setAction (action) {
246
- this.action = action
247
- return this
248
- }
249
-
250
- setFiltersForRoute (route) {
251
- this.route = route
252
- return this
253
- }
254
-
255
- setFields (fields) {
256
- this.fields = fields
257
- return this
258
- }
259
-
260
- setScopes (scopes) {
261
- this.scopes = scopes
262
- return this
263
- }
264
-
265
- setFilters (filters) {
266
- this.filters = filters
267
- return this
268
- }
269
-
270
238
  noEvents (noEvents) {
271
239
  this.events = noEvents === undefined ? false : !noEvents
272
240
  return this
@@ -277,26 +245,7 @@ export class ListAction {
277
245
  eventBus.dispatch(new LoadingEvent(LoadingEvent.START_LOADING))
278
246
  }
279
247
 
280
- let filters = this.filters
281
-
282
- if (this.route) {
283
- const querySource = new RouteParamsFilterSource(this.route)
284
- const requestFilters = this.action.createRequestFilters(null, querySource)
285
- const storedFilters = RequestFilters.fromHistory(this.route.path)
286
- if (storedFilters) {
287
- requestFilters.initFromUsed(storedFilters.serialize(), 1)
288
- }
289
- filters = requestFilters.serialize()
290
- }
291
-
292
- const request = this.request ||
293
- this.action
294
- .request()
295
- .scopes(this.scopes)
296
- .filters(filters)
297
- .fields(this.fields)
298
-
299
- const result = await request.send()
248
+ const result = await this.request.send()
300
249
 
301
250
  if (result.error) {
302
251
  if (this.events) {
@@ -33,10 +33,6 @@ export default class APagination extends Vue {
33
33
 
34
34
 
35
35
  <style scoped lang="scss">
36
- .pagination-nav {
37
- line-height: 1;
38
- }
39
-
40
36
  ::v-deep .v-pagination {
41
37
  gap: .3rem;
42
38
  .v-pagination__item,
@@ -58,9 +58,7 @@ export default class ARow extends Vue {
58
58
  <style scoped lang="scss">
59
59
  .a-row {
60
60
  display: flex;
61
- width: 100%;
62
- overflow-x: scroll;
63
-
61
+ overflow: hidden;
64
62
  @media (max-width: 900px), (orientation : portrait) {
65
63
  flex-wrap: wrap;
66
64
  & > * {
@@ -93,7 +93,7 @@ import { Component, Watch, Mixins } from 'vue-property-decorator'
93
93
  import { UsesPositionServiceMixin } from '../services/position/UsesPositionServiceMixin'
94
94
  import { PositionConfig } from '../services/PositionService'
95
95
  import { randomCssClass } from '../utils/random'
96
- import { QuerySourceType } from '@a-vue/components/list/QuerySourceType'
96
+ import { FilterSourceType } from '@a-vue/components/list/FilterSourceType'
97
97
  import SearchSelectFilters from './search-select/SearchSelectFilters'
98
98
  import SearchSelectList from './search-select/SearchSelectList'
99
99
  import { CancelOnEscMixin } from '@a-vue/services/escape/CancelOnEscMixin'
@@ -109,7 +109,7 @@ export default class ASearchSelect extends Mixins(UsesPositionServiceMixin, Canc
109
109
  selectId = randomCssClass(10)
110
110
  isOpen = false
111
111
  items_ = []
112
- filterSource = QuerySourceType.OBJECT
112
+ filterSource = FilterSourceType.OBJECT
113
113
 
114
114
  isLoading = false
115
115
  filters = []
@@ -56,7 +56,7 @@ export default class ATableHeader extends Vue {
56
56
  > * {
57
57
  padding-left: .5rem;
58
58
  padding-right: 1rem;
59
- padding-bottom: .2rem;
59
+ padding-bottom: .6rem;
60
60
  &:last-child {
61
61
  padding-right: .2rem;
62
62
  }
@@ -0,0 +1,10 @@
1
+ export class FilterSourceType {
2
+ // filters are synchronized with url's query string
3
+ static QUERY_STRING = 'query_string'
4
+
5
+ // filters are initialized from given route params (no synchronisation allowed)
6
+ static ROUTE_PARAMS = 'route_params'
7
+
8
+ // filters are synchronized with plain history object
9
+ static OBJECT = 'object'
10
+ }
@@ -1,14 +1,15 @@
1
1
  import { ListAction } from '@a-vue/api-resources/ApiActions'
2
2
  import { Component, Vue, Watch } from 'vue-property-decorator'
3
3
 
4
- import { QuerySourceType } from './QuerySourceType'
4
+ import { FilterSourceType } from './FilterSourceType'
5
5
  import { RouteFilterSource } from './RouteFilterSource'
6
6
 
7
7
  @Component({
8
8
  props: [
9
- 'models', 'meta',
10
- 'action', 'scopes', 'initialFilters', 'fields',
11
- 'noEvents', 'noHistory', 'filterHistoryKey', 'filterSource',
9
+ 'models', 'meta', // if already loaded
10
+ 'listViewRequest',
11
+ 'noEvents', 'noHistory',
12
+ 'filterHistoryKey', 'filterSource',
12
13
  'loadOnlyIfKeyword'
13
14
  ]
14
15
  })
@@ -35,19 +36,16 @@ export class ListViewMixin extends Vue {
35
36
  }
36
37
 
37
38
  if (this.requestFilters) {
39
+ // this can happen only on HMR-reload
38
40
  this.requestFilters.off('change', this.filtersChanged)
39
41
  }
40
42
 
41
43
  const historyKey = this.noHistory
42
44
  ? undefined
43
45
  : [this.$route.path, this.filterHistoryKey].filter(i => i).join('.')
44
- const querySource = this.filterSource === QuerySourceType.OBJECT ? undefined : new RouteFilterSource(this.$router)
45
- this.requestFilters = this.action.createRequestFilters(historyKey, querySource)
46
-
47
- console.log('Initial Filters: ', this.initialFilters)
48
- if (this.initialFilters) {
49
- this.requestFilters.initFromUsed(this.initialFilters)
50
- }
46
+ const filterSource = this.filterSource === FilterSourceType.OBJECT ? undefined : new RouteFilterSource(this.$router)
47
+ const action = this.listViewRequest.getAction()
48
+ this.requestFilters = action.createRequestFilters(historyKey, filterSource)
51
49
 
52
50
  this.requestFilters.on('change', this.filtersChanged)
53
51
 
@@ -64,8 +62,8 @@ export class ListViewMixin extends Vue {
64
62
 
65
63
  @Watch('$route.query')
66
64
  routeQueryChanged () {
67
- if (this.filterSource !== QuerySourceType.ROUTE) {
68
- this.requestFilters.querySourceChanged()
65
+ if (this.filterSource !== FilterSourceType.QUERY_STRING) {
66
+ this.requestFilters.filterSourceChanged()
69
67
  }
70
68
  }
71
69
 
@@ -109,11 +107,12 @@ export class ListViewMixin extends Vue {
109
107
  this.isLoading = true
110
108
  this.$emit('update:isLoading', this.isLoading)
111
109
 
110
+ const request = this.listViewRequest
111
+ .filters(this.requestFilters.serialize())
112
+ .toApiRequest()
113
+
112
114
  const {models, meta} = await new ListAction()
113
- .setAction(this.action)
114
- .setFields(this.fields)
115
- .setScopes(this.scopes)
116
- .setFilters(this.requestFilters.serialize())
115
+ .setRequest(request)
117
116
  .noEvents(this.noEvents)
118
117
  .load()
119
118
 
@@ -0,0 +1,124 @@
1
+ import { RequestFilters, apiResources } from '@afeefa/api-resources-client'
2
+
3
+ export class ListViewRequest {
4
+ _api = {}
5
+ _resource = {}
6
+ _action = {}
7
+
8
+ _params = {}
9
+ _filters = {}
10
+ _fields = {}
11
+
12
+ _filterSource = null
13
+ _historyKey = null
14
+
15
+ action ({api, resource, action}) {
16
+ this._api = api
17
+ this._resource = resource
18
+ this._action = action
19
+ return this
20
+ }
21
+
22
+ getAction () {
23
+ return apiResources.getAction({
24
+ api: this._api,
25
+ resource: this._resource,
26
+ action: this._action
27
+ })
28
+ }
29
+
30
+ params (params) {
31
+ this._params = params
32
+ return this
33
+ }
34
+
35
+ getParams () {
36
+ return this._params
37
+ }
38
+
39
+ filters (filters) {
40
+ this._filters = filters
41
+ return this
42
+ }
43
+
44
+ getFilters () {
45
+ return this._filters
46
+ }
47
+
48
+ fields (fields) {
49
+ this._fields = fields
50
+ return this
51
+ }
52
+
53
+ getFields () {
54
+ return this._fields
55
+ }
56
+
57
+ initFromFilterSource (filterSource) {
58
+ this._filterSource = filterSource
59
+ return this
60
+ }
61
+
62
+ recreateFromHistory (historyKey) {
63
+ this._historyKey = historyKey
64
+ return this
65
+ }
66
+
67
+ clone () {
68
+ const request = new ListViewRequest()
69
+ request._api = this._api
70
+ request._resource = this._resource
71
+ request._action = this._action
72
+ request._params = this._params
73
+ request._filters = this._filters
74
+ request._fields = this._fields
75
+ return request
76
+ }
77
+
78
+ toApiRequest () {
79
+ const action = this.getAction({
80
+ api: this._api,
81
+ resource: this._resource,
82
+ action: this._action
83
+ })
84
+
85
+ const request = action.createRequest()
86
+ .params(this._params)
87
+ .fields(this._fields)
88
+
89
+ // filters set on the request will be skipped if filterSource or historyKey are given
90
+ // and produce results
91
+ let filtersToUse = this._filters
92
+ let useHistory = true
93
+
94
+ // create and init request filters based on the current filter source state
95
+ if (this._filterSource) {
96
+ const requestFilters = action.createRequestFilters(null, this._filterSource)
97
+ const requestFiltersToUse = requestFilters.serialize()
98
+ // do not use history if any filter given by the given filter source
99
+ if (Object.keys(requestFiltersToUse).length) {
100
+ useHistory = false
101
+ }
102
+
103
+ filtersToUse = {
104
+ ...filtersToUse,
105
+ ...requestFiltersToUse
106
+ }
107
+ }
108
+
109
+ // if any filters is set by current filter source
110
+ // skip history and give that filter precedence
111
+ // otherwise: set stored filters
112
+ if (useHistory && this._historyKey) {
113
+ // check any already stored filters from a previous request
114
+ const storedFilters = RequestFilters.fromHistory(this._historyKey)
115
+ if (storedFilters) {
116
+ filtersToUse = storedFilters.serialize()
117
+ }
118
+ }
119
+
120
+ request.filters(filtersToUse)
121
+
122
+ return request
123
+ }
124
+ }
@@ -1,6 +1,6 @@
1
1
  import { BaseFilterSource } from '@afeefa/api-resources-client'
2
2
 
3
- export class RouteParamsFilterSource extends BaseFilterSource {
3
+ export class RouteQueryFilterSource extends BaseFilterSource {
4
4
  route = null
5
5
 
6
6
  constructor (route) {
@@ -0,0 +1,13 @@
1
+ import { apiResources } from '@afeefa/api-resources-client'
2
+
3
+ class ApiResourcesPlugin {
4
+ install (Vue) {
5
+ Object.defineProperty(Vue.prototype, '$apiResources', {
6
+ get () {
7
+ return apiResources
8
+ }
9
+ })
10
+ }
11
+ }
12
+
13
+ export const apiResourcesPlugin = new ApiResourcesPlugin()
@@ -1,6 +1,7 @@
1
1
  import './config/event-bus'
2
2
  import './config/components'
3
3
 
4
+ import { apiResourcesPlugin } from '@a-vue/plugins/api-resources/ApiResourcesPlugin'
4
5
  import { hasOptionsPlugin } from '@a-vue/plugins/has-options/HasOptionsPlugin'
5
6
  import { timeout } from '@a-vue/utils/timeout'
6
7
  import { apiResources } from '@afeefa/api-resources-client'
@@ -10,6 +11,7 @@ import { appConfig } from './config/AppConfig'
10
11
  import routeConfigPlugin from './config/routing'
11
12
  import vuetify from './config/vuetify'
12
13
 
14
+ Vue.use(apiResourcesPlugin)
13
15
  Vue.use(hasOptionsPlugin)
14
16
 
15
17
  Vue.config.productionTip = false
@@ -48,7 +50,7 @@ export async function bootstrap ({ apis, models, routing, authService, app, comp
48
50
  vuetify,
49
51
  router,
50
52
  el: '#app',
51
- template: '<index :splash="splash" />',
53
+ template: '<start :splash="splash" />',
52
54
  data: {
53
55
  splash
54
56
  }
File without changes
@@ -8,10 +8,10 @@
8
8
  >
9
9
  {{ _icon.icon }}
10
10
  </v-icon>
11
- <label :class="['label', {'label--withIcon': this._icon != null}]">{{ label }}</label>
11
+ <label :class="['label', {'label--withIcon': _icon != null}]">{{ label }}</label>
12
12
  </div>
13
13
 
14
- <div :class="['content', {'content--withIcon': this._icon != null}]">
14
+ <div :class="['content', {'content--withIcon': _icon != null}]">
15
15
  <a-row
16
16
  vertical
17
17
  gap="6"
@@ -37,8 +37,8 @@ export default class DetailProperty extends Vue {
37
37
  }
38
38
 
39
39
  if (this.iconModelType) {
40
- const model = apiResources.getModel(this.iconModelType)
41
- return model.icon
40
+ const ModelClass = apiResources.getModelClass(this.iconModelType)
41
+ return ModelClass.icon
42
42
  }
43
43
  }
44
44
  }
@@ -64,7 +64,7 @@ export default class DetailProperty extends Vue {
64
64
  @media (max-width: 900px), (orientation : portrait) {
65
65
  padding-left: 55px;
66
66
  &--withIcon {
67
- padding-left: 0;
67
+ padding-left: 0;
68
68
  }
69
69
  }
70
70
  }
@@ -7,7 +7,7 @@ import DetailContent from './detail/DetailContent'
7
7
  import DetailMeta from './detail/DetailMeta'
8
8
  import DetailProperty from './detail/DetailProperty'
9
9
  import DetailTitle from './detail/DetailTitle'
10
- import Index from './Index'
10
+ import Start from './Start.vue'
11
11
  import ListCard from './list/ListCard'
12
12
  import ListColumnHeader from './list/ListColumnHeader'
13
13
  import ListContent from './list/ListContent'
@@ -46,4 +46,4 @@ Vue.component('DetailColumn', DetailColumn)
46
46
  Vue.component('AppBarButton', AppBarButton)
47
47
  Vue.component('AppBarTitle', AppBarTitle)
48
48
 
49
- Vue.component('Index', Index)
49
+ Vue.component('Start', Start)
@@ -9,23 +9,32 @@
9
9
  </div>
10
10
 
11
11
  <template v-if="models_.length">
12
- <template v-if="table">
13
- <div class="table">
14
- <div class="header">
12
+ <template v-if="_table">
13
+ <a-table>
14
+ <a-table-header>
15
+ <div v-if="$has.icon" />
16
+
15
17
  <slot name="header-table" />
16
- </div>
18
+ </a-table-header>
17
19
 
18
- <div
20
+ <a-table-row
19
21
  v-for="model in models_"
20
22
  :key="model.id"
21
- class="row"
22
23
  >
24
+ <v-icon
25
+ v-if="$has.icon"
26
+ :color="model.getIcon().color"
27
+ size="1.2rem"
28
+ v-text="model.getIcon().icon"
29
+ />
30
+
23
31
  <slot
24
32
  name="model-table"
25
33
  :model="model"
34
+ :setFilter="setFilter"
26
35
  />
27
- </div>
28
- </div>
36
+ </a-table-row>
37
+ </a-table>
29
38
  </template>
30
39
 
31
40
  <template v-else>
@@ -60,6 +69,8 @@ import { LoadingEvent } from '@a-vue/events'
60
69
  props: ['table']
61
70
  })
62
71
  export default class ListView extends Mixins(ListViewMixin) {
72
+ $hasOptions = ['icon']
73
+
63
74
  @Watch('isLoading')
64
75
  isLoadingChanged () {
65
76
  if (this.noEvents === undefined || !this.noEvents) {
@@ -71,56 +82,31 @@ export default class ListView extends Mixins(ListViewMixin) {
71
82
  }
72
83
  this.$emit('update:isLoading', this.isLoading)
73
84
  }
85
+
86
+ get _table () {
87
+ return this.table !== false
88
+ }
89
+
90
+ setFilter (name, value) {
91
+ this.filters[name].value = value
92
+ }
74
93
  }
75
94
  </script>
76
95
 
77
96
 
78
97
  <style lang="scss" scoped>
98
+ .listView {
99
+ max-width: 100%;
100
+ overflow-x: auto;
101
+ overflow-y: hidden;
102
+ }
103
+
79
104
  .filters {
105
+ margin-left: 4px;
80
106
  margin-bottom: 2rem;
81
107
  }
82
108
 
83
- .table {
84
- display: table;
85
- border-collapse: collapse;
109
+ .a-table-row > :last-child {
86
110
  width: 100%;
87
-
88
- .header, .row {
89
- display: table-row;
90
- > * {
91
- display: table-cell;
92
- padding: .4rem;
93
- padding-right: 1.5rem;
94
- white-space: nowrap;
95
- vertical-align: middle;
96
-
97
- &.info {
98
- background: none !important;
99
- color: #888888;
100
- }
101
- }
102
- }
103
-
104
- .header {
105
- text-transform: uppercase;
106
- letter-spacing: 1px;
107
- color: #999999;
108
- font-size: .9rem;
109
- > * {
110
- padding-right: 1rem;
111
- }
112
- }
113
-
114
- .row {
115
- border-bottom: 1px solid #DDDDDD;
116
-
117
- &:hover {
118
- background: #F4F4F4;
119
- }
120
-
121
- &:last-child {
122
- border: none;
123
- }
124
- }
125
111
  }
126
112
  </style>
@@ -69,7 +69,11 @@ export default class CreatePage extends Mixins(EditPageMixin) {
69
69
  }
70
70
 
71
71
  get modelUpateAction () {
72
- return this.ModelClass.getAction(this.$routeDefinition, 'create')
72
+ return this.ModelClass.getAction('create')
73
+ }
74
+
75
+ get _icon () {
76
+ return this.icon || this.modelToEdit.getIcon()
73
77
  }
74
78
 
75
79
  get _title () {
@@ -89,7 +93,7 @@ export default class CreatePage extends Mixins(EditPageMixin) {
89
93
  get _listLink () {
90
94
  if (this.listLink) {
91
95
  if (typeof this.listLink === 'function') {
92
- return this.listLink(this.$route.params)
96
+ return this.listLink()
93
97
  } else {
94
98
  return this.listLink
95
99
  }
@@ -97,13 +101,6 @@ export default class CreatePage extends Mixins(EditPageMixin) {
97
101
  return this.modelToEdit.getLink('list')
98
102
  }
99
103
 
100
- get _icon () {
101
- if (this.icon) {
102
- return this.icon
103
- }
104
- return this.modelToEdit.getIcon()
105
- }
106
-
107
104
  createModelToEdit () {
108
105
  if (this.createModel) {
109
106
  return this.createModel(this.fields)
@@ -94,7 +94,7 @@ export default class DetailPage extends Vue {
94
94
  get _listLink () {
95
95
  if (this.listLink) {
96
96
  if (typeof this.listLink === 'function') {
97
- return this.listLink(this.$route.params)
97
+ return this.listLink()
98
98
  } else {
99
99
  return this.listLink
100
100
  }
@@ -113,7 +113,7 @@ export default class DetailPage extends Vue {
113
113
  if (this.removeAction) {
114
114
  return this.removeAction
115
115
  }
116
- return this.ModelClass.getAction(this.$routeDefinition, 'delete')
116
+ return this.ModelClass.getAction('delete')
117
117
  }
118
118
 
119
119
  async remove () {
@@ -99,14 +99,18 @@ export default class EditPage extends Mixins(EditPageMixin) {
99
99
  }
100
100
 
101
101
  get modelUpateAction () {
102
- return this.ModelClass.getAction(this.$routeDefinition, 'update')
102
+ return this.ModelClass.getAction('update')
103
103
  }
104
104
 
105
105
  get _getAction () {
106
106
  if (this.getAction) {
107
107
  return this.getAction
108
108
  }
109
- return this.ModelClass.getAction(this.$routeDefinition, 'get')
109
+ return this.ModelClass.getAction('get')
110
+ }
111
+
112
+ get _icon () {
113
+ return this.icon || this.model.getIcon()
110
114
  }
111
115
 
112
116
  get _title () {
@@ -126,7 +130,7 @@ export default class EditPage extends Mixins(EditPageMixin) {
126
130
  get _listLink () {
127
131
  if (this.listLink) {
128
132
  if (typeof this.listLink === 'function') {
129
- return this.listLink(this.$route.params)
133
+ return this.listLink()
130
134
  } else {
131
135
  return this.listLink
132
136
  }
@@ -134,13 +138,6 @@ export default class EditPage extends Mixins(EditPageMixin) {
134
138
  return this.model.getLink('list')
135
139
  }
136
140
 
137
- get _icon () {
138
- if (this.icon) {
139
- return this.icon
140
- }
141
- return this.model.getIcon()
142
- }
143
-
144
141
  createModelToEdit () {
145
142
  return this.model_.cloneForEdit(this.fields)
146
143
  }
@@ -15,72 +15,7 @@
15
15
  />
16
16
  </app-bar-button>
17
17
 
18
- <list-view
19
- v-bind="$attrs"
20
- :models="models"
21
- :meta="meta"
22
- :action="action"
23
- :scopes="scopes"
24
- :fields="fields"
25
- :table="table"
26
- :initialFilters="initialFilters"
27
- v-on="$listeners"
28
- >
29
- <template #filters="{filters, count}">
30
- <div class="pl-2">
31
- <slot
32
- name="filters"
33
- :filters="filters"
34
- :count="count"
35
- />
36
- </div>
37
- </template>
38
-
39
- <template
40
- v-if="table"
41
- #header-table
42
- >
43
- <div />
44
-
45
- <slot name="header" />
46
- </template>
47
-
48
- <template
49
- v-if="table"
50
- #model-table="{ model }"
51
- >
52
- <v-icon
53
- :color="model.getIcon().color"
54
- size="1.5rem"
55
- v-text="model.getIcon().icon"
56
- />
57
-
58
- <slot
59
- name="model"
60
- :model="model"
61
- />
62
-
63
- <div class="lastColumn" />
64
- </template>
65
-
66
- <template
67
- v-if="!table"
68
- #model="{ model }"
69
- >
70
- <a-row gap="4">
71
- <v-icon
72
- :color="model.getIcon().color"
73
- size="2rem"
74
- v-text="model.getIcon().icon"
75
- />
76
-
77
- <slot
78
- name="model"
79
- :model="model"
80
- />
81
- </a-row>
82
- </template>
83
- </list-view>
18
+ <slot />
84
19
  </div>
85
20
  </template>
86
21
 
@@ -89,42 +24,13 @@ import { Component, Vue } from 'vue-property-decorator'
89
24
  import { apiResources } from '@afeefa/api-resources-client'
90
25
 
91
26
  @Component({
92
- props: ['models', 'meta', 'title', 'newTitle', 'newLink', 'table']
27
+ props: ['icon', 'title', 'newTitle', 'newLink', 'Model']
93
28
  })
94
29
  export default class ListPage extends Vue {
95
30
  $hasOptions = ['add']
96
31
 
97
- created () {
98
- if (!this.$parent.constructor.getListConfig) {
99
- console.warn('<list-view> owner must provide a static getListConfig method.')
100
- }
101
- }
102
-
103
- get listConfig () {
104
- return this.$parent.constructor.getListConfig(this.$route)
105
- }
106
-
107
- get ModelClass () {
108
- return this.listConfig.ModelClass
109
- }
110
-
111
- get action () {
112
- if (this.listConfig.action) {
113
- return this.listConfig.action
114
- }
115
- return this.ModelClass.getAction(this.$routeDefinition, 'list')
116
- }
117
-
118
- get scopes () {
119
- return this.listConfig.scopes
120
- }
121
-
122
- get initialFilters () {
123
- return this.listConfig.initialFilters
124
- }
125
-
126
- get fields () {
127
- return this.listConfig.fields
32
+ get _icon () {
33
+ return this.icon || this.Model.icon
128
34
  }
129
35
 
130
36
  get _title () {
@@ -132,7 +38,7 @@ export default class ListPage extends Vue {
132
38
  return this.title
133
39
  }
134
40
 
135
- const type = apiResources.getType(this.ModelClass.type)
41
+ const type = apiResources.getType(this.Model.type)
136
42
  return type.t('TITLE_PLURAL')
137
43
  }
138
44
 
@@ -141,33 +47,12 @@ export default class ListPage extends Vue {
141
47
  return this.newTitle
142
48
  }
143
49
 
144
- const type = apiResources.getType(this.ModelClass.type)
50
+ const type = apiResources.getType(this.Model.type)
145
51
  return type.t('TITLE_SINGULAR')
146
52
  }
147
53
 
148
- get _icon () {
149
- if (this.icon) {
150
- return this.icon
151
- }
152
- return this.ModelClass.icon
153
- }
154
-
155
54
  get _newLink () {
156
- if (this.newLink) {
157
- if (typeof this.newLink === 'function') {
158
- return this.newLink(this.$route.params)
159
- } else {
160
- return this.newLink
161
- }
162
- }
163
- return this.ModelClass.getLink('new')
55
+ return this.newLink || this.Model.getLink('new')
164
56
  }
165
57
  }
166
58
  </script>
167
-
168
-
169
- <style lang="scss" scoped>
170
- .lastColumn {
171
- width: 100%;
172
- }
173
- </style>
@@ -19,13 +19,7 @@ function load (route) {
19
19
  const routeDefinition = route.meta.routeDefinition
20
20
  const Component = routeDefinition.config.detail
21
21
  const detailConfig = Component.getDetailConfig(route)
22
-
23
- let action = null
24
- if (detailConfig.ModelClass) {
25
- action = detailConfig.ModelClass.getAction(routeDefinition, 'get')
26
- } else {
27
- action = detailConfig.action
28
- }
22
+ const action = detailConfig.action || detailConfig.ModelClass.getAction('get')
29
23
 
30
24
  return new GetAction()
31
25
  .setAction(action)
@@ -20,13 +20,7 @@ function load (route) {
20
20
  const routeDefinition = route.meta.routeDefinition
21
21
  const Component = routeDefinition.config.edit
22
22
  const editConfig = Component.getEditConfig(route)
23
-
24
- let action = null
25
- if (editConfig.ModelClass) {
26
- action = editConfig.ModelClass.getAction(routeDefinition, 'get')
27
- } else {
28
- action = editConfig.getAction
29
- }
23
+ const action = editConfig.getAction || editConfig.ModelClass.getAction('get')
30
24
 
31
25
  return new GetAction()
32
26
  .setAction(action)
@@ -10,6 +10,7 @@
10
10
  <script>
11
11
  import { Component, Vue, Watch } from 'vue-property-decorator'
12
12
  import { ListAction } from '@a-vue/api-resources/ApiActions'
13
+ import { RouteQueryFilterSource } from '@a-vue/components/list/RouteQueryFilterSource'
13
14
 
14
15
  Component.registerHooks([
15
16
  'beforeRouteEnter',
@@ -28,20 +29,18 @@ let lastVm = null
28
29
  function load (route) {
29
30
  const routeDefinition = route.meta.routeDefinition
30
31
  const Component = routeDefinition.config.list
31
- const listConfig = Component.getListConfig(route)
32
32
 
33
- let action = null
34
- if (listConfig.ModelClass) {
35
- action = listConfig.ModelClass.getAction(routeDefinition, 'list')
36
- } else {
37
- action = listConfig.action
33
+ if (!Component.listViewRequest) {
34
+ console.warn('A list route component must implement a static listViewRequest property.')
38
35
  }
39
36
 
37
+ const request = Component.listViewRequest.clone()
38
+ .initFromFilterSource(new RouteQueryFilterSource(route))
39
+ .recreateFromHistory(route.path)
40
+ .toApiRequest()
41
+
40
42
  return new ListAction()
41
- .setAction(action)
42
- .setFields(listConfig.fields)
43
- .setScopes(listConfig.scopes)
44
- .setFiltersForRoute(route)
43
+ .setRequest(request)
45
44
  .load()
46
45
  }
47
46
 
@@ -1,5 +1,6 @@
1
- import { Model as ApiResourcesModel } from '@afeefa/api-resources-client'
1
+ import { Model as ApiResourcesModel, apiResources } from '@afeefa/api-resources-client'
2
2
  import { mdiAlphaMCircle } from '@mdi/js'
3
+
3
4
  export class Model extends ApiResourcesModel {
4
5
  static resourceType = null
5
6
  static routeName = null
@@ -9,12 +10,14 @@ export class Model extends ApiResourcesModel {
9
10
  return (new this()).getLink(action)
10
11
  }
11
12
 
12
- static getAction (routeDefinition, action) {
13
+ static getAction (action) {
13
14
  if (this.resourceType) {
14
- const api = routeDefinition.config.api
15
- return api.getAction(this.resourceType, action)
15
+ return apiResources.getAction({
16
+ resource: this.resourceType,
17
+ action
18
+ })
16
19
  }
17
- console.warn('You can\'t get an action of a model without resourceType:', this.type)
20
+ console.warn('You can\'t get an action out of a model without resourceType:', this.type)
18
21
  return null
19
22
  }
20
23
 
@@ -32,8 +35,8 @@ export class Model extends ApiResourcesModel {
32
35
  }
33
36
  }
34
37
 
35
- getAction (routeDefinition, action) {
36
- return this.constructor.getAction(routeDefinition, action)
38
+ getAction (action) {
39
+ return this.constructor.getAction(action)
37
40
  }
38
41
 
39
42
  getIcon () {
@@ -0,0 +1,43 @@
1
+ $fontUrl: '';
2
+
3
+ @if variable-exists(ibmPlexSansFontUrl) {
4
+ $fontUrl: $ibmPlexSansFontUrl;
5
+ }
6
+
7
+ /* ibm-plex-sans-regular - latin */
8
+ @font-face {
9
+ font-family: 'IBM Plex Sans';
10
+ font-style: normal;
11
+ font-weight: 400;
12
+ src: local(''),
13
+ url('#{$fontUrl}/ibm-plex-sans-v9-latin-regular.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
14
+ url('#{$fontUrl}/ibm-plex-sans-v9-latin-regular.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
15
+ }
16
+
17
+ /* ibm-plex-sans-italic - latin */
18
+ @font-face {
19
+ font-family: 'IBM Plex Sans';
20
+ font-style: italic;
21
+ font-weight: 400;
22
+ src: local(''),
23
+ url('#{$fontUrl}/ibm-plex-sans-v9-latin-italic.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
24
+ url('#{$fontUrl}/ibm-plex-sans-v9-latin-italic.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
25
+ }
26
+ /* ibm-plex-sans-700 - latin */
27
+ @font-face {
28
+ font-family: 'IBM Plex Sans';
29
+ font-style: normal;
30
+ font-weight: 700;
31
+ src: local(''),
32
+ url('#{$fontUrl}/ibm-plex-sans-v9-latin-700.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
33
+ url('#{$fontUrl}/ibm-plex-sans-v9-latin-700.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
34
+ }
35
+ /* ibm-plex-sans-700italic - latin */
36
+ @font-face {
37
+ font-family: 'IBM Plex Sans';
38
+ font-style: italic;
39
+ font-weight: 700;
40
+ src: local(''),
41
+ url('#{$fontUrl}/ibm-plex-sans-v9-latin-700italic.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
42
+ url('#{$fontUrl}/ibm-plex-sans-v9-latin-700italic.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
43
+ }
@@ -1,4 +0,0 @@
1
- export class QuerySourceType {
2
- static ROUTE = 'route'
3
- static OBJECT = 'object'
4
- }