Created
January 28, 2020 11:34
-
-
Save JackBoyle1/014991afc375a85a0c1d60d8b97ecc23 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<template> | |
<div> | |
<b-row class="mt-1 d-flex justify-content-between"> | |
<b-col v-if="isExpandable"> | |
<slot name="tableFilters" /> | |
</b-col> | |
</b-row> | |
<b-row class="mt-1 d-flex justify-content-between"> | |
<b-col v-if="isExpandable" class="mt-2"> | |
<b-button | |
v-if="!allExpanded" | |
variant="link" | |
class="mb-3 expand-all-btn" | |
@click="expandAll" | |
> | |
<chevrons-down-icon /> | |
</b-button> | |
<b-button | |
v-else | |
variant="link" | |
class="expand-all-btn" | |
@click="collapseAll" | |
> | |
<chevrons-up-icon /> | |
</b-button> | |
</b-col> | |
<b-col v-if="isExpandable === false"> | |
<slot name="tableFilters" /> | |
</b-col> | |
<b-col class="text-right mt-3"> | |
<slot name="tableActions" /> | |
<b-button | |
v-if="wantCsvExport" | |
size="sm" | |
variant="outline-secondary" | |
class="mb-3" | |
@click="exportToCsv" | |
> | |
Export to CSV | |
</b-button> | |
</b-col> | |
</b-row> | |
<b-input | |
v-if="enabledFilter" | |
v-model="filter" | |
placeholder="Type to search..." | |
/> | |
<b-table | |
ref="reportTable" | |
class="pb-4 list-table" | |
responsive | |
hover | |
small | |
:sticky-header="stickyHeader" | |
:items="rows" | |
:fields="fields" | |
filter="true" | |
:filter-function="isVisible" | |
:busy="busy" | |
show-empty | |
v-bind="$attrs" | |
v-on="$listeners" | |
> | |
<template #empty> | |
<div class="d-flex justify-content-around mt-5"> | |
No records found | |
</div> | |
</template> | |
<template #emptyfiltered> | |
<div class="d-flex justify-content-around mt-5"> | |
No records found | |
</div> | |
</template> | |
<!-- Pass all slots to b-table --> | |
<slot v-for="(_, name) in $slots" :slot="name" :name="name" /> | |
<template | |
v-for="(_, name) in $scopedSlots" | |
:slot="name" | |
slot-scope="slotData" | |
> | |
<slot :name="name" v-bind="{ ...slotData, ...additionalSlotData }" /> | |
</template> | |
</b-table> | |
<div v-if="busy"> | |
<b-spinner class="table-expand-all"></b-spinner> | |
</div> | |
</div> | |
</template> | |
<script> | |
import rowsToCsvFormat from './list-table/rowsToCsvFormat' | |
import ExpandedRowsQueryMixin from './list-table/expandedRowsQuery' | |
import csvExportAndSave from '@/core/csv/exportAndSave' | |
export default { | |
mixins: [ExpandedRowsQueryMixin], | |
props: { | |
rows: { | |
type: Array, | |
required: true | |
}, | |
busy: { | |
type: Boolean, | |
default: false | |
}, | |
fields: { | |
type: Array, | |
required: true | |
}, | |
keyRowProperty: { | |
type: String, | |
default: 'path' | |
}, | |
parentKeyRowProperty: { | |
type: String, | |
default: 'parentPath' | |
}, | |
finalNodeType: { | |
type: String, | |
default: '' | |
}, | |
forceExpandAll: { | |
type: null, | |
default: 0 | |
}, | |
routeForCallback: { | |
type: Function, | |
default: () => ({}) | |
}, | |
getClassesForRowValueCallback: { | |
type: Function, | |
default: () => [] | |
}, | |
isExpandable: { | |
type: Boolean, | |
default: false | |
}, | |
wantCsvExport: { | |
type: Boolean, | |
default: false | |
}, | |
stickyHeader: { | |
type: String, | |
default: null | |
} | |
}, | |
data() { | |
return { | |
// expandedRows: populated by ExpandedRowsQueryMixin | |
} | |
}, | |
computed: { | |
allExpanded() { | |
return this.rows | |
? this.rows.every(row => | |
this.expandedRows.includes(row[this.keyRowProperty]) | |
) | |
: [] | |
}, | |
csvData() { | |
return rowsToCsvFormat(this.fields, this.rows || []) | |
}, | |
additionalSlotData() { | |
return { | |
routeForCallback: this.routeForCallback, | |
toggleRowExpansionCallback: this.toggleRowExpansion, | |
isExpandedCallback: this.isExpanded, | |
finalNodeType: this.finalNodeType | |
} | |
} | |
}, | |
watch: { | |
rows() { | |
const rows = this.rows.filter(row => | |
this.expandedRows.includes(row[this.keyRowProperty]) | |
) | |
this.$emit('expandRows', rows) | |
this.scrollToRight() | |
}, | |
forceExpandAll() { | |
this.expandAll() | |
} | |
}, | |
methods: { | |
scrollToRight() { | |
if (this.$refs.reportTable) { | |
const el = this.$refs.reportTable.$el | |
el.scrollLeft = el.scrollWidth - el.clientWidth | |
} | |
}, | |
expandAll() { | |
this.expandedRows = this.rows.map(n => n[this.keyRowProperty]) | |
this.$emit('expandAll') | |
}, | |
collapseAll() { | |
this.expandedRows = [] | |
this.$emit('collapseAll') | |
}, | |
isExpanded(row) { | |
return this.expandedRows.includes(row[this.keyRowProperty]) | |
}, | |
isVisible(row) { | |
const parentRow = this.rows.find( | |
r => r[this.keyRowProperty] === row[this.parentKeyRowProperty] | |
) | |
return ( | |
!this.isExpandable || | |
(row.depth || 0) === 0 || | |
(this.isExpanded(parentRow) && this.isVisible(parentRow)) | |
) | |
}, | |
toggleRowExpansion(row) { | |
if (this.isExpanded(row)) { | |
this.expandedRows = this.expandedRows.filter( | |
key => key !== row[this.keyRowProperty] | |
) | |
} else { | |
this.expandedRows = [...this.expandedRows, row[this.keyRowProperty]] | |
this.$emit('expandRows', [row]) | |
} | |
}, | |
async exportToCsv() { | |
if (this.csvData.length < 1) { | |
this.$store.dispatch('errors/add', { | |
source: 'Report to CSV', | |
message: 'No rows selected' | |
}) | |
return [] | |
} | |
this.exporting = true | |
await csvExportAndSave('report.csv', this.csvData) | |
this.exporting = false | |
} | |
} | |
} | |
</script> | |
<style lang="scss" scoped> | |
.expand-all-btn { | |
margin-left: -12px; // Do not use rem as match bootstrap 15px margin | |
} | |
</style> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment