@afeefa/vue-app 0.0.43 → 0.0.47

Sign up to get free protection for your applications and to get access to all the features.
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
- }