From 50a7149a934e22fd1216f4359faea083dd7f8e09 Mon Sep 17 00:00:00 2001
From: zachend
Date: Mon, 17 Feb 2025 18:37:41 -0500
Subject: [PATCH 1/6] ZE-0 add resizing for QTable Columns
---
ui/src/components/table/QTable.js | 58 +++++++++++++++++++++++++++++
ui/src/components/table/QTable.sass | 11 ++++++
2 files changed, 69 insertions(+)
diff --git a/ui/src/components/table/QTable.js b/ui/src/components/table/QTable.js
index c7e3601ca4e..733c3d4e7fc 100644
--- a/ui/src/components/table/QTable.js
+++ b/ui/src/components/table/QTable.js
@@ -43,6 +43,11 @@ export default createComponent({
type: [ String, Function ],
default: 'id'
},
+ resizableCols: {
+ type: Boolean,
+ default: false
+ },
+
columns: Array,
loading: Boolean,
@@ -116,6 +121,59 @@ export default createComponent({
...useTableSortProps
},
+
+ data() {
+ return {
+ colWidths: {},
+ resizingCol: null,
+ startX: 0
+ }
+ },
+ mounted() {
+ // Initialize widths for each column
+ this.computedCols.forEach(col => {
+ this.$set(this.colWidths, col.name, 150)
+ })
+ },
+ methods: {
+ startResizing(colName, evt) {
+ this.resizingCol = colName
+ this.startX = evt.pageX
+ document.addEventListener('mousemove', this.handleResize)
+ document.addEventListener('mouseup', this.stopResizing)
+ },
+ handleResize(evt) {
+ if (!this.resizingCol) return
+ const diff = evt.pageX - this.startX
+ this.colWidths[this.resizingCol] += diff
+ this.startX = evt.pageX
+ },
+ stopResizing() {
+ document.removeEventListener('mousemove', this.handleResize)
+ document.removeEventListener('mouseup', this.stopResizing)
+ this.resizingCol = null
+ },
+ renderHeaderCell(h, col) {
+ const hasHandle = this.resizableCols
+ const handle = hasHandle
+ ? h('span', {
+ class: 'q-table__resize-handle',
+ onMousedown: evt => this.startResizing(col.name, evt)
+ })
+ : null
+
+ return h('th', {
+ style: { width: this.colWidths[col.name] + 'px' }
+ }, [
+ col.label,
+ handle
+ ])
+ }
+ },
+
+
+
+
emits: [
'request', 'virtualScroll',
...useFullscreenEmits,
diff --git a/ui/src/components/table/QTable.sass b/ui/src/components/table/QTable.sass
index e82234d61aa..4ccf7ad69bc 100644
--- a/ui/src/components/table/QTable.sass
+++ b/ui/src/components/table/QTable.sass
@@ -291,3 +291,14 @@ body.desktop .q-table > tbody > tr:not(.q-tr--no-hover):hover > td:not(.q-td--no
&.q-table--vertical-separator, &.q-table--cell-separator
.q-table__top
border-color: $table-dark-border-color
+
+
+
+.q-table th .q-table__resize-handle {
+ cursor: col-resize;
+ display: inline-block;
+ width: 6px;
+ height: 100%;
+ background-color: #ccc;
+ margin-left: 4px;
+}
From 5c3ecb32d383c796142e9df7cbb96b57ae7367d1 Mon Sep 17 00:00:00 2001
From: zachend
Date: Tue, 25 Feb 2025 08:17:01 -0500
Subject: [PATCH 2/6] address required fixes
---
ui/src/components/table/QTable.js | 92 ++++++++++++-----------------
ui/src/components/table/QTable.sass | 12 ++--
2 files changed, 44 insertions(+), 60 deletions(-)
diff --git a/ui/src/components/table/QTable.js b/ui/src/components/table/QTable.js
index 733c3d4e7fc..e50717a6173 100644
--- a/ui/src/components/table/QTable.js
+++ b/ui/src/components/table/QTable.js
@@ -1,4 +1,4 @@
-import { h, ref, computed, watch, getCurrentInstance } from 'vue'
+import { h, ref, computed, watch, getCurrentInstance, onMounted, reactive } from 'vue'
import QTh from './QTh.js'
@@ -43,15 +43,12 @@ export default createComponent({
type: [ String, Function ],
default: 'id'
},
- resizableCols: {
- type: Boolean,
- default: false
- },
-
columns: Array,
loading: Boolean,
+ resizableCols: Boolean,
+
iconFirstPage: String,
iconPrevPage: String,
iconNextPage: String,
@@ -121,58 +118,44 @@ export default createComponent({
...useTableSortProps
},
+ const vm = getCurrentInstance()
+ const colWidths = reactive({})
+ const resizingCol = ref(null)
+ const startX = ref(0)
- data() {
- return {
- colWidths: {},
- resizingCol: null,
- startX: 0
- }
- },
- mounted() {
- // Initialize widths for each column
- this.computedCols.forEach(col => {
- this.$set(this.colWidths, col.name, 150)
- })
- },
- methods: {
- startResizing(colName, evt) {
- this.resizingCol = colName
- this.startX = evt.pageX
- document.addEventListener('mousemove', this.handleResize)
- document.addEventListener('mouseup', this.stopResizing)
- },
- handleResize(evt) {
- if (!this.resizingCol) return
- const diff = evt.pageX - this.startX
- this.colWidths[this.resizingCol] += diff
- this.startX = evt.pageX
- },
- stopResizing() {
- document.removeEventListener('mousemove', this.handleResize)
- document.removeEventListener('mouseup', this.stopResizing)
- this.resizingCol = null
- },
- renderHeaderCell(h, col) {
- const hasHandle = this.resizableCols
- const handle = hasHandle
- ? h('span', {
- class: 'q-table__resize-handle',
- onMousedown: evt => this.startResizing(col.name, evt)
- })
- : null
-
- return h('th', {
- style: { width: this.colWidths[col.name] + 'px' }
- }, [
- col.label,
- handle
- ])
- }
- },
+ onMounted(() => {
+ vm.proxy.computedCols.forEach(col => {
+ colWidths[col.name] = 150
+ })
+ })
+
+ function startResizing(colName, evt) {
+ resizingCol.value = colName
+ startX.value = evt.pageX
+ document.addEventListener('mousemove', handleResize)
+ document.addEventListener('mouseup', stopResizing)
+ }
+ function handleResize(evt) {
+ if (!resizingCol.value) return
+ const diff = evt.pageX - startX.value
+ colWidths[resizingCol.value] += diff
+ startX.value = evt.pageX
+ }
+ function stopResizing() {
+ document.removeEventListener('mousemove', handleResize)
+ document.removeEventListener('mouseup', stopResizing)
+ resizingCol.value = null
+ }
+ return {
+ colWidths,
+ startResizing,
+ handleResize,
+ stopResizing
+ }
+ },
emits: [
'request', 'virtualScroll',
@@ -185,6 +168,7 @@ export default createComponent({
const vm = getCurrentInstance()
const { proxy: { $q } } = vm
+
const isDark = useDark(props, $q)
const { inFullscreen, toggleFullscreen } = useFullscreen()
diff --git a/ui/src/components/table/QTable.sass b/ui/src/components/table/QTable.sass
index 4ccf7ad69bc..d196ff535a1 100644
--- a/ui/src/components/table/QTable.sass
+++ b/ui/src/components/table/QTable.sass
@@ -295,10 +295,10 @@ body.desktop .q-table > tbody > tr:not(.q-tr--no-hover):hover > td:not(.q-td--no
.q-table th .q-table__resize-handle {
- cursor: col-resize;
- display: inline-block;
- width: 6px;
- height: 100%;
- background-color: #ccc;
- margin-left: 4px;
+ cursor: col-resize
+ display: inline-block
+ width: 6px
+ height: 100%
+ background-color: #ccc
+ margin-left: 4px
}
From 78d6a65c4de6d76c88221fb339f87709a8d6f3a2 Mon Sep 17 00:00:00 2001
From: zachend
Date: Thu, 27 Feb 2025 16:23:07 -0500
Subject: [PATCH 3/6] minor improvments
---
ui/src/components/table/QTable.js | 112 +++++++++++++++-------------
ui/src/components/table/QTable.sass | 4 +-
2 files changed, 64 insertions(+), 52 deletions(-)
diff --git a/ui/src/components/table/QTable.js b/ui/src/components/table/QTable.js
index e50717a6173..b8b2b75d81e 100644
--- a/ui/src/components/table/QTable.js
+++ b/ui/src/components/table/QTable.js
@@ -43,11 +43,11 @@ export default createComponent({
type: [ String, Function ],
default: 'id'
},
-
+ resizableCols: Boolean,
columns: Array,
loading: Boolean,
- resizableCols: Boolean,
+
iconFirstPage: String,
iconPrevPage: String,
@@ -118,44 +118,7 @@ export default createComponent({
...useTableSortProps
},
- const vm = getCurrentInstance()
- const colWidths = reactive({})
- const resizingCol = ref(null)
- const startX = ref(0)
-
- onMounted(() => {
- vm.proxy.computedCols.forEach(col => {
- colWidths[col.name] = 150
- })
- })
- function startResizing(colName, evt) {
- resizingCol.value = colName
- startX.value = evt.pageX
- document.addEventListener('mousemove', handleResize)
- document.addEventListener('mouseup', stopResizing)
- }
-
- function handleResize(evt) {
- if (!resizingCol.value) return
- const diff = evt.pageX - startX.value
- colWidths[resizingCol.value] += diff
- startX.value = evt.pageX
- }
-
- function stopResizing() {
- document.removeEventListener('mousemove', handleResize)
- document.removeEventListener('mouseup', stopResizing)
- resizingCol.value = null
- }
-
- return {
- colWidths,
- startResizing,
- handleResize,
- stopResizing
- }
- },
emits: [
'request', 'virtualScroll',
@@ -169,6 +132,47 @@ export default createComponent({
const { proxy: { $q } } = vm
+ const colWidths = reactive({})
+ const resizingCol = ref(null)
+ const startX = ref(0)
+
+ onMounted(() => {
+ props.columns.forEach(col => {
+ colWidths[col.name] = 150
+ })
+ })
+
+ function startResizing(colName, evt) {
+ resizingCol.value = colName
+ startX.value = evt.pageX
+ document.addEventListener('mousemove', handleResize)
+ document.addEventListener('mouseup', stopResizing)
+ }
+
+ function handleResize(evt) {
+ if (!resizingCol.value) return
+ const diff = evt.pageX - startX.value
+ colWidths[resizingCol.value] += diff
+ startX.value = evt.pageX
+ }
+
+ function stopResizing() {
+ document.removeEventListener('mousemove', handleResize);
+ document.removeEventListener('mouseup', stopResizing);
+ resizingCol.value = null;
+ }
+
+ return {
+ colWidths,
+ startResizing,
+ handleResize,
+ stopResizing,
+ };
+
+
+
+
+
const isDark = useDark(props, $q)
const { inFullscreen, toggleFullscreen } = useFullscreen()
@@ -681,12 +685,18 @@ export default createComponent({
props = getHeaderScope({ col })
return slot !== void 0
- ? slot(props)
- : h(QTh, {
- key: col.name,
- props
- }, () => col.label)
- })
+ ? slot(props)
+ : h(QTh, {
+ key: col.name,
+ props
+ }, () => [
+ col.label,
+ props.resizableCols ? h('div', {
+ class: 'q-table__resize-handle',
+ onMousedown: evt => startResizing(col.name, evt)
+ }) : null
+ ])
+ })
if (singleSelection.value === true && props.grid !== true) {
child.unshift(
@@ -713,12 +723,12 @@ export default createComponent({
}
return [
- h('tr', {
- class: props.tableHeaderClass,
- style: props.tableHeaderStyle
- }, child)
- ]
- }
+ h('tr', {
+ class: props.tableHeaderClass,
+ style: props.tableHeaderStyle
+ }, child)
+ ]
+ }
function getHeaderScope (data) {
Object.assign(data, {
diff --git a/ui/src/components/table/QTable.sass b/ui/src/components/table/QTable.sass
index d196ff535a1..eed9f99353d 100644
--- a/ui/src/components/table/QTable.sass
+++ b/ui/src/components/table/QTable.sass
@@ -300,5 +300,7 @@ body.desktop .q-table > tbody > tr:not(.q-tr--no-hover):hover > td:not(.q-td--no
width: 6px
height: 100%
background-color: #ccc
- margin-left: 4px
+ position: absolute
+ right: 0
+ top: 0
}
From d2ca3a5029031c1d7c51284a166c6a8d4399ba56 Mon Sep 17 00:00:00 2001
From: zachend
Date: Thu, 27 Feb 2025 16:44:27 -0500
Subject: [PATCH 4/6] - use column definitions to determine if a column is
resizable or not
- double clicking resizer brings column back to their default size
---
ui/src/components/table/QTable.js | 171 +++++++++++++++---------------
1 file changed, 84 insertions(+), 87 deletions(-)
diff --git a/ui/src/components/table/QTable.js b/ui/src/components/table/QTable.js
index b8b2b75d81e..28d784c4808 100644
--- a/ui/src/components/table/QTable.js
+++ b/ui/src/components/table/QTable.js
@@ -142,36 +142,36 @@ export default createComponent({
})
})
- function startResizing(colName, evt) {
- resizingCol.value = colName
- startX.value = evt.pageX
- document.addEventListener('mousemove', handleResize)
- document.addEventListener('mouseup', stopResizing)
- }
-
- function handleResize(evt) {
- if (!resizingCol.value) return
- const diff = evt.pageX - startX.value
- colWidths[resizingCol.value] += diff
- startX.value = evt.pageX
- }
+ function resetColumnWidth(colName) {
+ colWidths[colName] = 150; // Reset to default width or any desired full size
+ }
- function stopResizing() {
- document.removeEventListener('mousemove', handleResize);
- document.removeEventListener('mouseup', stopResizing);
- resizingCol.value = null;
+ function startResizing(colName, evt) {
+ resizingCol.value = colName
+ startX.value = evt.pageX
+ document.addEventListener('mousemove', handleResize)
+ document.addEventListener('mouseup', stopResizing)
}
- return {
- colWidths,
- startResizing,
- handleResize,
- stopResizing,
- };
-
-
+ function handleResize(evt) {
+ if (!resizingCol.value) return
+ const diff = evt.pageX - startX.value
+ colWidths[resizingCol.value] += diff
+ startX.value = evt.pageX
+ }
+ function stopResizing() {
+ document.removeEventListener('mousemove', handleResize);
+ document.removeEventListener('mouseup', stopResizing);
+ resizingCol.value = null;
+ }
+ return {
+ colWidths,
+ startResizing,
+ handleResize,
+ stopResizing,
+ };
const isDark = useDark(props, $q)
const { inFullscreen, toggleFullscreen } = useFullscreen()
@@ -667,68 +667,65 @@ export default createComponent({
return h('thead', child)
}
- function getTHeadTR () {
- const
- header = slots.header,
- headerCell = slots[ 'header-cell' ]
-
- if (header !== void 0) {
- return header(
- getHeaderScope({ header: true })
- ).slice()
- }
-
- const child = computedCols.value.map(col => {
- const
- headerCellCol = slots[ `header-cell-${ col.name }` ],
- slot = headerCellCol !== void 0 ? headerCellCol : headerCell,
- props = getHeaderScope({ col })
-
- return slot !== void 0
- ? slot(props)
- : h(QTh, {
- key: col.name,
- props
- }, () => [
- col.label,
- props.resizableCols ? h('div', {
- class: 'q-table__resize-handle',
- onMousedown: evt => startResizing(col.name, evt)
- }) : null
- ])
- })
-
- if (singleSelection.value === true && props.grid !== true) {
- child.unshift(
- h('th', { class: 'q-table--col-auto-width' }, ' ')
- )
- }
- else if (multipleSelection.value === true) {
- const slot = slots[ 'header-selection' ]
- const content = slot !== void 0
- ? slot(getHeaderScope({}))
- : [
- h(QCheckbox, {
- color: props.color,
- modelValue: headerSelectedValue.value,
- dark: isDark.value,
- dense: props.dense,
- 'onUpdate:modelValue': onMultipleSelectionSet
- })
- ]
-
- child.unshift(
- h('th', { class: 'q-table--col-auto-width' }, content)
- )
- }
-
- return [
- h('tr', {
- class: props.tableHeaderClass,
- style: props.tableHeaderStyle
- }, child)
- ]
- }
+ function getTHeadTR() {
+ const header = slots.header;
+ const headerCell = slots['header-cell'];
+
+ if (header !== void 0) {
+ return header(
+ getHeaderScope({ header: true })
+ ).slice();
+ }
+
+ const child = computedCols.value.map(col => {
+ const headerCellCol = slots[`header-cell-${col.name}`];
+ const slot = headerCellCol !== void 0 ? headerCellCol : headerCell;
+ const props = getHeaderScope({ col });
+
+ return slot !== void 0
+ ? slot(props)
+ : h(QTh, {
+ key: col.name,
+ props
+ }, () => [
+ col.label,
+ col.resizable ? h('div', {
+ class: 'q-table__resize-handle',
+ onMousedown: evt => startResizing(col.name, evt)
+ }) : null
+ ]);
+ });
+
+ if (singleSelection.value === true && props.grid !== true) {
+ child.unshift(
+ h('th', { class: 'q-table--col-auto-width' }, ' ')
+ );
+ } else if (multipleSelection.value === true) {
+ const slot = slots['header-selection'];
+ const content = slot !== void 0
+ ? slot(getHeaderScope({}))
+ : [
+ h(QCheckbox, {
+ color: props.color,
+ modelValue: headerSelectedValue.value,
+ dark: isDark.value,
+ dense: props.dense,
+ 'onUpdate:modelValue': onMultipleSelectionSet
+ })
+ ];
+
+ child.unshift(
+ h('th', { class: 'q-table--col-auto-width' }, content)
+ );
+ }
+
+ return [
+ h('tr', {
+ class: props.tableHeaderClass,
+ style: props.tableHeaderStyle
+ }, child)
+ ];
+ }
function getHeaderScope (data) {
Object.assign(data, {
From 18ddcea529233765bfacf967c29d52cf13a78be4 Mon Sep 17 00:00:00 2001
From: zachend
Date: Thu, 27 Feb 2025 18:23:39 -0500
Subject: [PATCH 5/6] -cleaned up code to match rest of project -documented new
feature in QTable.json
---
ui/src/components/table/QTable.js | 56 ++++++++++++++---------------
ui/src/components/table/QTable.json | 6 +++-
2 files changed, 32 insertions(+), 30 deletions(-)
diff --git a/ui/src/components/table/QTable.js b/ui/src/components/table/QTable.js
index 28d784c4808..8f40d441745 100644
--- a/ui/src/components/table/QTable.js
+++ b/ui/src/components/table/QTable.js
@@ -118,8 +118,6 @@ export default createComponent({
...useTableSortProps
},
-
-
emits: [
'request', 'virtualScroll',
...useFullscreenEmits,
@@ -131,7 +129,6 @@ export default createComponent({
const vm = getCurrentInstance()
const { proxy: { $q } } = vm
-
const colWidths = reactive({})
const resizingCol = ref(null)
const startX = ref(0)
@@ -142,36 +139,37 @@ export default createComponent({
})
})
- function resetColumnWidth(colName) {
- colWidths[colName] = 150; // Reset to default width or any desired full size
- }
+ function resetColumnWidth (colName) {
+ colWidths[colName] = 150 // Reset to default width or any desired full size
+ }
- function startResizing(colName, evt) {
- resizingCol.value = colName
- startX.value = evt.pageX
- document.addEventListener('mousemove', handleResize)
- document.addEventListener('mouseup', stopResizing)
- }
+ function startResizing (colName, evt) {
+ resizingCol.value = colName
+ startX.value = evt.pageX
+ document.addEventListener('mousemove', handleResize)
+ document.addEventListener('mouseup', stopResizing)
+ }
- function handleResize(evt) {
- if (!resizingCol.value) return
- const diff = evt.pageX - startX.value
- colWidths[resizingCol.value] += diff
- startX.value = evt.pageX
- }
+ function handleResize (evt) {
+ if (!resizingCol.value) return
+ const diff = evt.pageX - startX.value
+ colWidths[resizingCol.value] += diff
+ startX.value = evt.pageX
+ }
- function stopResizing() {
- document.removeEventListener('mousemove', handleResize);
- document.removeEventListener('mouseup', stopResizing);
- resizingCol.value = null;
- }
+ function stopResizing () {
+ document.removeEventListener('mousemove', handleResize)
+ document.removeEventListener('mouseup', stopResizing)
+ resizingCol.value = null
+ }
- return {
- colWidths,
- startResizing,
- handleResize,
- stopResizing,
- };
+ return {
+ colWidths,
+ resetColumnWidth,
+ startResizing,
+ handleResize,
+ stopResizing,
+ };
const isDark = useDark(props, $q)
const { inFullscreen, toggleFullscreen } = useFullscreen()
diff --git a/ui/src/components/table/QTable.json b/ui/src/components/table/QTable.json
index 6e3e6029c4f..b230aaf1dd2 100644
--- a/ui/src/components/table/QTable.json
+++ b/ui/src/components/table/QTable.json
@@ -13,7 +13,11 @@
"examples": [ "# :rows=\"myData\"" ],
"category": "general"
},
-
+ "resizable-cols": {
+ "type": "Boolean",
+ "desc": "Enable column resizing functionality",
+ "category": "behavior"
+ },
"row-key": {
"type": [ "String", "Function" ],
"desc": "Property of each row that defines the unique key of each row (the result must be a primitive, not Object, Array, etc); The value of property must be string or a function taking a row and returning the desired (nested) key in the row; If supplying a function then for best performance, reference it from your scope and do not define it inline",
From 5ec286e8900e139ed651b2184c0f3fee5c275085 Mon Sep 17 00:00:00 2001
From: zachend
Date: Thu, 27 Feb 2025 18:30:33 -0500
Subject: [PATCH 6/6] -improved specificity of QTable.json description for
resizable-cols prop
---
ui/src/components/table/QTable.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/ui/src/components/table/QTable.json b/ui/src/components/table/QTable.json
index b230aaf1dd2..e559afcb8e1 100644
--- a/ui/src/components/table/QTable.json
+++ b/ui/src/components/table/QTable.json
@@ -15,7 +15,7 @@
},
"resizable-cols": {
"type": "Boolean",
- "desc": "Enable column resizing functionality",
+ "desc": "Enabling allows for easy configuration of user resizable column widths by adding a customizable drag handle between each column specified in the 'columns' prop. By default the drag handle is a small vertical line between each column. The drag handle can be customized by using the 'column-resize-handle' slot. Double clicking the grabber sets the columns back to their default width",
"category": "behavior"
},
"row-key": {