@triptyk/ember-yeti-table 3.0.0 → 3.0.2

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 (130) hide show
  1. package/LICENSE.md +1 -1
  2. package/README.md +9 -115
  3. package/declarations/components/yeti-table/body.d.ts +32 -0
  4. package/declarations/components/yeti-table/body.d.ts.map +1 -0
  5. package/declarations/components/yeti-table/header.d.ts +33 -0
  6. package/declarations/components/yeti-table/header.d.ts.map +1 -0
  7. package/declarations/components/yeti-table/pagination.d.ts +40 -0
  8. package/declarations/components/yeti-table/pagination.d.ts.map +1 -0
  9. package/declarations/components/yeti-table/table.d.ts +21 -0
  10. package/declarations/components/yeti-table/table.d.ts.map +1 -0
  11. package/declarations/components/yeti-table/tbody/row/cell.d.ts +44 -0
  12. package/declarations/components/yeti-table/tbody/row/cell.d.ts.map +1 -0
  13. package/declarations/components/yeti-table/tbody/row.d.ts +37 -0
  14. package/declarations/components/yeti-table/tbody/row.d.ts.map +1 -0
  15. package/declarations/components/yeti-table/tbody.d.ts +29 -0
  16. package/declarations/components/yeti-table/tbody.d.ts.map +1 -0
  17. package/declarations/components/yeti-table/tfoot/row/cell.d.ts +40 -0
  18. package/declarations/components/yeti-table/tfoot/row/cell.d.ts.map +1 -0
  19. package/declarations/components/yeti-table/tfoot/row.d.ts +37 -0
  20. package/declarations/components/yeti-table/tfoot/row.d.ts.map +1 -0
  21. package/declarations/components/yeti-table/tfoot.d.ts +27 -0
  22. package/declarations/components/yeti-table/tfoot.d.ts.map +1 -0
  23. package/declarations/components/yeti-table/thead/row/cell.d.ts +54 -0
  24. package/declarations/components/yeti-table/thead/row/cell.d.ts.map +1 -0
  25. package/declarations/components/yeti-table/thead/row/column.d.ts +69 -0
  26. package/declarations/components/yeti-table/thead/row/column.d.ts.map +1 -0
  27. package/declarations/components/yeti-table/thead/row.d.ts +55 -0
  28. package/declarations/components/yeti-table/thead/row.d.ts.map +1 -0
  29. package/declarations/components/yeti-table/thead.d.ts +34 -0
  30. package/declarations/components/yeti-table/thead.d.ts.map +1 -0
  31. package/declarations/components/yeti-table.d.ts +107 -0
  32. package/declarations/components/yeti-table.d.ts.map +1 -0
  33. package/declarations/index.d.ts +1 -0
  34. package/declarations/index.d.ts.map +1 -0
  35. package/declarations/template-registry.d.ts +1 -0
  36. package/declarations/template-registry.d.ts.map +1 -0
  37. package/declarations/themes/default-theme.d.ts +3 -27
  38. package/declarations/themes/default-theme.d.ts.map +1 -1
  39. package/declarations/types.d.ts +82 -0
  40. package/declarations/types.d.ts.map +1 -0
  41. package/declarations/utils/create-regex.d.ts +1 -1
  42. package/declarations/utils/create-regex.d.ts.map +1 -1
  43. package/declarations/utils/filtering-utils.d.ts +2 -4
  44. package/declarations/utils/filtering-utils.d.ts.map +1 -1
  45. package/declarations/utils/sorting-utils.d.ts +6 -15
  46. package/declarations/utils/sorting-utils.d.ts.map +1 -1
  47. package/dist/components/yeti-table/body.js +19 -14
  48. package/dist/components/yeti-table/body.js.map +1 -1
  49. package/dist/components/yeti-table/header.js +10 -10
  50. package/dist/components/yeti-table/header.js.map +1 -1
  51. package/dist/components/yeti-table/pagination.js +14 -44
  52. package/dist/components/yeti-table/pagination.js.map +1 -1
  53. package/dist/components/yeti-table/table.js +1 -23
  54. package/dist/components/yeti-table/table.js.map +1 -1
  55. package/dist/components/yeti-table/tbody/row/cell.js +12 -12
  56. package/dist/components/yeti-table/tbody/row/cell.js.map +1 -1
  57. package/dist/components/yeti-table/tbody/row.js +15 -21
  58. package/dist/components/yeti-table/tbody/row.js.map +1 -1
  59. package/dist/components/yeti-table/tbody.js +1 -0
  60. package/dist/components/yeti-table/tbody.js.map +1 -1
  61. package/dist/components/yeti-table/tfoot/row/cell.js +9 -9
  62. package/dist/components/yeti-table/tfoot/row/cell.js.map +1 -1
  63. package/dist/components/yeti-table/tfoot/row.js +11 -11
  64. package/dist/components/yeti-table/tfoot/row.js.map +1 -1
  65. package/dist/components/yeti-table/tfoot.js +1 -0
  66. package/dist/components/yeti-table/tfoot.js.map +1 -1
  67. package/dist/components/yeti-table/thead/row/cell.js +11 -8
  68. package/dist/components/yeti-table/thead/row/cell.js.map +1 -1
  69. package/dist/components/yeti-table/thead/row/column.js +27 -128
  70. package/dist/components/yeti-table/thead/row/column.js.map +1 -1
  71. package/dist/components/yeti-table/thead/row.js +15 -15
  72. package/dist/components/yeti-table/thead/row.js.map +1 -1
  73. package/dist/components/yeti-table/thead.js +3 -22
  74. package/dist/components/yeti-table/thead.js.map +1 -1
  75. package/dist/components/yeti-table.js +102 -303
  76. package/dist/components/yeti-table.js.map +1 -1
  77. package/dist/index.js +2 -0
  78. package/dist/index.js.map +1 -0
  79. package/dist/template-registry.js +2 -0
  80. package/dist/template-registry.js.map +1 -0
  81. package/dist/themes/default-theme.js +3 -2
  82. package/dist/themes/default-theme.js.map +1 -1
  83. package/dist/types.js +2 -0
  84. package/dist/types.js.map +1 -0
  85. package/dist/utils/create-regex.js +6 -6
  86. package/dist/utils/create-regex.js.map +1 -1
  87. package/dist/utils/filtering-utils.js +20 -8
  88. package/dist/utils/filtering-utils.js.map +1 -1
  89. package/dist/utils/sorting-utils.js +13 -18
  90. package/dist/utils/sorting-utils.js.map +1 -1
  91. package/package.json +37 -16
  92. package/src/components/yeti-table/{body.gjs → body.gts} +49 -45
  93. package/src/components/yeti-table/header.gts +67 -0
  94. package/src/components/yeti-table/pagination.gts +118 -0
  95. package/src/components/yeti-table/table.gts +27 -0
  96. package/src/components/yeti-table/tbody/row/{cell.gjs → cell.gts} +38 -19
  97. package/src/components/yeti-table/tbody/row.gts +76 -0
  98. package/src/components/yeti-table/tbody.gts +53 -0
  99. package/src/components/yeti-table/tfoot/row/cell.gts +64 -0
  100. package/src/components/yeti-table/tfoot/row.gts +59 -0
  101. package/src/components/yeti-table/tfoot.gts +41 -0
  102. package/src/components/yeti-table/thead/row/{cell.gjs → cell.gts} +36 -13
  103. package/src/components/yeti-table/thead/row/column.gts +177 -0
  104. package/src/components/yeti-table/thead/row.gts +105 -0
  105. package/src/components/yeti-table/thead.gts +65 -0
  106. package/src/components/yeti-table.gts +633 -0
  107. package/src/template-registry.ts +10 -0
  108. package/src/themes/{default-theme.js → default-theme.ts} +5 -1
  109. package/src/types.ts +94 -0
  110. package/src/utils/{create-regex.js → create-regex.ts} +10 -10
  111. package/src/utils/filtering-utils.ts +91 -0
  112. package/src/utils/{sorting-utils.js → sorting-utils.ts} +35 -26
  113. package/dist/_app_/themes/default-theme.js +0 -1
  114. package/dist/_app_/utils/create-regex.js +0 -1
  115. package/dist/_app_/utils/filtering-utils.js +0 -1
  116. package/dist/_app_/utils/sorting-utils.js +0 -1
  117. package/src/components/yeti-table/header.gjs +0 -54
  118. package/src/components/yeti-table/pagination.gjs +0 -155
  119. package/src/components/yeti-table/table.gjs +0 -34
  120. package/src/components/yeti-table/tbody/row.gjs +0 -89
  121. package/src/components/yeti-table/tbody.gjs +0 -55
  122. package/src/components/yeti-table/tfoot/row/cell.gjs +0 -45
  123. package/src/components/yeti-table/tfoot/row.gjs +0 -44
  124. package/src/components/yeti-table/tfoot.gjs +0 -33
  125. package/src/components/yeti-table/thead/row/column.gjs +0 -260
  126. package/src/components/yeti-table/thead/row.gjs +0 -71
  127. package/src/components/yeti-table/thead.gjs +0 -45
  128. package/src/components/yeti-table.gjs +0 -780
  129. package/src/utils/filtering-utils.js +0 -75
  130. /package/src/{.gitkeep → index.ts} +0 -0
@@ -1,780 +0,0 @@
1
- import { getOwner } from '@ember/application';
2
- import { action, notifyPropertyChange } from '@ember/object';
3
- import { later, schedule, scheduleOnce } from '@ember/runloop';
4
- import { isEmpty, isPresent } from '@ember/utils';
5
- import Component from '@glimmer/component';
6
- import { tracked } from '@glimmer/tracking';
7
- import merge from 'deepmerge';
8
- import { use } from 'ember-resources';
9
- import { trackedFunction } from 'reactiveweb/function';
10
- import { keepLatest } from 'reactiveweb/keep-latest';
11
- import { dedupeTracked, localCopy } from 'tracked-toolbox';
12
- import { cached } from '@glimmer/tracking';
13
-
14
- import DEFAULT_THEME from '../themes/default-theme.js';
15
- import filterData from '../utils/filtering-utils.js';
16
- import {
17
- compareValues,
18
- mergeSort,
19
- sortMultiple,
20
- } from '../utils/sorting-utils.js';
21
- import Helper from '@ember/component/helper';
22
- /**
23
- The primary Yeti Table component. This component represents the root of the
24
- table, and manages high level state of all of its subcomponents.
25
-
26
- ```hbs
27
- <YetiTable @data={{this.data}} as |table|>
28
-
29
- <table.header as |header|>
30
- <header.column @prop="firstName">
31
- First name
32
- </header.column>
33
- <header.column @prop="lastName">
34
- Last name
35
- </header.column>
36
- <header.column @prop="points">
37
- Points
38
- </header.column>
39
- </table.header>
40
-
41
- <table.body/>
42
-
43
- </YetiTable>
44
- ```
45
-
46
- ```hbs
47
- <YetiTable @data={{this.data}} as |table|>
48
-
49
- <table.thead as |thead|>
50
- <thead.row as |row|>
51
- <row.column @prop="firstName">
52
- First name
53
- </row.column>
54
- <row.column @prop="lastName">
55
- Last name
56
- </row.column>
57
- <row.column @prop="points">
58
- Points
59
- </row.column>
60
- </thead.row>
61
- </table.thead>
62
-
63
- <table.body/>
64
-
65
- </YetiTable>
66
- ```
67
- @class YetiTable
68
- @yield {object} table
69
- @yield {Component} table.header the table header component (Single row in header)
70
- @yield {Component} table.thead the table header component (Allows multiple rows in header)
71
- @yield {Component} table.body the table body component
72
- @yield {Component} table.tfoot the table footer component
73
- @yield {Component} table.pagination the pagination controls component
74
- @yield {object} table.actions an object that contains actions to interact with the table
75
- @yield {object} table.paginationData object that represents the current pagination state
76
- @yield {boolean} table.isLoading boolean that is `true` when data is being loaded
77
- @yield {array} table.columns the columns on the table
78
- @yield {array} table.visibleColumns the visible columns on the table
79
- @yield {array} table.rows an array of all the rows yeti table knows of. In the sync case, it will contain the entire dataset. In the async case, it will be the same as `table.visibleRows`
80
- @yield {number} table.totalRows the total number of rows on the table (regardless of pagination). Important argument in the async case to inform yeti table of the total number of rows in the dataset.
81
- @yield {array} table.visibleRows the rendered rows on the table account for pagination, filtering, etc; when pagination is false, it will be the same length as totalRows
82
- @yield {object} table.theme the theme being used
83
- */
84
- // template imports
85
- import { hash } from '@ember/helper';
86
- import Table from './yeti-table/table.gjs';
87
- import Header from './yeti-table/header.gjs';
88
- import THead from './yeti-table/thead.gjs';
89
- import Body from './yeti-table/body.gjs';
90
- import TBody from './yeti-table/tbody.gjs';
91
- import TFoot from './yeti-table/tfoot.gjs';
92
- import Pagination from './yeti-table/pagination.gjs';
93
-
94
- // bring ember-concurrency didCancel helper instead of
95
- // including the whole dependency
96
- const TASK_CANCELATION_NAME = 'TaskCancelation';
97
- const didCancel = function (e) {
98
- return e && e.name === TASK_CANCELATION_NAME;
99
- };
100
-
101
- const getConfigWithDefault = function (key, defaultValue) {
102
- return function () {
103
- return this.config[key] ?? defaultValue;
104
- };
105
- };
106
-
107
- // we keep `totalRows` updated manually in xwaan untracked property
108
- // to allow the user to update it in a loadData call and avoid
109
- // a re-run of the main tracked function
110
- class UpdateTotalRows extends Helper {
111
- compute(positional, { context }) {
112
- context.totalRows = positional[0];
113
- notifyPropertyChange(context, 'normalizedTotalRows');
114
- notifyPropertyChange(context, 'paginationData');
115
- return '';
116
- }
117
- }
118
-
119
- // we need some control of how we update the filter property, hence this modifier
120
- // in this case, any falsy value will be considered as en empty string, which will then
121
- // be deduped.
122
- class UpdateFilter extends Helper {
123
- compute(positional, { context }) {
124
- context.filter = positional[0] || '';
125
- return '';
126
- }
127
- }
128
-
129
- class ProcessedData extends Helper {
130
- compute(positional, { loadData, context }) {
131
- let data = context.latestData ?? [];
132
-
133
- if (!loadData) {
134
- context.processData(data);
135
- } else {
136
- // This is instrumental to ignoreDataChanges working
137
- context.processedData = data;
138
- }
139
- return '';
140
- }
141
- }
142
-
143
- export default class YetiTable extends Component {
144
- <template>
145
- {{#let
146
- (hash
147
- table=(component Table theme=this.mergedTheme parent=this)
148
- header=(component
149
- Header
150
- columns=this.columns
151
- onColumnClick=this.onColumnSort
152
- sortable=this.sortable
153
- sortSequence=this.sortSequence
154
- parent=this
155
- theme=this.mergedTheme
156
- )
157
- thead=(component
158
- THead
159
- columns=this.columns
160
- onColumnClick=this.onColumnSort
161
- sortable=this.sortable
162
- sortSequence=this.sortSequence
163
- theme=this.mergedTheme
164
- parent=this
165
- )
166
- body=(component
167
- Body
168
- data=this.processedData
169
- columns=this.columns
170
- theme=this.mergedTheme
171
- parent=this
172
- )
173
- tbody=(component
174
- TBody
175
- data=this.processedData
176
- columns=this.columns
177
- theme=this.mergedTheme
178
- parent=this
179
- )
180
- tfoot=(component
181
- TFoot columns=this.columns theme=this.mergedTheme parent=this
182
- )
183
- pagination=(component
184
- Pagination
185
- disabled=this.isLoading
186
- theme=this.mergedTheme
187
- paginationData=this.paginationData
188
- paginationActions=(hash
189
- previousPage=this.previousPage
190
- nextPage=this.nextPage
191
- goToPage=this.goToPage
192
- changePageSize=this.changePageSize
193
- )
194
- )
195
- actions=this.publicApi
196
- paginationData=this.paginationData
197
- isLoading=this.resolvedData.isPending
198
- columns=this.columns
199
- visibleColumns=this.visibleColumns
200
- rows=this.normalizedRows
201
- totalRows=this.normalizedTotalRows
202
- visibleRows=this.processedData
203
- theme=this.mergedTheme
204
- )
205
- as |api|
206
- }}
207
- {{UpdateTotalRows @totalRows context=this}}
208
- {{UpdateFilter @filter context=this}}
209
- {{ProcessedData loadData=@loadData context=this}}
210
-
211
- {{#if this.renderTableElement}}
212
- <Table @theme={{this.mergedTheme}} @parent={{this}} ...attributes>
213
- {{yield api}}
214
- </Table>
215
- {{else}}
216
- {{yield api}}
217
- {{/if}}
218
-
219
- {{/let}}
220
- </template>
221
- /**
222
- * An object that contains classes for yeti table to apply when rendering its various table
223
- * html elements. The theme object your pass in will be deeply merged with yeti-table's default theme
224
- * and with a theme defined in your environment.js at `ENV['ember-yeti-table'].theme`.
225
- *
226
- * @argument theme
227
- * @type {Object}
228
- */
229
-
230
- /**
231
- * The data for Yeti Table to render. It can be an array or a promise that resolves with an array.
232
- * The only case when `@data` is optional is if a `@loadData` was passed in.
233
- * @argument data
234
- * @type {Array | Promise<Array>}
235
- */
236
-
237
- /**
238
- * The function that will be called when Yeti Table needs data. This argument is used
239
- * when you don't have all the data available or loading all rows at once isn't possible,
240
- * e.g the dataset is too large.
241
- *
242
- * By passing in a function to `@loadData` you assume the responsibility to filter, sort and
243
- * paginate the data (if said features are enabled).
244
- *
245
- * This function must return an array or a promise that resolves with an array.
246
- *
247
- * This function will be called with an argument with the current state of the table.
248
- * Use this object to know what data to fetch, pass it to the server, etc.
249
- * Please check the "Async Data" guide to understand what that object contains and
250
- * an example of its usage.
251
- *
252
- * @argument loadData
253
- * @type {Function}
254
- */
255
-
256
- publicApi = {
257
- previousPage: this.previousPage,
258
- nextPage: this.nextPage,
259
- goToPage: this.goToPage,
260
- changePageSize: this.changePageSize,
261
- reloadData: this.reloadData,
262
- };
263
-
264
- /**
265
- * This function will be called when Yeti Table initializes. It will be called with
266
- * an object argument containing the functions for the possible actions you can make
267
- * on a table. This object contains the following actions:
268
- * - previousPage
269
- * - nextPage
270
- * - goToPage
271
- * - changePageSize
272
- * - reloadData
273
- *
274
- * @argument registerApi
275
- * @type {Function}
276
- */
277
-
278
- /**
279
- * Use this argument to enable the pagination feature. Default is `false`.
280
- *
281
- * @argument pagination
282
- * @type {Boolean}
283
- */
284
- @localCopy('args.pagination', getConfigWithDefault('pagination', false))
285
- pagination;
286
-
287
- /**
288
- * Controls the size of each page. Default is `15`.
289
- *
290
- * @argument pageSize
291
- * @type {number}
292
- */
293
- @localCopy('args.pageSize', getConfigWithDefault('pageSize', 15))
294
- pageSize;
295
-
296
- /**
297
- * Controls the current page to show. Default is `1`.
298
- *
299
- * @argument pageNumber
300
- * @type {number}
301
- */
302
- @localCopy('args.pageNumber', 1)
303
- pageNumber;
304
-
305
- /**
306
- * Optional argument that informs yeti table of how many rows your data has.
307
- * Only needed when using a `@loadData` function and `@pagination={{true}}`.
308
- * When you use `@data`, Yeti Table uses the size of that array.
309
- * This information is used to calculate the pagination information that is yielded
310
- * and passed to the `@loadData` function.
311
- *
312
- * @argument totalRows
313
- * @type {number}
314
- */
315
- totalRows;
316
-
317
- // we keep `totalRows` updated manually in an untracked property
318
- // to allow the user to update it in a loadData call and avoid
319
- // a re-run of the main tracked function
320
- // @action
321
- // updateTotalRows(totalRows) {
322
- // this.totalRows = totalRows;
323
- // notifyPropertyChange(this, 'normalizedTotalRows');
324
- // notifyPropertyChange(this, 'paginationData');
325
- // }
326
-
327
- /**
328
- * The global filter. If passed in, Yeti Table will search all the rows that contain this
329
- * string and show them. Defaults to `''`.
330
- *
331
- * @argument filter
332
- * @type {String}
333
- */
334
- @dedupeTracked
335
- filter = '';
336
-
337
- // we need some control of how we update the filter property, hence this modifier
338
- // in this case, any falsy value will be considered as en empty string, which will then
339
- // be deduped.
340
- // @action
341
- // updateFilter(filter) {
342
- // this.filter = filter || '';
343
- // }
344
-
345
- /**
346
- * An optional function to customize the filtering logic. This function should return true
347
- * or false to either include or exclude the row on the resulting set. If this function depends
348
- * on a value, pass that value as the `@filterUsing` argument.
349
- *
350
- * This function will be called with two arguments:
351
- * - `row` - the current data row to use for filtering
352
- * - `filterUsing` - the value you passed in as `@filterUsing`
353
- *
354
- * @argument filterFunction
355
- * @type {Function}
356
- */
357
-
358
- /**
359
- * If you `@filterFunction` function depends on a different value (other that `@filter`)
360
- * to show, pass it in this argument. Yeti Table uses this argument to know when to recalculate
361
- * the fitlered rows.
362
- *
363
- * @argument filterUsing
364
- * @type {Object}
365
- */
366
-
367
- /**
368
- * Used to enable/disable sorting on all columns. You should use this to avoid passing
369
- * the @sortable argument to all columns. Defaults to `true`.
370
- *
371
- * @argument sortable
372
- * @type {Boolean}
373
- */
374
- @localCopy('args.sortable', getConfigWithDefault('sortable', true))
375
- sortable;
376
-
377
- /**
378
- * Use the `@sortFunction` if you want to completely customize how the row sorting is done.
379
- * It will be invoked with two rows, the current sortings that are applied and the `@compareFunction`.
380
- *
381
- * @argument sortFunction
382
- * @type {Function}
383
- */
384
- @localCopy('args.sortFunction', () => sortMultiple)
385
- sortFunction;
386
-
387
- /**
388
- * Use `@compareFunction` if you just want to customize how two values relate to each other (not the entire row).
389
- * It will be invoked with two values and you just need to return `-1`, `0` or `1` depending on if first value is
390
- * greater than the second or not. The default compare function used is the `compare` function from `@ember/utils`.
391
- *
392
- * @argument compareFunction
393
- * @type {Function}
394
- */
395
- @localCopy('args.compareFunction', () => compareValues)
396
- compareFunction;
397
-
398
- /**
399
- * Use `@sortSequence` to customize the sequence in which the sorting order will cycle when
400
- * clicking on the table headers. You can either pass in a comma-separated string or an array
401
- * of strings. Accepted values are `'asc'`, `'desc'` and `'unsorted'`. The default value is `['asc', 'desc']`.
402
- *
403
- * @argument sortSequence
404
- * @type {Array<string> | string}
405
- */
406
- @localCopy(
407
- 'args.sortSequence',
408
- getConfigWithDefault('sortSequence', ['asc', 'desc']),
409
- )
410
- sortSequence;
411
-
412
- /**
413
- * Use `@ignoreDataChanges` to prevent yeti table from observing changes to the underlying data and resorting or
414
- * refiltering. Useful when doing inline editing in a table.
415
- *
416
- * Defaults to `false`.
417
- *
418
- * This is an initial render only value. Changing it after the table has been rendered will not be respected.
419
- *
420
- * @argument ignoreDataChanges
421
- * @type {boolean}
422
- */
423
- @localCopy(
424
- 'args.ignoreDataChanges',
425
- getConfigWithDefault('ignoreDataChanges', false),
426
- )
427
- ignoreDataChanges;
428
-
429
- /**
430
- * Use `@renderTableElement` to prevent yeti table from rendering the topmost <table> element.
431
- * Might be useful for styling purposes (e.g if you want to place your pagination controls outside
432
- * of your table element). If you set this to `false`, you should render the table element yourself
433
- * using the yielded `<t.table>` component.
434
- *
435
- * Defaults to `true`.
436
- *
437
- * @argument renderTableElement
438
- * @type {boolean}
439
- */
440
- @localCopy('args.renderTableElement', true)
441
- renderTableElement;
442
-
443
- /**
444
- * The `@isColumnVisible` argument can be used to initialize the column visibility in a programmatic way.
445
- * For example, let's say you store the initial column visibility in local storage, then you can
446
- * use this function to initialize the `visible` column of the specific column. The given function should
447
- * return a boolean which will be assigned to the `visible` property of the column. An object representing
448
- * the column is passed in. Sou can use column.prop and column.name to know which column your computed
449
- * the visibility for.
450
- *
451
- * @argument isColumnVisible
452
- * @type {Function}
453
- */
454
-
455
- // If the theme is replaced, this will invalidate, but not if any prop under theme is changed
456
- @cached
457
- get mergedTheme() {
458
- let configTheme = this.config.theme || {};
459
- let localTheme = this.args.theme || {};
460
- return merge.all([DEFAULT_THEME, configTheme, localTheme]);
461
- }
462
-
463
- @cached
464
- get visibleColumns() {
465
- return this.columns.filter((c) => c.visible === true);
466
- }
467
-
468
- config =
469
- getOwner(this).resolveRegistration('config:environment')[
470
- 'ember-yeti-table'
471
- ] || {};
472
-
473
- get normalizedTotalRows() {
474
- if (!this.args.loadData) {
475
- // sync scenario using @data
476
- return this.processedDataRows?.length || 0;
477
- } else {
478
- // async scenario. @loadData is present.
479
- if (this.totalRows === undefined) {
480
- // @totalRows was not passed in. Use the latest returned data set length as a fallback
481
- return this.previousResolvedData.length || 0;
482
- } else {
483
- // @totalRows was passed in.
484
- return this.totalRows;
485
- }
486
- }
487
- }
488
-
489
- get normalizedRows() {
490
- if (!this.args.loadData) {
491
- // sync scenario using @data
492
- return this.processedDataRows;
493
- } else {
494
- // async scenario. @loadData is present.
495
- return this.processedData;
496
- }
497
- }
498
-
499
- get paginationData() {
500
- let pageSize = this.pageSize;
501
- let pageNumber = this.pageNumber;
502
- let totalRows = this.normalizedTotalRows;
503
- let isLastPage, totalPages;
504
-
505
- if (totalRows) {
506
- totalPages = Math.ceil(totalRows / pageSize);
507
- pageNumber = Math.min(pageNumber, totalPages);
508
- isLastPage = pageNumber === totalPages;
509
- }
510
-
511
- let isFirstPage = pageNumber === 1;
512
- let pageStart = (pageNumber - 1) * pageSize + 1;
513
- let pageEnd = pageStart + pageSize - 1;
514
-
515
- if (totalRows) {
516
- pageEnd = Math.min(pageEnd, totalRows);
517
- }
518
-
519
- return {
520
- pageSize,
521
- pageNumber,
522
- pageStart,
523
- pageEnd,
524
- isFirstPage,
525
- isLastPage,
526
- totalRows,
527
- totalPages,
528
- };
529
- }
530
-
531
- @tracked
532
- columns = [];
533
-
534
- constructor(owner, args) {
535
- super(...arguments);
536
-
537
- console.log(owner, args);
538
-
539
- if (typeof this.args.registerApi === 'function') {
540
- // eslint-disable-next-line ember/no-runloop
541
- scheduleOnce('actions', null, this.args.registerApi, this.publicApi);
542
- }
543
- }
544
-
545
- previousResolvedData = [];
546
-
547
- resolvedData = trackedFunction(this, async () => {
548
- let data = this.args.data;
549
-
550
- if (this.columns.length == 0) {
551
- return [];
552
- }
553
-
554
- // call loadData if exists
555
- if (typeof this.args.loadData === 'function') {
556
- let params = this.computeLoadDataParams();
557
-
558
- try {
559
- console.log("loadData", params);
560
-
561
- data = await this.args.loadData(params);
562
-
563
- console.log("loadData end");
564
-
565
- } catch (e) {
566
- console.log(e);
567
-
568
- if (!didCancel(e)) {
569
- // re-throw the non-cancellation error
570
- throw e;
571
- }
572
- }
573
- } else if (data?.then) {
574
- // resolve the data promise (either from the @loadData call or @data)
575
- data = await data;
576
- }
577
-
578
- if (this.isDestroyed) {
579
- return;
580
- }
581
-
582
- data = data || [];
583
-
584
- this.previousResolvedData = data;
585
-
586
- return data;
587
- });
588
-
589
- @use latestData = keepLatest({
590
- value: () => this.resolvedData.value ?? [],
591
- when: () => this.resolvedData.isPending,
592
- });
593
-
594
- @tracked
595
- processedData;
596
-
597
- @tracked
598
- processedDataRows;
599
-
600
- processData(data) {
601
- // only columns that have filterable = true and a prop defined will be considered
602
- let columns = this.columns.filter((c) => c.filterable && isPresent(c.prop));
603
-
604
- let sortableColumns = this.columns.filter((c) => !isEmpty(c.sort));
605
- let sortings = sortableColumns.map((c) => ({
606
- prop: c.prop,
607
- direction: c.sort,
608
- }));
609
-
610
- let filterFunction = this.args.filterFunction;
611
- let filterUsing = this.args.filterUsing;
612
- let filter = this.filter;
613
-
614
- let processTheData = () => {
615
- // filter the data
616
- data = filterData(data, columns, filter, filterFunction, filterUsing);
617
- // Sort the data
618
- if (sortings.length > 0) {
619
- data = mergeSort(data, (itemA, itemB) => {
620
- return this.sortFunction(
621
- itemA,
622
- itemB,
623
- sortings,
624
- this.compareFunction,
625
- );
626
- });
627
- }
628
-
629
- this.processedDataRows = data;
630
-
631
- // Paginate the Data
632
- if (this.pagination) {
633
- let { pageStart, pageEnd } = this.paginationData;
634
- data = data.slice(pageStart - 1, pageEnd); // slice excludes last element so we don't need to subtract 1
635
- }
636
-
637
- this.processedData = data;
638
- };
639
-
640
- if (this.ignoreDataChanges) {
641
- // eslint-disable-next-line ember/no-runloop
642
- later(processTheData, 0);
643
- } else {
644
- processTheData();
645
- }
646
- }
647
-
648
- computeLoadDataParams() {
649
- let params = {};
650
-
651
- if (this.pagination) {
652
- params.paginationData = this.paginationData;
653
- }
654
-
655
- params.sortData = this.columns
656
- .filter((c) => !isEmpty(c.sort))
657
- .map((c) => ({ prop: c.prop, direction: c.sort }));
658
- params.filterData = {
659
- filter: this.filter,
660
- filterUsing: this.args.filterUsing,
661
- columnFilters: this.columns.map((c) => ({
662
- prop: c.prop,
663
- filter: c.filter,
664
- filterUsing: c.filterUsing,
665
- })),
666
- };
667
-
668
- return params;
669
- }
670
-
671
- paginateData(data) {
672
- if (this.pagination) {
673
- let { pageStart, pageEnd } = this.paginationData;
674
- data = data.slice(pageStart - 1, pageEnd); // slice excludes last element so we don't need to subtract 1
675
- }
676
-
677
- return data;
678
- }
679
-
680
- @action
681
- async reloadData() {
682
- return await this.resolvedData.retry();
683
- }
684
-
685
- @action
686
- onColumnSort(column, e) {
687
- if (column.isSorted) {
688
- // if this column is already sorted, calculate the next
689
- // sorting on the sequence.
690
- let direction = column.sort;
691
- let sortSequence = column.normalizedSortSequence;
692
- direction =
693
- sortSequence[
694
- (sortSequence.indexOf(direction) + 1) % sortSequence.length
695
- ];
696
-
697
- if (direction === 'unsorted') {
698
- direction = null;
699
- }
700
- column.sort = direction;
701
-
702
- if (!e.shiftKey) {
703
- // if not pressed shift, reset other column sorting
704
- let columns = this.columns.filter((c) => c !== column);
705
- columns.forEach((c) => (c.sort = null));
706
- }
707
- } else {
708
- // use first direction from sort sequence
709
- let direction = column.normalizedSortSequence[0];
710
- // create new sorting
711
- column.sort = direction;
712
-
713
- // normal click replaces all sortings with the new one
714
- // shift click adds a new sorting to the existing ones
715
- if (!e.shiftKey) {
716
- // if not pressed shift, reset other column sortings
717
- let columns = this.columns.filter((c) => c !== column);
718
- columns.forEach((c) => (c.sort = null));
719
- }
720
- }
721
- }
722
-
723
- @action
724
- previousPage() {
725
- if (this.pagination) {
726
- this.pageNumber = Math.max(this.pageNumber - 1, 1);
727
- }
728
- }
729
-
730
- @action
731
- nextPage() {
732
- if (this.pagination) {
733
- let { isLastPage } = this.paginationData;
734
-
735
- if (!isLastPage) {
736
- this.pageNumber = this.pageNumber + 1;
737
- }
738
- }
739
- }
740
-
741
- @action
742
- goToPage(pageNumber) {
743
- if (this.pagination) {
744
- let { totalPages } = this.paginationData;
745
- pageNumber = Math.max(pageNumber, 1);
746
-
747
- if (totalPages) {
748
- pageNumber = Math.min(pageNumber, totalPages);
749
- }
750
-
751
- this.pageNumber = pageNumber;
752
- }
753
- }
754
-
755
- @action
756
- changePageSize(pageSize) {
757
- if (this.pagination) {
758
- this.pageSize = parseInt(pageSize);
759
- }
760
- }
761
-
762
- registerColumn(column) {
763
- // eslint-disable-next-line ember/no-runloop
764
- schedule('afterRender', this, function () {
765
- if (typeof this.args.isColumnVisible === 'function') {
766
- column.visible = this.args.isColumnVisible(column);
767
- }
768
-
769
- if (!this.columns.includes(column)) {
770
- this.columns = [...this.columns, column];
771
- }
772
- });
773
- }
774
-
775
- unregisterColumn(column) {
776
- if (this.columns.includes(column)) {
777
- this.columns = this.columns.filter((c) => c !== column);
778
- }
779
- }
780
- }