@itfin/components 1.4.35 → 1.4.40
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/package.json +1 -1
- package/src/components/app/App.vue +3 -6
- package/src/components/checkbox/Checkbox.vue +1 -1
- package/src/components/checkbox/RadioBox.vue +6 -13
- package/src/components/filter/FilterBadge.vue +5 -0
- package/src/components/filter/FilterPanel.vue +54 -16
- package/src/components/icon/components/nomi-arrow-right.vue +4 -0
- package/src/components/icon/components/nomi-cash-repeat.vue +6 -0
- package/src/components/icon/components/nomi-chavron-up.vue +4 -0
- package/src/components/icon/components/nomi-chavron_down.vue +4 -0
- package/src/components/icon/components/nomi-chavron_up.vue +4 -0
- package/src/components/icon/components/nomi-chevron-up.vue +4 -0
- package/src/components/icon/components/nomi-history.vue +7 -0
- package/src/components/icon/components/nomi-pen-alt.vue +4 -0
- package/src/components/panels/PanelItemEdit.vue +6 -8
- package/src/components/panels/PanelList.vue +33 -102
- package/src/components/panels/helpers.ts +11 -29
- package/src/components/table/Table2.vue +65 -61
- package/src/components/table/TableBody.vue +6 -0
- package/src/components/table/TableGroup.vue +14 -4
- package/src/components/table/TableHeader.vue +12 -7
- package/src/components/table/TableRowToggle.vue +9 -1
- package/src/components/table/TableRows.vue +55 -43
- package/src/components/table/table2.scss +15 -25
- package/src/components/view/View.vue +15 -8
|
@@ -1,51 +1,33 @@
|
|
|
1
|
-
import JSON5 from 'json5'
|
|
2
|
-
import {isPathType} from "./index";
|
|
3
|
-
|
|
4
1
|
export interface IPanel {
|
|
5
2
|
type: string;
|
|
6
3
|
payload?: any;
|
|
7
4
|
isCollapsed?: boolean;
|
|
8
5
|
}
|
|
9
6
|
|
|
10
|
-
const COLLAPSE_SYMBOL = '~'
|
|
11
|
-
const PARAMS_SYMBOL = ';'
|
|
12
|
-
|
|
13
7
|
export function stackToHash(stack: IPanel[]) {
|
|
14
8
|
const hash = stack.map(panel => {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
}).join(isPathType() ? '/' : '&');
|
|
19
|
-
return isPathType() ? `/${hash}` : `#${hash}`;
|
|
9
|
+
return `${panel.type}${panel.isCollapsed ? '' : '!'}=${JSON.stringify(panel.payload || {})}`;
|
|
10
|
+
}).join('&');
|
|
11
|
+
return `#${hash}`;
|
|
20
12
|
}
|
|
21
13
|
|
|
22
14
|
|
|
23
15
|
export function hashToStack(hash: string|undefined): IPanel[] {
|
|
24
16
|
let stack:IPanel[] = [];
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
const [type, payload] = item.split(PARAMS_SYMBOL);
|
|
32
|
-
const isCollapsed = type.includes(COLLAPSE_SYMBOL);
|
|
17
|
+
if (hash) {
|
|
18
|
+
const str = hash.replace(/^#/, '');
|
|
19
|
+
|
|
20
|
+
stack = str.split('&').map(item => {
|
|
21
|
+
const [type, payload] = item.split('=');
|
|
22
|
+
const isCollapsed = !type.includes('!');
|
|
33
23
|
let payloadObj:any = {};
|
|
34
24
|
try {
|
|
35
|
-
|
|
36
|
-
if (!json.startsWith('{')) {
|
|
37
|
-
json = `{${json}`; // Ensure it starts with a '{' to be valid JSON
|
|
38
|
-
}
|
|
39
|
-
if (!json.endsWith('}')) {
|
|
40
|
-
json += '}'; // Ensure it ends with a '}' to be valid JSON
|
|
41
|
-
}
|
|
42
|
-
payloadObj = JSON5.parse(json);
|
|
25
|
+
payloadObj = JSON.parse(decodeURIComponent(payload));
|
|
43
26
|
} catch (e) {
|
|
44
27
|
// ignore
|
|
45
|
-
console.warn(`Error parsing payload for type ${type}:`, payload, e);
|
|
46
28
|
}
|
|
47
29
|
return {
|
|
48
|
-
type: type.replace(
|
|
30
|
+
type: type.replace('!', ''),
|
|
49
31
|
isCollapsed,
|
|
50
32
|
payload: payloadObj
|
|
51
33
|
};
|
|
@@ -7,11 +7,9 @@
|
|
|
7
7
|
'permanent-checkboxes': selectedIds.length
|
|
8
8
|
}" :style="{ '--indicator-area-width': `${indicatorType === 'none' ? 1 : indicatorWidth}px`, '--shadow-area-width': `${shadowWidth}px` }">
|
|
9
9
|
<itf-notice-popout :visible="showGroupOperations" class="rounded-3 bg-black text-white">
|
|
10
|
-
<div class="d-flex gap-2 ps-
|
|
11
|
-
<
|
|
12
|
-
|
|
13
|
-
<div class="opacity-50">•</div>
|
|
14
|
-
</slot>
|
|
10
|
+
<div class="d-flex gap-2 ps-3 align-items-center small itf-table2_mass-operations">
|
|
11
|
+
<div>{{$tc('components.table.selectedItems', selectedIds.length, { n: selectedIds.length })}}</div>
|
|
12
|
+
<div class="opacity-50">•</div>
|
|
15
13
|
<a href="" class="me-3 opacity-50 text-white text-decoration-none" @click.stop.prevent="selectedIds = []">{{$t('components.table.cancelSelected')}}</a>
|
|
16
14
|
<div>
|
|
17
15
|
<slot name="group-operations"></slot>
|
|
@@ -19,61 +17,64 @@
|
|
|
19
17
|
</div>
|
|
20
18
|
</itf-notice-popout>
|
|
21
19
|
<div class="scrollable scrollable-x">
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
20
|
+
<itf-checkbox-group v-model="selectedIds">
|
|
21
|
+
<template v-for="(group, index) in groups">
|
|
22
|
+
<div class="table-view-body">
|
|
23
|
+
<itf-table-group
|
|
24
|
+
:key="index"
|
|
25
|
+
@update="$emit('update', { ...$event, group, groupIndex: index })"
|
|
26
|
+
@row-click="$emit('row-click', $event)"
|
|
27
|
+
:id-property="idProperty"
|
|
28
|
+
:columns="columns"
|
|
29
|
+
@update:columns="onColumnsUpdate"
|
|
30
|
+
:rows="group.rows"
|
|
31
|
+
:title="group.name"
|
|
32
|
+
:selected-ids.sync="selectedIds"
|
|
33
|
+
:add-new-rows="addNewRows"
|
|
34
|
+
:shadow-width="shadowWidth"
|
|
35
|
+
:column-sorting="columnSorting"
|
|
36
|
+
:column-resizing="columnResizing"
|
|
37
|
+
:show-grouping="showGrouping"
|
|
38
|
+
:show-summary="showSummary"
|
|
39
|
+
:show-add-column="showAddColumn"
|
|
40
|
+
:show-actions="showActions"
|
|
41
|
+
:show-header="!noHeader"
|
|
42
|
+
:schema="schema"
|
|
43
|
+
:editable="editable"
|
|
44
|
+
:no-column-menu="noColumnMenu"
|
|
45
|
+
:no-select-all="noSelectAll"
|
|
46
|
+
:currencies="currencies"
|
|
47
|
+
:currency="currency"
|
|
48
|
+
:subrows-property="subrowsProperty"
|
|
49
|
+
:async-subrows-property="asyncSubrowsProperty"
|
|
50
|
+
:divider-property="dividerProperty"
|
|
51
|
+
:indicator-type="indicatorType"
|
|
52
|
+
:expanded-all="expandedAll"
|
|
53
|
+
:indicatorWidth="indicatorWidth"
|
|
54
|
+
:striped="striped"
|
|
55
|
+
:expanded-ids="expandedIds"
|
|
56
|
+
:css-property="cssProperty"
|
|
57
|
+
:sticky-header="stickyHeader"
|
|
58
|
+
:editable-property="editableProperty"
|
|
59
|
+
:sorting.sync="_sorting"
|
|
60
|
+
:sort-as-string="sortAsString"
|
|
61
|
+
:active="active"
|
|
62
|
+
@loadChildren="$emit('loadChildren', $event)"
|
|
63
|
+
@update:expanded-ids="$emit('update:expanded-ids', $event)"
|
|
64
|
+
@new="$emit('new', $event)"
|
|
65
|
+
@filter="$emit('filter', $event)"
|
|
66
|
+
@add-column="$emit('add-column', $event)"
|
|
67
|
+
>
|
|
68
|
+
<template v-for="(_, name) in $slots" #[name]="slotData">
|
|
69
|
+
<slot :name="name" v-bind="slotData || {}" />
|
|
70
|
+
</template>
|
|
71
|
+
<template v-for="(_, name) in $scopedSlots" #[name]="slotData">
|
|
72
|
+
<slot :name="name" v-bind="slotData || {}" />
|
|
73
|
+
</template>
|
|
74
|
+
</itf-table-group>
|
|
75
|
+
</div>
|
|
76
|
+
</template>
|
|
77
|
+
</itf-checkbox-group>
|
|
77
78
|
</div>
|
|
78
79
|
</div>
|
|
79
80
|
|
|
@@ -104,11 +105,13 @@ export default @Component({
|
|
|
104
105
|
})
|
|
105
106
|
class itfTable2 extends Vue {
|
|
106
107
|
// @Prop({ required: true, type: Array }) columns;
|
|
108
|
+
@Prop(Boolean) sortAsString;
|
|
107
109
|
@Prop({ required: true, type: Array }) rows;
|
|
108
110
|
@Prop({ type: String, default: null }) groupBy;
|
|
109
111
|
@Prop({ type: String, default: null }) idProperty;
|
|
110
112
|
@Prop({ type: String, default: null }) cssProperty;
|
|
111
113
|
@Prop({ type: String, default: null }) subrowsProperty;
|
|
114
|
+
@Prop({ type: String, default: null }) asyncSubrowsProperty;
|
|
112
115
|
@Prop({ type: String, default: null }) dividerProperty;
|
|
113
116
|
@Prop({ type: String, default: null }) editableProperty;
|
|
114
117
|
@Prop({ default: null }) active;
|
|
@@ -244,7 +247,8 @@ class itfTable2 extends Vue {
|
|
|
244
247
|
@Watch('selectedIds')
|
|
245
248
|
onSelectedIdsUpdate(selectedIds) {
|
|
246
249
|
this.state.selectedIds = selectedIds;
|
|
247
|
-
|
|
250
|
+
// метод saveTableState не зберігає selectedIds в localStorage, не впевнений що він тут треба
|
|
251
|
+
// this.saveTableState();
|
|
248
252
|
}
|
|
249
253
|
|
|
250
254
|
onColumnsUpdate(columns) {
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
:columns="columns"
|
|
8
8
|
:id-property="idProperty"
|
|
9
9
|
:subrows-property="subrowsProperty"
|
|
10
|
+
:async-subrows-property="asyncSubrowsProperty"
|
|
10
11
|
:divider-property="dividerProperty"
|
|
11
12
|
:show-add-column="showAddColumn"
|
|
12
13
|
:show-actions="showActions"
|
|
@@ -144,6 +145,7 @@ class itfTableBody extends Vue {
|
|
|
144
145
|
@Prop() rows;
|
|
145
146
|
@Prop() idProperty;
|
|
146
147
|
@Prop() subrowsProperty;
|
|
148
|
+
@Prop() asyncSubrowsProperty;
|
|
147
149
|
@Prop() dividerProperty;
|
|
148
150
|
@Prop() active;
|
|
149
151
|
@Prop(Boolean) showAddColumn;
|
|
@@ -164,6 +166,10 @@ class itfTableBody extends Vue {
|
|
|
164
166
|
this.$emit('update:expanded-ids', this.expandedIds.includes(item[this.idProperty])
|
|
165
167
|
? this.expandedIds.filter((id) => id !== item[this.idProperty])
|
|
166
168
|
: [...this.expandedIds, item[this.idProperty]]);
|
|
169
|
+
|
|
170
|
+
if (this.asyncSubrowsProperty && item[this.asyncSubrowsProperty] && item[this.asyncSubrowsProperty]) {
|
|
171
|
+
this.$emit('loadChildren', item);
|
|
172
|
+
}
|
|
167
173
|
}
|
|
168
174
|
}
|
|
169
175
|
</script>
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
<div class="shadow-area"></div>
|
|
18
18
|
<div class="header-wrapper" :class="{'header-additional-column': showAddColumn}" @click.prevent="toggleGroup">
|
|
19
19
|
<a class="header-content position-sticky d-flex align-items-center">
|
|
20
|
-
<itf-button
|
|
20
|
+
<itf-button icon small secondary class="collapse-arrow">
|
|
21
21
|
<itf-icon :name="isShowTable ? 'chevron_down' : 'chevron_right'"/>
|
|
22
22
|
</itf-button>
|
|
23
23
|
<span class="d-flex align-items-center line-overflow group-header-value text-primary"
|
|
@@ -39,6 +39,7 @@
|
|
|
39
39
|
:show-add-column="showAddColumn"
|
|
40
40
|
:show-actions="showActions"
|
|
41
41
|
:id-property="idProperty"
|
|
42
|
+
:sort-as-string="sortAsString"
|
|
42
43
|
:rows="rows"
|
|
43
44
|
:schema="schema"
|
|
44
45
|
:editable="editable"
|
|
@@ -61,11 +62,13 @@
|
|
|
61
62
|
@row-click="$emit('row-click', $event)"
|
|
62
63
|
:id-property="idProperty"
|
|
63
64
|
:subrows-property="subrowsProperty"
|
|
65
|
+
:async-subrows-property="asyncSubrowsProperty"
|
|
64
66
|
:divider-property="dividerProperty"
|
|
65
67
|
:rows="rows"
|
|
66
68
|
:editable="editable"
|
|
67
69
|
:currency="currency"
|
|
68
70
|
:currencies="currencies"
|
|
71
|
+
:sort-as-string="sortAsString"
|
|
69
72
|
:columns="visibleColumns"
|
|
70
73
|
:no-select-all="noSelectAll"
|
|
71
74
|
:selected-ids="selectedIds"
|
|
@@ -78,6 +81,7 @@
|
|
|
78
81
|
:css-property="cssProperty"
|
|
79
82
|
:editable-property="editableProperty"
|
|
80
83
|
:active="active"
|
|
84
|
+
@loadChildren="$emit('loadChildren', $event)"
|
|
81
85
|
@update:expanded-ids="$emit('update:expanded-ids', $event)"
|
|
82
86
|
>
|
|
83
87
|
<template v-for="(_, name) in $slots" #[name]="slotData">
|
|
@@ -91,11 +95,11 @@
|
|
|
91
95
|
|
|
92
96
|
<!-- Лінія додати нову -->
|
|
93
97
|
<div v-if="isShowTable && addNewRows"
|
|
94
|
-
class="table-row-template d-flex align-items-stretch">
|
|
98
|
+
class="table-row-template table-row-template__new-row d-flex align-items-stretch">
|
|
95
99
|
<div class="shadow-area"></div>
|
|
96
100
|
<a href="" @click.prevent="$emit('new', title)" data-test="table-add-new-item"
|
|
97
101
|
class="d-flex align-items-center flex-grow-1 table-add-new-item text-decoration-none">
|
|
98
|
-
<span class="d-sticky d-flex align-items-center py-1">
|
|
102
|
+
<span class="d-sticky d-flex align-items-center py-1 px-2 small">
|
|
99
103
|
<itf-icon name="plus"/>
|
|
100
104
|
<span>{{ newLabel }}</span>
|
|
101
105
|
</span>
|
|
@@ -264,7 +268,11 @@
|
|
|
264
268
|
min-height: var(--table-small-row-size);
|
|
265
269
|
}
|
|
266
270
|
|
|
271
|
+
.table-row-template.table-row-template__new-row {
|
|
272
|
+
min-height: 2rem;
|
|
273
|
+
}
|
|
267
274
|
.table-add-new-item {
|
|
275
|
+
background-color: var(--itf-table-header-bg);
|
|
268
276
|
border-right:var(--itf-table-border-base-width) solid var(--itf-table-border-base-color);
|
|
269
277
|
border-left:var(--itf-table-border-base-width) solid var(--itf-table-border-base-color);
|
|
270
278
|
border-bottom: var(--itf-table-border-base-width) solid var(--itf-table-border-base-color);
|
|
@@ -273,7 +281,7 @@
|
|
|
273
281
|
border-bottom-right-radius: var(--itf-table-table-border-radius);
|
|
274
282
|
|
|
275
283
|
& > span {
|
|
276
|
-
left: var(--shadow-area-width);
|
|
284
|
+
left: calc(var(--shadow-area-width) + 4px);
|
|
277
285
|
position: sticky;
|
|
278
286
|
padding-left: var(--shadow-area-width);
|
|
279
287
|
//border-left: var(--itf-table-border-base-width) solid var(--itf-table-border-base-color);
|
|
@@ -359,6 +367,7 @@ class itfTableGroup extends Vue {
|
|
|
359
367
|
@Prop() title;
|
|
360
368
|
@Prop() idProperty;
|
|
361
369
|
@Prop() subrowsProperty;
|
|
370
|
+
@Prop() asyncSubrowsProperty;
|
|
362
371
|
@Prop() dividerProperty;
|
|
363
372
|
@Prop() currency;
|
|
364
373
|
@Prop() currencies;
|
|
@@ -378,6 +387,7 @@ class itfTableGroup extends Vue {
|
|
|
378
387
|
@Prop(Boolean) expandedAll;
|
|
379
388
|
@Prop(Boolean) striped;
|
|
380
389
|
@Prop(Boolean) stickyHeader;
|
|
390
|
+
@Prop(Boolean) sortAsString;
|
|
381
391
|
@Prop() indicatorWidth;
|
|
382
392
|
@Prop() shadowWidth;
|
|
383
393
|
@Prop() cssProperty;
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
<div ref="container" class="table-row-template">
|
|
5
5
|
<div accept-group="items" class="table-view-body-space" v-dropzone="{ payload: 0 }"></div>
|
|
6
6
|
<div class="shadow-area"></div>
|
|
7
|
-
<div class="table-view-header-value reserved sticky">
|
|
8
|
-
<itf-checkbox v-if="indicatorType
|
|
7
|
+
<div v-if="indicatorType !== 'none'" class="table-view-header-value reserved sticky">
|
|
8
|
+
<itf-checkbox v-if="indicatorType !== 'none' && visibleHeader && !noSelectAll" ungrouped value="all" v-model="selectAll" ref="selectAll" />
|
|
9
9
|
</div>
|
|
10
10
|
|
|
11
11
|
<template v-for="(column, n) in visibleAttributes">
|
|
@@ -29,14 +29,16 @@
|
|
|
29
29
|
<div v-if="visibleHeader" group="tablecolumns"
|
|
30
30
|
class="table-header"
|
|
31
31
|
@drop="reorderColumns"
|
|
32
|
-
v-draggable="{ handle: true, payload: { index: n, item: column }, mirror: {yAxis:false} }">
|
|
32
|
+
v-draggable="{ dragHandleClass: null, handle: true, payload: { index: n, item: column }, mirror: {yAxis:false} }">
|
|
33
33
|
<itf-dropdown text append-to-body shadow ref="dropdown" class="w-100" :disabled="noColumnMenu">
|
|
34
34
|
<template #button>
|
|
35
35
|
<div class="itf-table2__header-title d-flex w-100 align-items-center" :title="getTitle(column.title)">
|
|
36
36
|
<itf-icon class="itf-table2__header-icon" new v-if="column.icon" :name="column.icon"></itf-icon>
|
|
37
37
|
<div class="flex-grow-1 w-100 itf-table2__title-container d-flex align-items-center" :class="{'justify-content-end': column.align === 'end'}">
|
|
38
|
-
<div class="itf-table2__title text-truncate">
|
|
39
|
-
|
|
38
|
+
<div class="itf-table2__title text-truncate">
|
|
39
|
+
{{getTitle(column.title)}}
|
|
40
|
+
<div v-if="column.prefix" class="itf-table2__subtitle text-truncate" :class="{'text-end': column.align === 'end'}" v-text="column.prefix" />
|
|
41
|
+
</div>
|
|
40
42
|
</div>
|
|
41
43
|
</div>
|
|
42
44
|
<itf-icon v-if="sortColumnParams[column.property]" :name="sortColumnParams[column.property] === 'asc' ? 'sort-asc' : 'sort-desc'" new :size="20" class="ms-1" />
|
|
@@ -194,6 +196,7 @@ class itfTableHeader extends Vue {
|
|
|
194
196
|
@Prop(Boolean) noColumnMenu;
|
|
195
197
|
@Prop(Boolean) noSelectAll;
|
|
196
198
|
@Prop(Boolean) editable;
|
|
199
|
+
@Prop(Boolean) sortAsString;
|
|
197
200
|
@Prop() idProperty;
|
|
198
201
|
@Prop() indicatorType;
|
|
199
202
|
|
|
@@ -411,8 +414,10 @@ class itfTableHeader extends Vue {
|
|
|
411
414
|
}
|
|
412
415
|
|
|
413
416
|
sortBy(column, order) {
|
|
414
|
-
let sort =
|
|
415
|
-
|
|
417
|
+
let sort = { [column.property]: order };
|
|
418
|
+
if (this.sortAsString) {
|
|
419
|
+
sort = order === 'desc' ? `-${column.property}` : column.property;
|
|
420
|
+
}
|
|
416
421
|
this.$emit('update:sorting', sort);
|
|
417
422
|
}
|
|
418
423
|
}
|
|
@@ -2,7 +2,10 @@
|
|
|
2
2
|
<div>
|
|
3
3
|
<div @click.prevent.stop="toggle" class="d-flex align-items-center flex-nowrap" :class="{'active-toggle': visible}">
|
|
4
4
|
<div class="item-toggle text-muted">
|
|
5
|
-
<template v-if="visible &&
|
|
5
|
+
<template v-if="visible && loading">
|
|
6
|
+
<div class="itf-spinner"></div>
|
|
7
|
+
</template>
|
|
8
|
+
<template v-else-if="visible && expanded">
|
|
6
9
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
|
7
10
|
width="16" height="16" viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
|
|
8
11
|
<path d="M184.7,413.1l2.1-1.8l156.5-136c5.3-4.6,8.6-11.5,8.6-19.2c0-7.7-3.4-14.6-8.6-19.2L187.1,101l-2.6-2.3
|
|
@@ -23,6 +26,10 @@
|
|
|
23
26
|
</div>
|
|
24
27
|
</template>
|
|
25
28
|
<style lang="scss" scoped>
|
|
29
|
+
.itf-spinner {
|
|
30
|
+
width: 1rem;
|
|
31
|
+
height: 1rem;
|
|
32
|
+
}
|
|
26
33
|
.active-toggle {
|
|
27
34
|
cursor: pointer;
|
|
28
35
|
}
|
|
@@ -43,6 +50,7 @@ export default @Component({
|
|
|
43
50
|
class itfTableRowToggle extends Vue {
|
|
44
51
|
@Prop(Boolean) expanded;
|
|
45
52
|
@Prop(Boolean) visible;
|
|
53
|
+
@Prop(Boolean) loading;
|
|
46
54
|
|
|
47
55
|
toggle() {
|
|
48
56
|
this.$emit('toggle');
|
|
@@ -25,6 +25,22 @@
|
|
|
25
25
|
<span v-if="indicatorType === 'order'">{{ (n + 1) }}</span>
|
|
26
26
|
<span v-else-if="indicatorType === 'property'">{{ item[idProperty] }}</span>
|
|
27
27
|
<span v-else-if="indicatorType === 'checkbox'"><itf-checkbox :value="item[idProperty]" /></span>
|
|
28
|
+
<a href="" @click.prevent.stop="$emit('toggle', item)" v-else-if="indicatorType === 'toggle'">
|
|
29
|
+
<template v-if="subrowsProperty && item[subrowsProperty] && item[subrowsProperty].length">
|
|
30
|
+
<template v-if="item[subrowsProperty] && item[subrowsProperty].length && !isExpanded(item)">
|
|
31
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-plus-square" viewBox="0 0 16 16">
|
|
32
|
+
<path d="M14 1a1 1 0 0 1 1 1v12a1 1 0 0 1-1 1H2a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1zM2 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2z"/>
|
|
33
|
+
<path d="M8 4a.5.5 0 0 1 .5.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3A.5.5 0 0 1 8 4"/>
|
|
34
|
+
</svg>
|
|
35
|
+
</template>
|
|
36
|
+
<template v-else>
|
|
37
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-dash-square" viewBox="0 0 16 16">
|
|
38
|
+
<path d="M14 1a1 1 0 0 1 1 1v12a1 1 0 0 1-1 1H2a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1zM2 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2z"/>
|
|
39
|
+
<path d="M4 8a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7A.5.5 0 0 1 4 8"/>
|
|
40
|
+
</svg>
|
|
41
|
+
</template>
|
|
42
|
+
</template>
|
|
43
|
+
</a>
|
|
28
44
|
</div>
|
|
29
45
|
</div>
|
|
30
46
|
<div accept-group="items" class="table-item-inner" @click="$emit('row-click', item)">
|
|
@@ -33,37 +49,37 @@
|
|
|
33
49
|
v-if="column.visible !== false"
|
|
34
50
|
:data-column="k"
|
|
35
51
|
:style="`width: ${column.width}px; max-width: ${column.width}px; left: ${column.left}px;`"
|
|
36
|
-
:class="{'
|
|
52
|
+
:class="{'sticky': column.pinned, 'last-sticky-column': k === lastPinnedIndex, 'editable': column.editable && editable}"
|
|
37
53
|
class="table-view-item-value d-flex h-100">
|
|
38
|
-
<div class="table-view-item-value-content" :class="{'px-2': !(column.editable && editable)}">
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
54
|
+
<div class="table-view-item-value-content align-items-center" :class="{'justify-content-end': column.align === 'end', 'px-2': !(column.editable && editable)}">
|
|
55
|
+
<slot
|
|
56
|
+
:name="`column.${column.property}`"
|
|
57
|
+
:toggle="() => $emit('toggle', item)"
|
|
58
|
+
:hasSubitems="hasSubitems(item)"
|
|
59
|
+
:isExpanded="!!(hasSubitems(item) && !isExpanded(item))"
|
|
60
|
+
:level="level" :editable="column.editable && editable" :item="item" :column="column" :update="(val) => updateValue(item, val, n, column)" :value="getValue(item, column)">
|
|
61
|
+
<template v-if="column.editable && editable && (!editableProperty || item[editableProperty])">
|
|
62
|
+
<slot :name="`edit.${column.type}`" :level="level" :toggle="() => $emit('toggle', item)" :update="(val) => updateValue(item, val, n, column)" :value="getValue(item, column)" :item="item" :column="column">
|
|
63
|
+
<itf-text-field class="w-100 h-100" v-if="column.type === 'text'" :value="getValue(item, column)" @input="updateValue(item, $event, n, column)" />
|
|
64
|
+
<itf-text-field class="w-100 h-100" v-if="column.type === 'number'" type="number" :value="getValue(item, column)" @input="updateValue(item, $event, n, column)" />
|
|
65
|
+
<itf-hours-field
|
|
66
|
+
class="w-100 h-100"
|
|
67
|
+
placeholder="00h 00m"
|
|
68
|
+
v-else-if="column.type === 'time'"
|
|
69
|
+
:hours="getValue(item, column)"
|
|
70
|
+
@update:hours="updateValue(item, $event, n, column)"
|
|
71
|
+
/>
|
|
72
|
+
<itf-textarea class="w-100 h-100" :rows="1" autogrow v-else-if="column.type === 'textarea'" :value="getValue(item, column)" @input="updateValue(item, $event, n, column)" />
|
|
73
|
+
<itf-money-field class="w-100 h-100" currency-disabled :currency="currency" :currencies="currencies" v-else-if="column.type === 'money'" :value="getValue(item, column)" @input="updateValue(item, $event, n, column)" />
|
|
74
|
+
<itf-select class="w-100 h-100" v-else-if="column.type === 'select'" :reduce="(item) => item.value" :value="getValue(item, column)" @input="updateValue(item, $event, n, column)" :options="column.options"></itf-select>
|
|
75
|
+
</slot>
|
|
76
|
+
</template>
|
|
77
|
+
<span v-else class="text-truncate">
|
|
78
|
+
<slot :name="`format.${column.type}`" :toggle="() => $emit('toggle', item)" :level="level" :value="getValue(item, column)" :update="(value) => updateValue(item, value, n, column)" :item="item" :column="column">
|
|
79
|
+
{{getValue(item, column)}}
|
|
80
|
+
</slot>
|
|
81
|
+
</span>
|
|
82
|
+
</slot>
|
|
67
83
|
</div>
|
|
68
84
|
</div>
|
|
69
85
|
</template>
|
|
@@ -86,6 +102,7 @@
|
|
|
86
102
|
:columns="columns"
|
|
87
103
|
:id-property="idProperty"
|
|
88
104
|
:subrows-property="subrowsProperty"
|
|
105
|
+
:async-subrows-property="asyncSubrowsProperty"
|
|
89
106
|
:show-add-column="showAddColumn"
|
|
90
107
|
:show-actions="showActions"
|
|
91
108
|
:no-select-all="noSelectAll"
|
|
@@ -145,6 +162,7 @@ class itfTableRows extends Vue {
|
|
|
145
162
|
@Prop() rows;
|
|
146
163
|
@Prop() idProperty;
|
|
147
164
|
@Prop() subrowsProperty;
|
|
165
|
+
@Prop() asyncSubrowsProperty;
|
|
148
166
|
@Prop() dividerProperty;
|
|
149
167
|
@Prop() active;
|
|
150
168
|
@Prop(Boolean) showAddColumn;
|
|
@@ -174,6 +192,12 @@ class itfTableRows extends Vue {
|
|
|
174
192
|
return this.columns.findIndex((column) => column.lastPinned);
|
|
175
193
|
}
|
|
176
194
|
|
|
195
|
+
hasSubitems(item) {
|
|
196
|
+
const hasFactItems = this.subrowsProperty && item[this.subrowsProperty] && item[this.subrowsProperty].length;
|
|
197
|
+
const hasPlanItems = this.asyncSubrowsProperty && item[this.asyncSubrowsProperty] && item[this.asyncSubrowsProperty];
|
|
198
|
+
return !!(hasFactItems || hasPlanItems);
|
|
199
|
+
}
|
|
200
|
+
|
|
177
201
|
updateValue(item, value, index, column) {
|
|
178
202
|
const newItem = { ...item };
|
|
179
203
|
if (newItem[column.property] !== value) {
|
|
@@ -188,20 +212,8 @@ class itfTableRows extends Vue {
|
|
|
188
212
|
}
|
|
189
213
|
}
|
|
190
214
|
|
|
191
|
-
updateValues(item, values, index, column) {
|
|
192
|
-
const newItem = { ...item };
|
|
193
|
-
Object.assign(newItem, values);
|
|
194
|
-
this.$emit('update', {
|
|
195
|
-
index,
|
|
196
|
-
item,
|
|
197
|
-
inputValue: values,
|
|
198
|
-
value: newItem,
|
|
199
|
-
column
|
|
200
|
-
});
|
|
201
|
-
}
|
|
202
|
-
|
|
203
215
|
isActive(id) {
|
|
204
|
-
if (!this.idProperty) {
|
|
216
|
+
if (!this.idProperty || !this.active) {
|
|
205
217
|
return false;
|
|
206
218
|
}
|
|
207
219
|
if (Array.isArray(this.active)) {
|