From 5048fe0f7d99ab14ac6f467b5e4479d712963127 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Wed, 11 Jun 2025 14:41:30 -0400 Subject: [PATCH 1/9] wip --- .../js/components/ui/Listing/BulkActions.vue | 5 + .../js/components/ui/Listing/ColumnPicker.vue | 5 + .../js/components/ui/Listing/Filters.vue | 3 + .../js/components/ui/Listing/HeaderCell.vue | 30 ++ .../js/components/ui/Listing/Listing.vue | 275 ++++++++++++++++++ .../js/components/ui/Listing/Pagination.vue | 16 + .../js/components/ui/Listing/Presets.vue | 5 + resources/js/components/ui/Listing/Search.vue | 5 + resources/js/components/ui/Listing/Table.vue | 179 ++++++++++++ .../js/components/ui/Listing/ToggleAll.vue | 35 +++ resources/js/components/ui/Pagination.vue | 197 +++++++++++++ resources/js/components/ui/index.js | 2 + 12 files changed, 757 insertions(+) create mode 100644 resources/js/components/ui/Listing/BulkActions.vue create mode 100644 resources/js/components/ui/Listing/ColumnPicker.vue create mode 100644 resources/js/components/ui/Listing/Filters.vue create mode 100644 resources/js/components/ui/Listing/HeaderCell.vue create mode 100644 resources/js/components/ui/Listing/Listing.vue create mode 100644 resources/js/components/ui/Listing/Pagination.vue create mode 100644 resources/js/components/ui/Listing/Presets.vue create mode 100644 resources/js/components/ui/Listing/Search.vue create mode 100644 resources/js/components/ui/Listing/Table.vue create mode 100644 resources/js/components/ui/Listing/ToggleAll.vue create mode 100644 resources/js/components/ui/Pagination.vue diff --git a/resources/js/components/ui/Listing/BulkActions.vue b/resources/js/components/ui/Listing/BulkActions.vue new file mode 100644 index 0000000000..b6b549b3cc --- /dev/null +++ b/resources/js/components/ui/Listing/BulkActions.vue @@ -0,0 +1,5 @@ + + + diff --git a/resources/js/components/ui/Listing/ColumnPicker.vue b/resources/js/components/ui/Listing/ColumnPicker.vue new file mode 100644 index 0000000000..3168de7e1d --- /dev/null +++ b/resources/js/components/ui/Listing/ColumnPicker.vue @@ -0,0 +1,5 @@ + + + diff --git a/resources/js/components/ui/Listing/Filters.vue b/resources/js/components/ui/Listing/Filters.vue new file mode 100644 index 0000000000..5958daf7cc --- /dev/null +++ b/resources/js/components/ui/Listing/Filters.vue @@ -0,0 +1,3 @@ + + + diff --git a/resources/js/components/ui/Listing/HeaderCell.vue b/resources/js/components/ui/Listing/HeaderCell.vue new file mode 100644 index 0000000000..6621ac77b2 --- /dev/null +++ b/resources/js/components/ui/Listing/HeaderCell.vue @@ -0,0 +1,30 @@ + + + diff --git a/resources/js/components/ui/Listing/Listing.vue b/resources/js/components/ui/Listing/Listing.vue new file mode 100644 index 0000000000..c18710790a --- /dev/null +++ b/resources/js/components/ui/Listing/Listing.vue @@ -0,0 +1,275 @@ + + + + + diff --git a/resources/js/components/ui/Listing/Pagination.vue b/resources/js/components/ui/Listing/Pagination.vue new file mode 100644 index 0000000000..fe80b60a3f --- /dev/null +++ b/resources/js/components/ui/Listing/Pagination.vue @@ -0,0 +1,16 @@ + + + diff --git a/resources/js/components/ui/Listing/Presets.vue b/resources/js/components/ui/Listing/Presets.vue new file mode 100644 index 0000000000..c61e878e13 --- /dev/null +++ b/resources/js/components/ui/Listing/Presets.vue @@ -0,0 +1,5 @@ + + + diff --git a/resources/js/components/ui/Listing/Search.vue b/resources/js/components/ui/Listing/Search.vue new file mode 100644 index 0000000000..10f021a01e --- /dev/null +++ b/resources/js/components/ui/Listing/Search.vue @@ -0,0 +1,5 @@ + + + diff --git a/resources/js/components/ui/Listing/Table.vue b/resources/js/components/ui/Listing/Table.vue new file mode 100644 index 0000000000..7bcba933a7 --- /dev/null +++ b/resources/js/components/ui/Listing/Table.vue @@ -0,0 +1,179 @@ + + + diff --git a/resources/js/components/ui/Listing/ToggleAll.vue b/resources/js/components/ui/Listing/ToggleAll.vue new file mode 100644 index 0000000000..f5d9a12a18 --- /dev/null +++ b/resources/js/components/ui/Listing/ToggleAll.vue @@ -0,0 +1,35 @@ + + + diff --git a/resources/js/components/ui/Pagination.vue b/resources/js/components/ui/Pagination.vue new file mode 100644 index 0000000000..28ece87dd4 --- /dev/null +++ b/resources/js/components/ui/Pagination.vue @@ -0,0 +1,197 @@ + + + diff --git a/resources/js/components/ui/index.js b/resources/js/components/ui/index.js index 57fa97d2e5..41b0785666 100644 --- a/resources/js/components/ui/index.js +++ b/resources/js/components/ui/index.js @@ -60,6 +60,7 @@ import { default as Textarea } from './Textarea.vue'; import { default as TimePicker } from './TimePicker/TimePicker.vue'; import { default as Tooltip } from './Tooltip.vue'; import { default as Widget } from './Widget.vue'; +import { default as Pagination } from './Pagination.vue'; export { Badge, @@ -124,4 +125,5 @@ export { TimePicker, Tooltip, Widget, + Pagination, }; From 3e2a352286b0b170926827b32fdfc8a22670f4bc Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Wed, 11 Jun 2025 15:05:22 -0400 Subject: [PATCH 2/9] maxselections is a ref --- resources/js/components/ui/Listing/ToggleAll.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/js/components/ui/Listing/ToggleAll.vue b/resources/js/components/ui/Listing/ToggleAll.vue index f5d9a12a18..7ed5d7dde7 100644 --- a/resources/js/components/ui/Listing/ToggleAll.vue +++ b/resources/js/components/ui/Listing/ToggleAll.vue @@ -12,7 +12,7 @@ function toggle() { function checkMaximumAmountOfItems() { let newSelections = items.value.map((row) => row.id); - if (maxSelections) newSelections = newSelections.slice(0, maxSelections); + if (maxSelections.value) newSelections = newSelections.slice(0, maxSelections.value); selections.value.splice(0, selections.value.length, ...newSelections); } From cca05c0cc39daf814be5ccde2ac49408c1c6262a Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Wed, 11 Jun 2025 15:26:31 -0400 Subject: [PATCH 3/9] wire up search --- .../js/components/ui/Listing/Listing.vue | 13 +++++++++++ resources/js/components/ui/Listing/Search.vue | 22 +++++++++++++++++-- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/resources/js/components/ui/Listing/Listing.vue b/resources/js/components/ui/Listing/Listing.vue index c18710790a..c38d0fe97f 100644 --- a/resources/js/components/ui/Listing/Listing.vue +++ b/resources/js/components/ui/Listing/Listing.vue @@ -61,6 +61,10 @@ const props = defineProps({ type: Object, default: () => ({}), }, + searchQuery: { + type: String, + default: null, + }, }); const id = uniqid(); @@ -73,12 +77,14 @@ const initializing = ref(true); const loading = ref(true); let popping = false; let source = null; +const searchQuery = ref(null); const rawParameters = computed(() => ({ page: currentPage.value, perPage: perPage.value, sort: props.sortColumn, order: props.sortDirection, + search: searchQuery.value, })); function setParameters(params) { @@ -86,6 +92,7 @@ function setParameters(params) { perPage.value = parseInt(params.perPage); emit('update:sortColumn', params.sort); emit('update:sortDirection', params.order); + searchQuery.value = params.search; } const parameters = computed(() => { @@ -224,6 +231,10 @@ function setPerPage(value) { perPage.value = value; } +function setSearchQuery(query) { + searchQuery.value = query; +} + provideListingContext({ loading, items, @@ -238,6 +249,8 @@ provideListingContext({ perPage, setPerPage, setCurrentPage, + searchQuery, + setSearchQuery, }); const slotProps = computed(() => ({ diff --git a/resources/js/components/ui/Listing/Search.vue b/resources/js/components/ui/Listing/Search.vue index 10f021a01e..cc75234f8c 100644 --- a/resources/js/components/ui/Listing/Search.vue +++ b/resources/js/components/ui/Listing/Search.vue @@ -1,5 +1,23 @@ - + From 606ca40ec33d316b1b5ef371ca6e26c9ae61b4e7 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Wed, 11 Jun 2025 15:31:25 -0400 Subject: [PATCH 4/9] Make filter button look like it works (but doesnt yet) --- .../js/components/ui/Listing/Filters.vue | 35 +++++++++++++++++-- resources/js/components/ui/index.js | 4 +++ 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/resources/js/components/ui/Listing/Filters.vue b/resources/js/components/ui/Listing/Filters.vue index 5958daf7cc..08e9ead080 100644 --- a/resources/js/components/ui/Listing/Filters.vue +++ b/resources/js/components/ui/Listing/Filters.vue @@ -1,3 +1,34 @@ - + + + diff --git a/resources/js/components/ui/index.js b/resources/js/components/ui/index.js index 41b0785666..ccfd866b7b 100644 --- a/resources/js/components/ui/index.js +++ b/resources/js/components/ui/index.js @@ -61,6 +61,8 @@ import { default as TimePicker } from './TimePicker/TimePicker.vue'; import { default as Tooltip } from './Tooltip.vue'; import { default as Widget } from './Widget.vue'; import { default as Pagination } from './Pagination.vue'; +import { default as Modal } from './Modal/Modal.vue'; +import { default as ModalClose } from './Modal/Close.vue'; export { Badge, @@ -126,4 +128,6 @@ export { Tooltip, Widget, Pagination, + Modal, + ModalClose, }; From 3728f7a8dfae29fc96c6e933fb9057cc473ef19d Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Wed, 11 Jun 2025 17:05:20 -0400 Subject: [PATCH 5/9] Column picker --- .../js/components/ui/Listing/ColumnPicker.vue | 154 +++++++++++++++++- .../js/components/ui/Listing/Listing.vue | 17 +- resources/js/components/ui/Modal/Modal.vue | 3 +- 3 files changed, 170 insertions(+), 4 deletions(-) diff --git a/resources/js/components/ui/Listing/ColumnPicker.vue b/resources/js/components/ui/Listing/ColumnPicker.vue index 3168de7e1d..07a18d9afe 100644 --- a/resources/js/components/ui/Listing/ColumnPicker.vue +++ b/resources/js/components/ui/Listing/ColumnPicker.vue @@ -1,5 +1,155 @@ - + diff --git a/resources/js/components/ui/Listing/Listing.vue b/resources/js/components/ui/Listing/Listing.vue index c38d0fe97f..e7484b8029 100644 --- a/resources/js/components/ui/Listing/Listing.vue +++ b/resources/js/components/ui/Listing/Listing.vue @@ -126,7 +126,7 @@ function request() { signal: source.signal, }) .then((response) => { - emit('update:columns', response.data.meta.columns); + setColumns(response.data.meta.columns); activeFilterBadges.value = { ...response.data.meta.activeFilterBadges }; items.value = Object.values(response.data.data); meta.value = response.data.meta; @@ -187,6 +187,8 @@ const visibleColumns = computed(() => { return visibleColumns.length ? visibleColumns : props.columns; }); +const hiddenColumns = computed(() => props.columns.filter((column) => !column.visible)); + const sortableColumns = computed(() => { return props.columns.filter((column) => column.sortable).map((column) => column.field); }); @@ -195,6 +197,16 @@ function isColumnVisible(column) { return visibleColumns.value.find((c) => c.field === column); } +function setColumns(columns) { + emit('update:columns', columns); +} + +const testColumns = computed(() => { + return props.columns.map((column) => { + return [column.field, column.visible]; + }); +}); + function setSortColumn(column) { if (!props.sortable) return; @@ -240,7 +252,9 @@ provideListingContext({ items, meta, columns: toRef(() => props.columns), + setColumns, visibleColumns, + hiddenColumns, sortColumn: toRef(() => props.sortColumn), setSortColumn, selections, @@ -251,6 +265,7 @@ provideListingContext({ setCurrentPage, searchQuery, setSearchQuery, + preferencesPrefix: toRef(() => props.preferencesPrefix), }); const slotProps = computed(() => ({ diff --git a/resources/js/components/ui/Modal/Modal.vue b/resources/js/components/ui/Modal/Modal.vue index 074f382459..d417a6aa82 100644 --- a/resources/js/components/ui/Modal/Modal.vue +++ b/resources/js/components/ui/Modal/Modal.vue @@ -5,6 +5,7 @@ import { DialogContent, DialogOverlay, DialogPortal, DialogRoot, DialogTitle, Di const props = defineProps({ title: { type: String, default: '' }, + open: { type: Boolean, default: false }, }); const hasModalTitleComponent = hasComponent('ModalTitle'); @@ -25,7 +26,7 @@ const modalClasses = cva({