aloha-vue 1.0.74 → 1.0.76

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.
package/docs/package.json CHANGED
@@ -12,7 +12,7 @@
12
12
  },
13
13
  "dependencies": {
14
14
  "@popperjs/core": "2.11.6",
15
- "aloha-css": "1.0.47",
15
+ "aloha-css": "1.0.51",
16
16
  "lodash-es": "^4.17.21",
17
17
  "tiny-emitter": "2.1.0",
18
18
  "vue": "3.2.31",
@@ -21,6 +21,7 @@ export default {
21
21
  sortId: "aloha",
22
22
  locked: true,
23
23
  grow: 2,
24
+ footerSlot: "footerAloha",
24
25
  },
25
26
  {
26
27
  label: "Aloha frei",
@@ -28,18 +29,22 @@ export default {
28
29
  path: "aloha",
29
30
  sortId: "aloha",
30
31
  grow: 0,
32
+ footerPath: "aloha",
31
33
  },
32
34
  {
33
35
  label: "Hola",
34
36
  id: "hola",
35
37
  path: "hola",
36
38
  sortId: "hola",
39
+ footerPath: "hola",
37
40
  },
38
41
  {
39
42
  label: "Default",
40
43
  id: "default",
41
44
  path: "default",
42
45
  defaultValue: "-",
46
+ footerPath: "default",
47
+ footerDefaultValue: "-",
43
48
  },
44
49
  {
45
50
  label: "Hola2",
@@ -47,6 +52,7 @@ export default {
47
52
  path: "hola",
48
53
  sortId: "hola",
49
54
  hide: true,
55
+ footerPath: "hola",
50
56
  },
51
57
  {
52
58
  label: "Obj",
@@ -55,27 +61,32 @@ export default {
55
61
  sortId: "obj.aloha",
56
62
  slot: "get",
57
63
  filter: "boolean",
64
+ footerPath: "obj.aloha",
58
65
  },
59
66
  {
60
67
  label: "Obj2",
61
68
  id: "obj2",
62
69
  path: "obj.aloha",
63
70
  sortId: "obj.aloha",
71
+ footerPath: "obj.aloha",
64
72
  },
65
73
  {
66
74
  label: "Obj3",
67
75
  id: "obj3",
68
76
  path: "obj.aloha",
77
+ footerPath: "obj.aloha",
69
78
  },
70
79
  {
71
80
  label: "Obj4",
72
81
  id: "obj4",
73
82
  path: "obj.aloha",
83
+ footerPath: "obj.aloha",
74
84
  },
75
85
  {
76
86
  label: "Geld",
77
87
  id: "geld",
78
88
  path: "geld",
89
+ footerPath: "geld",
79
90
  },
80
91
  {
81
92
  label: "Slot",
@@ -90,6 +101,14 @@ export default {
90
101
  hide: true,
91
102
  },
92
103
  ],
104
+ rowsFooter: [
105
+ {
106
+ index: 1,
107
+ },
108
+ {
109
+ index: 2,
110
+ },
111
+ ],
93
112
  data: [],
94
113
  isLoadingOptions: false,
95
114
  rowActions: [
@@ -14,6 +14,7 @@ div
14
14
  :is-columns-dnd="true"
15
15
  :is-pagination="true"
16
16
  :filters="filters"
17
+ :rows-footer="rowsFooter"
17
18
  v-model:modelQuickSearch="modelQuickSearch"
18
19
  v-model:modelFilters="modelFilters"
19
20
  @change-columns-ordering="changeColumnsOrdering"
@@ -38,6 +39,11 @@ div
38
39
  )
39
40
  button.a_btn.a_btn_primary Click me
40
41
 
42
+ template(
43
+ v-slot:footerAloha="{ row, rows }"
44
+ )
45
+ strong {{ rows.length }}
46
+
41
47
  span modelQuickSearch: {{ modelQuickSearch }}
42
48
  div modelFilters:
43
49
  pre {{ modelFilters }}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "aloha-vue",
3
3
  "description": "Project aloha",
4
- "version": "1.0.74",
4
+ "version": "1.0.76",
5
5
  "author": "Ilia Brykin",
6
6
  "scripts": {
7
7
  "build-icons": "node scriptsNode/iconsSvgToJs.js bootstrap3 && node scriptsNode/iconsSvgToJs.js bootstrap-1-9-1"
@@ -74,10 +74,6 @@ export default {
74
74
  required: false,
75
75
  default: () => [],
76
76
  },
77
- hideLabel: {
78
- type: Boolean,
79
- required: false,
80
- },
81
77
  id: {
82
78
  type: String,
83
79
  required: false,
@@ -93,6 +89,11 @@ export default {
93
89
  required: false,
94
90
  default: true,
95
91
  },
92
+ isLabelVisible: {
93
+ type: Boolean,
94
+ required: false,
95
+ default: true,
96
+ },
96
97
  isLoadingOptions: {
97
98
  type: Boolean,
98
99
  required: false,
@@ -204,6 +205,11 @@ export default {
204
205
  required: false,
205
206
  default: () => [],
206
207
  },
208
+ rowsFooter: {
209
+ type: Array,
210
+ required: false,
211
+ default: () => [],
212
+ },
207
213
  sortingStart: {
208
214
  type: String,
209
215
  required: false,
@@ -358,6 +364,7 @@ export default {
358
364
  provide("previewRightRowIndex", previewRightRowIndex);
359
365
  provide("previewRightRowIndexLast", previewRightRowIndexLast);
360
366
 
367
+ provide("rowsLocal", rowsLocal);
361
368
  provide("modelColumnsVisibleLocal", modelColumnsVisibleLocal);
362
369
  provide("modelColumnsVisibleMapping", modelColumnsVisibleMapping);
363
370
  provide("onUpdateModelFilters", onUpdateModelFilters);
@@ -444,6 +451,10 @@ export default {
444
451
  isDataArray() {
445
452
  return isArray(this.data);
446
453
  },
454
+
455
+ hasRowsFooter() {
456
+ return this.rowsFooter.length > 0;
457
+ },
447
458
  },
448
459
  created() {
449
460
  this.initModelColumnsOrderingLocal();
@@ -556,7 +567,7 @@ export default {
556
567
  areSomeRowsSelected: this.areSomeRowsSelected,
557
568
  closeMultipleActionsActive: this.closeMultipleActionsActive,
558
569
  countAllRows: this.countAllRowsLocal,
559
- hideLabel: this.hideLabel,
570
+ isLabelVisible: this.isLabelVisible,
560
571
  label: this.label,
561
572
  labelTag: this.labelTag,
562
573
  labelClass: this.labelClass,
@@ -600,6 +611,29 @@ export default {
600
611
  ...this.$slots,
601
612
  });
602
613
  })),
614
+ (this.hasRows && this.hasRowsFooter) && h("div", {
615
+ class: "a_table__footer",
616
+ role: "rowgroup",
617
+ }, this.rowsFooter.map((row, rowIndex) => {
618
+ return h(ATableTr, {
619
+ row,
620
+ rowIndex,
621
+ selectedRowsIndexes: this.selectedRowsIndexes,
622
+ onSetSelectedRowsIndexes: this.setSelectedRowsIndexes,
623
+ isFooter: true,
624
+ }, {
625
+ get: vm => [
626
+ h(AGet, {
627
+ data: vm.row,
628
+ path: vm.column.footerPath,
629
+ filter: vm.column.footerFilter,
630
+ filterParameters: vm.column.footerFilterParameters,
631
+ defaultValue: vm.column.footerDefaultValue,
632
+ }),
633
+ ],
634
+ ...this.$slots,
635
+ });
636
+ })),
603
637
  ]),
604
638
  !this.hasRows && h("div", {
605
639
  class: "a_table__empty_text",
@@ -87,6 +87,7 @@ export default {
87
87
  style: `width: 50px; min-width: 50px; max-width: 50px;`,
88
88
  }, [
89
89
  h(AOneCheckbox, {
90
+ isWidthAuto: true,
90
91
  modelValue: this.areAllRowsSelected,
91
92
  indeterminate: this.areSomeRowsSelected && !this.areAllRowsSelected,
92
93
  "onUpdate:modelValue": this.toggleCheckbox,
@@ -8,6 +8,9 @@ import { get } from "lodash-es";
8
8
 
9
9
  export default {
10
10
  name: "ATableListItem",
11
+ inject: [
12
+ "rowsLocal",
13
+ ],
11
14
  props: {
12
15
  column: {
13
16
  type: Object,
@@ -25,13 +28,27 @@ export default {
25
28
  type: Number,
26
29
  required: true,
27
30
  },
31
+ isFooter: {
32
+ type: Boolean,
33
+ required: false,
34
+ },
28
35
  },
29
36
  computed: {
30
37
  isSlot() {
31
- return !!this.column.slot;
38
+ return !!this.slot;
39
+ },
40
+
41
+ slot() {
42
+ if (this.isFooter) {
43
+ return this.column.footerSlot;
44
+ }
45
+ return this.column.slot;
32
46
  },
33
47
 
34
48
  text() {
49
+ if (this.isFooter) {
50
+ return get(this.row, this.column.footerPath);
51
+ }
35
52
  return get(this.row, this.column.path);
36
53
  },
37
54
  },
@@ -45,9 +62,10 @@ export default {
45
62
  this.isSlot ?
46
63
  this.$slots[this.column.slot]({
47
64
  column: this.column,
48
- "column-index": this.columnIndex,
65
+ columnIndex: this.columnIndex,
49
66
  row: this.row,
50
- "row-index": this.rowIndex,
67
+ rowIndex: this.rowIndex,
68
+ rows: this.rowsLocal,
51
69
  }) :
52
70
  h("span", null, [
53
71
  this.text,
@@ -33,12 +33,17 @@ export default {
33
33
  type: Number,
34
34
  required: true,
35
35
  },
36
+ isFooter: {
37
+ type: Boolean,
38
+ required: false,
39
+ },
36
40
  },
37
41
  inject: [
38
42
  "columnsDefaultValue",
39
43
  "hasPreview",
40
44
  "modelColumnsVisibleMapping",
41
45
  "onTogglePreview",
46
+ "rowsLocal",
42
47
  "valuesForColumnDefault",
43
48
  ],
44
49
  setup(props) {
@@ -52,10 +57,16 @@ export default {
52
57
  },
53
58
  computed: {
54
59
  text() {
55
- const TEXT = get(this.row, this.column.path);
60
+ let text;
61
+ if (this.isFooter) {
62
+ text = get(this.row, this.column.footerPath);
63
+ } else {
64
+ text = get(this.row, this.column.path);
65
+ }
66
+
56
67
  let isTextInValuesForColumnDefault = false;
57
68
  forEach(this.valuesForColumnDefault, item => {
58
- if (TEXT === item) {
69
+ if (text === item) {
59
70
  isTextInValuesForColumnDefault = true;
60
71
  return false;
61
72
  }
@@ -63,10 +74,13 @@ export default {
63
74
  if (isTextInValuesForColumnDefault) {
64
75
  return this.defaultValue;
65
76
  }
66
- return TEXT;
77
+ return text;
67
78
  },
68
79
 
69
80
  defaultValue() {
81
+ if (this.isFooter && "footerDefaultValue" in this.column) {
82
+ return this.column.footerDefaultValue;
83
+ }
70
84
  if ("defaultValue" in this.column) {
71
85
  return this.column.defaultValue;
72
86
  }
@@ -77,11 +91,14 @@ export default {
77
91
  },
78
92
 
79
93
  path() {
94
+ if (this.isFooter) {
95
+ return this.column.footerPath;
96
+ }
80
97
  return this.column.path;
81
98
  },
82
99
 
83
100
  isSlot() {
84
- return !!this.column.slot;
101
+ return !!this.slot;
85
102
  },
86
103
 
87
104
  attributesForTd() {
@@ -91,12 +108,12 @@ export default {
91
108
  "a_table__td a_table__cell",
92
109
  this.column.class,
93
110
  {
94
- a_table__cell_click: this.hasPreview,
111
+ a_table__cell_click: this.hasPreview && !this.isFooter,
95
112
  },
96
113
  ],
97
114
  style: this.columnsStyles,
98
115
  };
99
- if (this.hasPreview) {
116
+ if (this.hasPreview && !this.isFooter) {
100
117
  ATTRIBUTES.onClick = () => this.onTogglePreview({
101
118
  row: this.row,
102
119
  rowIndex: this.rowIndex,
@@ -130,28 +147,40 @@ export default {
130
147
  classForLink() {
131
148
  return "a_btn a_btn_link a_p_0";
132
149
  },
150
+
151
+ slot() {
152
+ if (this.isFooter) {
153
+ return this.column.footerSlot;
154
+ }
155
+ return this.column.slot;
156
+ },
133
157
  },
134
158
  render() {
135
- return h("div", this.attributesForTd, this.isSlot ?
136
- this.$slots[this.column.slot]({
137
- column: this.column,
138
- columnIndex: this.columnIndex,
139
- row: this.row,
140
- rowIndex: this.rowIndex,
141
- }) : this.isLink ? [
142
- h(resolveComponent("RouterLink"), {
143
- class: [this.column.class, this.classForLink],
144
- to: this.toLocal,
145
- }, () => [
159
+ return h(
160
+ "div",
161
+ this.attributesForTd,
162
+ (this.isSlot && this.$slots[this.slot]) ?
163
+ this.$slots[this.slot]({
164
+ column: this.column,
165
+ columnIndex: this.columnIndex,
166
+ row: this.row,
167
+ rowIndex: this.rowIndex,
168
+ rows: this.rowsLocal,
169
+ }) : this.isLink ? [
170
+ h(resolveComponent("RouterLink"), {
171
+ class: [this.column.class, this.classForLink],
172
+ to: this.toLocal,
173
+ }, () => [
174
+ h("span", {
175
+ innerHTML: this.text,
176
+ }),
177
+ ]),
178
+ ] :
179
+ [
146
180
  h("span", {
147
181
  innerHTML: this.text,
148
182
  }),
149
- ]),
150
- ] :
151
- [
152
- h("span", {
153
- innerHTML: this.text,
154
- }),
155
- ]);
183
+ ]
184
+ );
156
185
  },
157
186
  };
@@ -26,6 +26,10 @@ export default {
26
26
  type: Number,
27
27
  required: true,
28
28
  },
29
+ isFooter: {
30
+ type: Boolean,
31
+ required: false,
32
+ },
29
33
  },
30
34
  inject: [
31
35
  "columnActionsWidthLocal",
@@ -86,8 +90,6 @@ export default {
86
90
  button: () => [
87
91
  h(AIcon, {
88
92
  icon: "Plus",
89
- width: 14,
90
- height: 14,
91
93
  class: "a_table__cell_action__additional_icon",
92
94
  }),
93
95
  h("span", {
@@ -104,6 +106,7 @@ export default {
104
106
  columnIndex,
105
107
  row: this.row,
106
108
  rowIndex: this.rowIndex,
109
+ isFooter: this.isFooter,
107
110
  }, this.$slots);
108
111
  }),
109
112
  ]),
@@ -21,7 +21,7 @@ export default {
21
21
  type: Number,
22
22
  required: true,
23
23
  },
24
- hideLabel: {
24
+ isLabelVisible: {
25
25
  type: Boolean,
26
26
  required: false,
27
27
  },
@@ -114,7 +114,7 @@ export default {
114
114
  return h("div", {
115
115
  class: "a_table__top_panel",
116
116
  }, [
117
- !this.hideLabel ?
117
+ !this.isLabelVisible ?
118
118
  this.$slots.tableLabel ? this.$slots.tableLabel({
119
119
  countAllRows: this.countAllRows,
120
120
  }) :
@@ -21,6 +21,10 @@ export default {
21
21
  type: Object,
22
22
  required: true,
23
23
  },
24
+ isFooter: {
25
+ type: Boolean,
26
+ required: false,
27
+ },
24
28
  },
25
29
  emits: [
26
30
  "setSelectedRowsIndexes",
@@ -83,7 +87,8 @@ export default {
83
87
  class: "a_table__td a_table__cell a_table__cell_checkbox",
84
88
  style: `width: 50px; min-width: 50px; max-width: 50px;`,
85
89
  }, [
86
- h(AOneCheckbox, {
90
+ !this.isFooter && h(AOneCheckbox, {
91
+ isWidthAuto: true,
87
92
  modelValue: this.isRowSelected,
88
93
  "onUpdate:modelValue": this.toggleCheckbox,
89
94
  }),
@@ -94,11 +99,13 @@ export default {
94
99
  columnIndex,
95
100
  row: this.row,
96
101
  rowIndex: this.rowIndex,
102
+ isFooter: this.isFooter,
97
103
  }, this.$slots);
98
104
  }),
99
105
  this.isActionColumnVisible && h(ATableTdAction, {
100
106
  row: this.row,
101
107
  rowIndex: this.rowIndex,
108
+ isFooter: this.isFooter,
102
109
  }, this.$slots),
103
110
  ]);
104
111
  },
@@ -11,16 +11,16 @@ import {
11
11
  export default function ColumnAdditionalSpaceAPI(props) {
12
12
  const column = toRef(props, "column");
13
13
  const columnsVisibleAdditionalSpaceForOneGrow = inject("columnsVisibleAdditionalSpaceForOneGrow", 0);
14
- const modelIsTableWithoutScroll = inject("modelIsTableWithoutScroll");
14
+ // const modelIsTableWithoutScroll = inject("modelIsTableWithoutScroll");
15
15
 
16
16
  const currentGrow = computed(() => {
17
17
  return isNil(column.value.grow) ? 1 : column.value.grow;
18
18
  });
19
19
 
20
20
  const additionalWidthForCurrentColumn = computed(() => {
21
- if (!modelIsTableWithoutScroll.value) {
22
- return 0;
23
- }
21
+ // if (!modelIsTableWithoutScroll.value) {
22
+ // return 0;
23
+ // }
24
24
  return columnsVisibleAdditionalSpaceForOneGrow.value * currentGrow.value;
25
25
  });
26
26
 
@@ -12,8 +12,10 @@ import {
12
12
  export default function RowActionsAPI(props) {
13
13
  const row = toRef(props, "row");
14
14
  const rowIndex = toRef(props, "rowIndex");
15
+ const isFooter = toRef(props, "isFooter");
15
16
  const rowActions = inject("rowActions");
16
17
 
18
+
17
19
  const isRowActionVisible = ({ rowAction }) => {
18
20
  if (rowAction.isHidden) {
19
21
  return false;
@@ -32,7 +34,7 @@ export default function RowActionsAPI(props) {
32
34
  });
33
35
 
34
36
  const isRowActionsDropdownVisible = computed(() => {
35
- return rowActionsFiltered.value.length > 0;
37
+ return !isFooter.value && rowActionsFiltered.value.length > 0;
36
38
  });
37
39
 
38
40
  return {
@@ -19,9 +19,17 @@ export default function ScrollControlAPI(props, { emit }, {
19
19
  }) {
20
20
  const columnWidthDefault = toRef(props, "columnWidthDefault");
21
21
  const columnActionsWidth = toRef(props, "columnActionsWidth");
22
+ const isActionColumnVisible = toRef(props, "isActionColumnVisible");
23
+
24
+ const columnActionsWidthLocal = computed(() => {
25
+ if (isActionColumnVisible.value) {
26
+ return columnActionsWidth.value;
27
+ }
28
+ return 0;
29
+ });
22
30
  const columnsSpecialWidth = computed(() => {
23
31
  const columnMultipleActionsWidth = isMultipleActionsActive.value ? 50 : 0;
24
- return columnMultipleActionsWidth + columnActionsWidth.value;
32
+ return columnMultipleActionsWidth + columnActionsWidthLocal.value;
25
33
  });
26
34
 
27
35
  const tableWidth = ref(undefined);
@@ -65,9 +73,6 @@ export default function ScrollControlAPI(props, { emit }, {
65
73
  };
66
74
 
67
75
  const checkVisibleColumns = () => {
68
- if (!modelIsTableWithoutScroll.value) {
69
- return;
70
- }
71
76
  const TABLE_WIDTH_WITHOUT_ACTIONS = tableWidth.value - columnsSpecialWidth.value;
72
77
 
73
78
  let columnsWidthInOrder = 0;
@@ -86,21 +91,23 @@ export default function ScrollControlAPI(props, { emit }, {
86
91
  indexFirstScrollInvisibleColumnLocal++;
87
92
  sumGrows += isNil(column.grow) ? 1 : column.grow;
88
93
  });
89
- const FREE_SPACE_WIDTH = TABLE_WIDTH_WITHOUT_ACTIONS - columnsWidthInOrder;
94
+ let freeSpaceWidth = 0;
95
+ if (modelIsTableWithoutScroll.value) {
96
+ freeSpaceWidth = TABLE_WIDTH_WITHOUT_ACTIONS - columnsWidthInOrder;
97
+ } else if (indexFirstScrollInvisibleColumnLocal === columnsOrdered.value.length) {
98
+ freeSpaceWidth = TABLE_WIDTH_WITHOUT_ACTIONS - columnsWidthInOrder;
99
+ }
90
100
  indexFirstScrollInvisibleColumn.value = indexFirstScrollInvisibleColumnLocal;
91
101
 
92
102
  setAdditionalSpaceColumnsForOneGrow({
93
103
  sumGrows,
94
- freeSpaceWidth: FREE_SPACE_WIDTH,
104
+ freeSpaceWidth,
95
105
  });
96
106
  setColumnsScrollInvisible();
97
107
  };
98
108
 
99
109
 
100
110
  const resizeOb = new ResizeObserver(entries => {
101
- if (!modelIsTableWithoutScroll.value) {
102
- return;
103
- }
104
111
  // since we are observing only a single element, so we access the first element in entries array
105
112
  const RECT = entries[0].contentRect;
106
113
 
@@ -17,6 +17,7 @@
17
17
  --a_table_preview_right_border_color: #f1f4f7;
18
18
  --a_table_preview_right_header_bg: #f1f4f7;
19
19
  --a_table_preview_right_header_font_size: 1.5rem;
20
+ --a_table_footer_border_top: 2px solid var(--a_color_gray_800);
20
21
 
21
22
  width: 100%;
22
23
  overflow-x: hidden;
@@ -26,7 +27,7 @@
26
27
  }
27
28
  .a_table {
28
29
  --a_table_bg: transparent;
29
- display: table;
30
+ display: block;
30
31
  width: 100%;
31
32
  caption-side: bottom;
32
33
  border-collapse: collapse;
@@ -70,18 +71,18 @@
70
71
  cursor: pointer;
71
72
  }
72
73
  .a_table__head {
73
- display: table-row-group;
74
- vertical-align: bottom;
74
+ display: flex;
75
+ flex-direction: column;
75
76
  }
76
77
  .a_table__head_dragstart .a_table__th > * {
77
78
  pointer-events: none;
78
79
  }
79
80
  .a_table__row {
80
- display: table-row;
81
+ display: flex;
81
82
  }
82
83
 
83
84
  .a_table__th {
84
- display: table-cell;
85
+ display: block;
85
86
  background-color: var(--a_table_th_bg);
86
87
  border-style: solid;
87
88
  border-width: var(--a_table_th_border_width);
@@ -98,11 +99,17 @@
98
99
  }
99
100
 
100
101
  .a_table__td {
101
- display: table-cell;
102
+ display: block;
103
+ }
104
+
105
+ .a_table__body,
106
+ .a_table__footer {
107
+ display: flex;
108
+ flex-direction: column;
102
109
  }
103
110
 
104
- .a_table__body {
105
- display: table-row-group;
111
+ .a_table__footer {
112
+ border-top: var(--a_table_footer_border_top);
106
113
  }
107
114
 
108
115
  .a_table__th__sort {
@@ -120,7 +120,8 @@ export default {
120
120
  a_custom_control_label_width_auto: this.isWidthAuto,
121
121
  }],
122
122
  }, [
123
- h("span", {
123
+ this.labelLocal && h("span", {
124
+ class: "a_custom_control_label__text",
124
125
  innerHTML: this.labelLocal,
125
126
  }),
126
127
  ]),
@@ -130,7 +130,8 @@ export default {
130
130
  a_custom_control_label_width_auto: this.isWidthAuto,
131
131
  }],
132
132
  }, [
133
- h("span", {
133
+ this.label && h("span", {
134
+ class: "a_custom_control_label__text",
134
135
  innerHTML: this.label,
135
136
  }),
136
137
  ]),
@@ -111,7 +111,8 @@ export default {
111
111
  a_custom_control_label_width_auto: this.isWidthAuto,
112
112
  }],
113
113
  }, [
114
- h("span", {
114
+ this.labelLocal && h("span", {
115
+ class: "a_custom_control_label__text",
115
116
  innerHTML: this.labelLocal,
116
117
  }),
117
118
  ]),