Skip to content

Instantly share code, notes, and snippets.

@JackBoyle1
Created January 28, 2020 11:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JackBoyle1/014991afc375a85a0c1d60d8b97ecc23 to your computer and use it in GitHub Desktop.
Save JackBoyle1/014991afc375a85a0c1d60d8b97ecc23 to your computer and use it in GitHub Desktop.
<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