stacks 0.47.4 → 0.48.2
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/buddy/art/social.png +0 -0
- package/buddy/package.json +1 -1
- package/buddy/src/commands/make.ts +27 -12
- package/buddy/src/commands/test.ts +40 -2
- package/core/actions/package.json +2 -2
- package/core/actions/src/helpers/utils.ts +29 -3
- package/core/actions/src/make.ts +37 -6
- package/core/actions/src/test-coverage.ts +1 -1
- package/core/actions/src/test-feature.ts +5 -0
- package/core/actions/src/test-unit.ts +5 -0
- package/core/ai/package.json +1 -1
- package/core/alias/package.json +1 -1
- package/core/arrays/package.json +1 -1
- package/core/auth/package.json +1 -1
- package/core/build/package.json +3 -3
- package/core/cache/package.json +3 -3
- package/core/chat/README.md +33 -40
- package/core/chat/package.json +1 -1
- package/core/cli/package.json +1 -1
- package/core/cloud/package.json +1 -1
- package/core/collections/package.json +1 -1
- package/core/config/package.json +1 -1
- package/core/dashboard/package.json +1 -1
- package/core/database/package.json +1 -1
- package/core/datetime/package.json +1 -1
- package/core/desktop/package.json +1 -1
- package/core/docs/node_modules/.bin/vitepress +2 -2
- package/core/docs/package.json +2 -2
- package/core/domains/package.json +1 -1
- package/core/drivers/package.json +1 -1
- package/core/email/README.md +101 -35
- package/core/email/package.json +1 -1
- package/core/error-handling/package.json +2 -2
- package/core/events/package.json +1 -1
- package/core/git/package.json +1 -1
- package/core/health/package.json +1 -1
- package/core/lint/node_modules/.bin/eslint +2 -2
- package/core/lint/package.json +3 -3
- package/core/logging/package.json +1 -1
- package/core/modules/package.json +1 -1
- package/core/notifications/README.md +7 -2
- package/core/notifications/package.json +1 -1
- package/core/notifications/src/index.ts +37 -9
- package/core/notifications/tests/chat/Slack.test.ts +5 -4
- package/core/notifications/tests/email/Mailgun.test.ts +4 -3
- package/core/notifications/tests/email/Sendgrid.test.ts +3 -3
- package/core/notifications/tests/sms/Twilio.test.ts +3 -3
- package/core/objects/package.json +1 -1
- package/core/path/package.json +1 -1
- package/core/path/src/index.ts +5 -0
- package/core/payments/package.json +1 -1
- package/core/push/README.md +24 -42
- package/core/push/package.json +1 -1
- package/core/realtime/package.json +1 -1
- package/core/router/package.json +1 -1
- package/core/search-engine/package.json +1 -1
- package/core/security/package.json +1 -1
- package/core/server/package.json +1 -1
- package/core/sms/README.md +82 -35
- package/core/sms/package.json +1 -1
- package/core/storage/package.json +1 -1
- package/core/storage/src/index.ts +13 -0
- package/core/strings/README.md +10 -2
- package/core/strings/package.json +4 -2
- package/core/strings/src/case.ts +14 -0
- package/core/strings/src/index.ts +4 -97
- package/core/strings/src/pluralize.ts +1 -0
- package/core/strings/src/utils.ts +80 -0
- package/core/strings/src/validation.ts +182 -0
- package/core/tables/README.md +109 -0
- package/core/tables/examples/vue/App.vue +12 -0
- package/core/tables/examples/vue/favicon.png +0 -0
- package/core/tables/examples/vue/index.html +20 -0
- package/core/tables/examples/web/favicon.png +0 -0
- package/core/tables/examples/web/index.html +13 -0
- package/core/tables/node_modules/.bin/mkdist +17 -0
- package/core/tables/node_modules/.bin/tsc +17 -0
- package/core/tables/node_modules/.bin/tsserver +17 -0
- package/core/tables/node_modules/.bin/unbuild +17 -0
- package/core/tables/package.json +97 -0
- package/core/tables/src/cli/index.ts +1 -0
- package/core/tables/src/components/Demo.vue +89 -0
- package/core/tables/src/components/README.md +111 -0
- package/core/tables/src/components/Table.vue +342 -0
- package/core/tables/src/components/TableBody.vue +33 -0
- package/core/tables/src/components/TableCellActionItems.vue +9 -0
- package/core/tables/src/components/TableFilters.vue +703 -0
- package/core/tables/src/components/TableHead.vue +87 -0
- package/core/tables/src/components/TablePagination.vue +146 -0
- package/core/tables/src/components/TableRow.vue +78 -0
- package/core/tables/src/components/TableSearch.vue +38 -0
- package/core/tables/src/components/Tooltip.vue +10 -0
- package/core/tables/src/config/tables.ts +1 -0
- package/core/tables/src/docs/index.md +0 -0
- package/core/tables/src/functions/README.md +8 -0
- package/core/tables/src/functions/dark.ts +3 -0
- package/core/tables/src/functions/index.ts +2 -0
- package/core/tables/src/functions/table.ts +180 -0
- package/core/tables/tests/example.test.ts +7 -0
- package/core/testing/node_modules/.bin/vitest +2 -2
- package/core/testing/package.json +9 -6
- package/core/types/node_modules/.bin/vitepress +2 -2
- package/core/types/package.json +4 -3
- package/core/types/src/cli.ts +10 -2
- package/core/types/src/hashing.ts +15 -0
- package/core/types/src/index.ts +2 -0
- package/core/types/src/notifications.ts +1 -0
- package/core/types/src/reactivity.ts +3 -0
- package/core/types/src/tables.ts +48 -0
- package/core/ui/node_modules/.bin/vue-tsc +2 -2
- package/core/ui/package.json +2 -2
- package/core/utils/package.json +1 -1
- package/core/x-ray/package.json +1 -1
- package/package.json +3 -2
- package/tsconfig.json +8 -0
- package/vitest.config.ts +2 -0
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { useTable } from '../table'
|
|
3
|
+
|
|
4
|
+
const { table, isColumnSortable, isColumnUsedAsSort, toggleSort, indeterminate, hits, lastColumn, readableLastColumn } = await useTable()
|
|
5
|
+
</script>
|
|
6
|
+
|
|
7
|
+
<template>
|
|
8
|
+
<thead class="bg-gray-50">
|
|
9
|
+
<tr>
|
|
10
|
+
<th
|
|
11
|
+
scope="col"
|
|
12
|
+
class="relative w-12 px-6 sm:px-8 sm:w-16"
|
|
13
|
+
>
|
|
14
|
+
<input
|
|
15
|
+
type="checkbox"
|
|
16
|
+
class="absolute w-4 h-4 -mt-2 text-indigo-600 border-gray-300 rounded top-1/2 left-4 sm:left-6 focus:ring-indigo-500"
|
|
17
|
+
:checked="indeterminate || table.selectedRows?.length === hits.length"
|
|
18
|
+
:indeterminate="indeterminate"
|
|
19
|
+
@change="table.selectedRows = ($event?.target as any).checked ? hits.map((h) => h.id) : []"
|
|
20
|
+
>
|
|
21
|
+
<!-- <input
|
|
22
|
+
type="checkbox"
|
|
23
|
+
class="absolute w-4 h-4 -mt-2 text-indigo-600 border-gray-300 rounded top-1/2 left-4 sm:left-6 focus:ring-indigo-500"
|
|
24
|
+
:checked="indeterminate || selectedRows?.length === hits?.length"
|
|
25
|
+
:indeterminate="indeterminate"
|
|
26
|
+
@change="selectedRows = []"
|
|
27
|
+
> -->
|
|
28
|
+
</th>
|
|
29
|
+
|
|
30
|
+
<th
|
|
31
|
+
v-for="(col, index) in table.columns"
|
|
32
|
+
:key="index"
|
|
33
|
+
scope="col"
|
|
34
|
+
class="font-semibold text-left text-sm py-3.5 pr-3 pl-4 sm:pl-6 text-gray-900"
|
|
35
|
+
:class="index === 0 ? `pr-3 pl-4 sm:pl-6` : `px-3`"
|
|
36
|
+
@click="toggleSort(col)"
|
|
37
|
+
>
|
|
38
|
+
<!-- the last column is oftentimes styled slightly different -->
|
|
39
|
+
|
|
40
|
+
<a
|
|
41
|
+
href="#"
|
|
42
|
+
class="inline-flex group"
|
|
43
|
+
>
|
|
44
|
+
{{ col.includes(':') ? col.split(':')[1].trim() : col }}
|
|
45
|
+
<span
|
|
46
|
+
v-if="isColumnSortable(col)"
|
|
47
|
+
class="flex-none ml-2 rounded"
|
|
48
|
+
:class="isColumnUsedAsSort(col) ? `bg-gray-200 text-gray-900 group-hover:bg-gray-300` : `text-gray-400 invisible group-hover:visible group-focus:visible`"
|
|
49
|
+
@click="toggleSort(col)"
|
|
50
|
+
>
|
|
51
|
+
<div
|
|
52
|
+
v-if="table.sort?.includes('desc')"
|
|
53
|
+
class="w-5 h-5 i-heroicons-solid-chevron-down"
|
|
54
|
+
/>
|
|
55
|
+
<div
|
|
56
|
+
v-if="table.sort?.includes('asc')"
|
|
57
|
+
class="w-5 h-5 i-heroicons-solid-chevron-up"
|
|
58
|
+
/>
|
|
59
|
+
</span>
|
|
60
|
+
</a>
|
|
61
|
+
</th>
|
|
62
|
+
|
|
63
|
+
<th class="font-semibold text-left text-sm py-3.5 pr-3 pl-4 sm:pl-6 text-gray-900">
|
|
64
|
+
<a
|
|
65
|
+
href="#"
|
|
66
|
+
class="inline-flex group"
|
|
67
|
+
>
|
|
68
|
+
{{ readableLastColumn }}
|
|
69
|
+
<span
|
|
70
|
+
v-if="isColumnSortable(lastColumn[0])"
|
|
71
|
+
:class="isColumnUsedAsSort(lastColumn) ? `bg-gray-200 text-gray-900 group-hover:bg-gray-300` : `text-gray-400 invisible group-hover:visible group-focus:visible`"
|
|
72
|
+
@click="toggleSort(lastColumn[0])"
|
|
73
|
+
>
|
|
74
|
+
<div
|
|
75
|
+
v-if="table.sort?.includes('desc')"
|
|
76
|
+
class="w-5 h-5 i-heroicons-solid-chevron-down"
|
|
77
|
+
/>
|
|
78
|
+
<div
|
|
79
|
+
v-if="table.sort?.includes('asc')"
|
|
80
|
+
class="w-5 h-5 i-heroicons-solid-chevron-up"
|
|
81
|
+
/>
|
|
82
|
+
</span>
|
|
83
|
+
</a>
|
|
84
|
+
</th>
|
|
85
|
+
</tr>
|
|
86
|
+
</thead>
|
|
87
|
+
</template>
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
const emit = defineEmits(['paginateToNextPage', 'paginateToPreviousPage', 'paginateToPage'])
|
|
3
|
+
|
|
4
|
+
const { goToNextPage, goToPrevPage, goToPage, table, lastPageNumber, totalPages, pages } = await useTable()
|
|
5
|
+
|
|
6
|
+
// watch(totalPages, (newValue, oldValue) => {
|
|
7
|
+
// // eslint-disable-next-line no-console
|
|
8
|
+
// console.log('totalPages', totalPages.value)
|
|
9
|
+
|
|
10
|
+
// // eslint-disable-next-line no-console
|
|
11
|
+
// console.log('oldValue', oldValue)
|
|
12
|
+
|
|
13
|
+
// // eslint-disable-next-line no-console
|
|
14
|
+
// console.log('newValue', newValue)
|
|
15
|
+
// })
|
|
16
|
+
|
|
17
|
+
// const isFirstPage = computed(() => {
|
|
18
|
+
// if (table.currentPage === 1)
|
|
19
|
+
// return true
|
|
20
|
+
|
|
21
|
+
// return false
|
|
22
|
+
// })
|
|
23
|
+
|
|
24
|
+
// const isLastPage = computed(() => {
|
|
25
|
+
// if (table.currentPage === totalPages.value)
|
|
26
|
+
// return true
|
|
27
|
+
|
|
28
|
+
// return false
|
|
29
|
+
// })
|
|
30
|
+
|
|
31
|
+
// console.log('pages', pages.value)
|
|
32
|
+
|
|
33
|
+
function next() {
|
|
34
|
+
goToNextPage()
|
|
35
|
+
emit('paginateToNextPage')
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function back() {
|
|
39
|
+
goToPrevPage()
|
|
40
|
+
emit('paginateToPreviousPage')
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function paginateTo(page: number) {
|
|
44
|
+
goToPage(page)
|
|
45
|
+
emit('paginateToPage', page)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const currentCount = computed(() => {
|
|
49
|
+
const count = table.perPage * table.currentPage
|
|
50
|
+
const nbHits = table.results?.nbHits || 1
|
|
51
|
+
|
|
52
|
+
return count > nbHits ? table.results?.nbHits : count
|
|
53
|
+
})
|
|
54
|
+
</script>
|
|
55
|
+
|
|
56
|
+
<template>
|
|
57
|
+
<div class="bg-white flex border-gray-200 py-3 items-center justify-end">
|
|
58
|
+
<div class="flex flex-1 justify-between sm:hidden">
|
|
59
|
+
<a
|
|
60
|
+
href="#"
|
|
61
|
+
class="bg-white border rounded-md font-medium border-gray-300 text-sm py-2 px-4 text-gray-700 relative inline-flex items-center hover:bg-gray-50"
|
|
62
|
+
@click.prevent="goToPrevPage()"
|
|
63
|
+
>
|
|
64
|
+
Previous
|
|
65
|
+
</a>
|
|
66
|
+
<a
|
|
67
|
+
href="#"
|
|
68
|
+
class="bg-white border rounded-md font-medium border-gray-300 text-sm ml-3 py-2 px-4 text-gray-700 relative inline-flex items-center hover:bg-gray-50"
|
|
69
|
+
@click.prevent="goToNextPage()"
|
|
70
|
+
>
|
|
71
|
+
Next
|
|
72
|
+
</a>
|
|
73
|
+
</div>
|
|
74
|
+
<div class="min-w-full py-2 hidden inline-block align-middle sm:flex sm:flex-1 sm:items-center sm:justify-between md:px-6 lg:px-8">
|
|
75
|
+
<div>
|
|
76
|
+
<p class="text-sm text-gray-700">
|
|
77
|
+
Showing {{ ((table.perPage * table.currentPage) - table.perPage) + 1 }}
|
|
78
|
+
<span class="font-medium" />
|
|
79
|
+
to
|
|
80
|
+
<span class="font-medium"> {{ currentCount }} </span>
|
|
81
|
+
of
|
|
82
|
+
<span class="font-medium"> {{ table.results?.nbHits ?? 0 }} </span>
|
|
83
|
+
results
|
|
84
|
+
</p>
|
|
85
|
+
</div>
|
|
86
|
+
|
|
87
|
+
<div>
|
|
88
|
+
<nav
|
|
89
|
+
class="-space-x-px rounded-md shadow-sm z-0 relative inline-flex"
|
|
90
|
+
aria-label="Pagination"
|
|
91
|
+
>
|
|
92
|
+
<a
|
|
93
|
+
href="#"
|
|
94
|
+
class="bg-white border rounded-l-md font-medium border-gray-300 text-sm py-2 px-2 text-gray-500 relative inline-flex items-center hover:bg-gray-50"
|
|
95
|
+
@click.prevent="paginateTo(1)"
|
|
96
|
+
>
|
|
97
|
+
<span class="sr-only">First</span>
|
|
98
|
+
<div class="h-4 w-5 i-heroicons-solid-chevron-double-left" />
|
|
99
|
+
</a>
|
|
100
|
+
<a
|
|
101
|
+
href="#"
|
|
102
|
+
class="bg-white border font-medium border-gray-300 text-sm py-2 px-2 text-gray-500 relative inline-flex items-center hover:bg-gray-50"
|
|
103
|
+
@click.prevent="back()"
|
|
104
|
+
>
|
|
105
|
+
<span class="sr-only">Previous</span>
|
|
106
|
+
<div class="h-5 w-5 i-heroicons-solid-chevron-left" />
|
|
107
|
+
</a>
|
|
108
|
+
|
|
109
|
+
<!-- Current: "z-10 bg-indigo-50 border-indigo-500 text-indigo-600", Default: "bg-white border-gray-300 text-gray-500 hover:bg-gray-50" -->
|
|
110
|
+
<a
|
|
111
|
+
v-for="page in pages"
|
|
112
|
+
:key="page"
|
|
113
|
+
href="#"
|
|
114
|
+
aria-current="page"
|
|
115
|
+
:class="[table.currentPage === page && 'border bg-yellow-500 border-yellow-500 text-gray-900 z-10']"
|
|
116
|
+
class="border border-gray-300 text-gray-500 font-medium text-sm py-2 px-4 relative inline-flex items-center underline-transparent"
|
|
117
|
+
@click.prevent="paginateTo(page)"
|
|
118
|
+
>
|
|
119
|
+
{{ page }}
|
|
120
|
+
</a>
|
|
121
|
+
<!-- <a href="#" class="bg-white border font-medium border-gray-300 text-sm py-2 px-4 text-gray-500 relative inline-flex items-center underline-transparent hover:bg-gray-50"> 2 </a>
|
|
122
|
+
<a href="#" class="bg-white border font-medium border-gray-300 text-sm py-2 px-4 text-gray-500 hidden relative items-center underline-transparent md:inline-flex hover:bg-gray-50"> 3 </a>
|
|
123
|
+
<a href="#" class="bg-white border font-medium border-gray-300 text-sm py-2 px-4 text-gray-500 hidden relative items-center underline-transparent md:inline-flex hover:bg-gray-50"> 4 </a>
|
|
124
|
+
<a href="#" class="bg-white border font-medium border-gray-300 text-sm py-2 px-4 text-gray-500 hidden relative items-center underline-transparent md:inline-flex hover:bg-gray-50"> 5 </a> -->
|
|
125
|
+
|
|
126
|
+
<a
|
|
127
|
+
href="#"
|
|
128
|
+
class="bg-white border font-medium border-gray-300 text-sm py-2 px-2 text-gray-500 relative inline-flex items-center underline-transparent hover:bg-gray-50"
|
|
129
|
+
@click.prevent="next()"
|
|
130
|
+
>
|
|
131
|
+
<span class="sr-only">Next</span>
|
|
132
|
+
<div class="h-5 w-5 i-heroicons-solid-chevron-right" />
|
|
133
|
+
</a>
|
|
134
|
+
<a
|
|
135
|
+
href="#"
|
|
136
|
+
class="bg-white border rounded-r-md font-medium border-gray-300 text-sm py-2 px-2 text-gray-500 relative inline-flex items-center underline-transparent hover:bg-gray-50"
|
|
137
|
+
@click.prevent="paginateTo(lastPageNumber)"
|
|
138
|
+
>
|
|
139
|
+
<span class="sr-only">Last</span>
|
|
140
|
+
<div class="h-4 w-5 i-heroicons-solid-chevron-double-right" />
|
|
141
|
+
</a>
|
|
142
|
+
</nav>
|
|
143
|
+
</div>
|
|
144
|
+
</div>
|
|
145
|
+
</div>
|
|
146
|
+
</template>
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { Hit } from '@stacksjs/types'
|
|
3
|
+
|
|
4
|
+
const { hit, index } = defineProps<{ hit: Hit; index: number }>()
|
|
5
|
+
|
|
6
|
+
const { table, columnName } = await useTable()
|
|
7
|
+
|
|
8
|
+
// let's generate the value of the row
|
|
9
|
+
function generateValue(hit: any, col: any) {
|
|
10
|
+
if (col.includes(':'))
|
|
11
|
+
return hit[col.split(':')[0].trim()]
|
|
12
|
+
|
|
13
|
+
return JSON.parse(hit[col])
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function getClass(index: number) {
|
|
17
|
+
if (index % 2 !== 0)
|
|
18
|
+
return 'bg-gray-200'
|
|
19
|
+
|
|
20
|
+
return 'bg-gray-50'
|
|
21
|
+
}
|
|
22
|
+
</script>
|
|
23
|
+
|
|
24
|
+
<template>
|
|
25
|
+
<tr
|
|
26
|
+
scope="row"
|
|
27
|
+
:class="getClass(index)"
|
|
28
|
+
:data-index="index"
|
|
29
|
+
>
|
|
30
|
+
<td class="relative w-12 px-6 sm:px-8 sm:w-16">
|
|
31
|
+
<div
|
|
32
|
+
v-if="table.selectedRows?.includes(hit.id)"
|
|
33
|
+
class="bg-indigo-600 inset-y-0 left-0 w-0.5 absolute"
|
|
34
|
+
/>
|
|
35
|
+
<input
|
|
36
|
+
v-model="table.selectedRows"
|
|
37
|
+
:value="hit.id"
|
|
38
|
+
type="checkbox"
|
|
39
|
+
class="absolute w-4 h-4 -mt-2 text-indigo-600 border-gray-300 rounded top-1/2 left-4 sm:left-6 focus:ring-indigo-500"
|
|
40
|
+
>
|
|
41
|
+
</td>
|
|
42
|
+
|
|
43
|
+
<td
|
|
44
|
+
v-for="(col, x) in table.columns"
|
|
45
|
+
:key="x"
|
|
46
|
+
class="py-4 text-sm font-medium text-gray-900 whitespace-nowrap "
|
|
47
|
+
:class="table.columns.length === x - 1 ? 'table-last-column pr-4 text-right sm:pr-6' : 'pr-3 pl-4 sm:pl-6'"
|
|
48
|
+
>
|
|
49
|
+
<!-- last columns oftentimes are styled slightly different -->
|
|
50
|
+
<!-- <span v-if="(table.columns.length === x + 1) && (table.actionable || table.actions)">
|
|
51
|
+
<slot name="action_column" :row-data="hit">
|
|
52
|
+
<TableCellActionItems />
|
|
53
|
+
</slot>
|
|
54
|
+
</span> -->
|
|
55
|
+
|
|
56
|
+
<span>
|
|
57
|
+
<slot
|
|
58
|
+
:name="columnName(col)"
|
|
59
|
+
:col-data="generateValue(hit, col)"
|
|
60
|
+
>
|
|
61
|
+
{{ generateValue(hit, col) }}
|
|
62
|
+
</slot>
|
|
63
|
+
</span>
|
|
64
|
+
</td>
|
|
65
|
+
|
|
66
|
+
<td v-if="(table.actionable || table.actions)">
|
|
67
|
+
<!-- last columns oftentimes are styled slightly different -->
|
|
68
|
+
<span>
|
|
69
|
+
<slot
|
|
70
|
+
name="action_column"
|
|
71
|
+
:row-data="hit"
|
|
72
|
+
>
|
|
73
|
+
<TableCellActionItems />
|
|
74
|
+
</slot>
|
|
75
|
+
</span>
|
|
76
|
+
</td>
|
|
77
|
+
</tr>
|
|
78
|
+
</template>
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
const { table } = await useTable()
|
|
3
|
+
|
|
4
|
+
const open = ref(false)
|
|
5
|
+
</script>
|
|
6
|
+
|
|
7
|
+
<template>
|
|
8
|
+
<div class="px-8 flex justify-between mx-auto max-w-7xl">
|
|
9
|
+
<div>
|
|
10
|
+
<input
|
|
11
|
+
v-model="table.query"
|
|
12
|
+
type="text"
|
|
13
|
+
class="block w-full shadow-sm focus:ring-indigo-500 p-2 focus:border-indigo-500 sm:max-w-xs sm:text-sm border-gray-300 rounded-md"
|
|
14
|
+
placeholder="type here"
|
|
15
|
+
>
|
|
16
|
+
</div>
|
|
17
|
+
|
|
18
|
+
<div>
|
|
19
|
+
<button
|
|
20
|
+
type="button"
|
|
21
|
+
class="inline-flex items-center px-3 py-2 border border-transparent shadow-sm text-sm leading-4 font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
|
|
22
|
+
@click="open = !open"
|
|
23
|
+
>
|
|
24
|
+
<!-- Heroicon name: solid/mail -->
|
|
25
|
+
<svg
|
|
26
|
+
class="w-4 h-4"
|
|
27
|
+
fill="currentColor"
|
|
28
|
+
viewBox="0 0 20 20"
|
|
29
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
30
|
+
><path
|
|
31
|
+
fill-rule="evenodd"
|
|
32
|
+
d="M3 3a1 1 0 011-1h12a1 1 0 011 1v3a1 1 0 01-.293.707L12 11.414V15a1 1 0 01-.293.707l-2 2A1 1 0 018 17v-5.586L3.293 6.707A1 1 0 013 6V3z"
|
|
33
|
+
clip-rule="evenodd"
|
|
34
|
+
/></svg>
|
|
35
|
+
</button>
|
|
36
|
+
</div>
|
|
37
|
+
</div>
|
|
38
|
+
</template>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {}
|
|
File without changes
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# Your Functions Library
|
|
2
|
+
|
|
3
|
+
You may use functions to share on npm or have them run on a server behind one of your `../routes`.
|
|
4
|
+
|
|
5
|
+
Learn more about Stacks functions, check out the [documentation](https://stacks.ow3org.com).
|
|
6
|
+
|
|
7
|
+
> **Note**
|
|
8
|
+
> If your project does not require any routes, you can remove this folder._
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import { calculatePagination, currentPage, filterName, filters, goToNextPage, goToPage, goToPrevPage, hits, index, lastPageNumber, perPage, query, results, search, searchFilters, searchParams, setTotalHits, sort, sorts, totalPages } from '@stacksjs/search-engine'
|
|
2
|
+
import { isObject, isString, useStorage } from '@stacksjs/utils'
|
|
3
|
+
import type { Ref, TableStore } from '@stacksjs/types'
|
|
4
|
+
import { computed } from 'vue-demi'
|
|
5
|
+
|
|
6
|
+
const table = (useStorage('table', determineState()).value as TableStore)
|
|
7
|
+
|
|
8
|
+
// table related
|
|
9
|
+
const columns = computed(() => table.columns)
|
|
10
|
+
const actions = computed(() => table.actions)
|
|
11
|
+
const actionable = computed(() => table.actionable)
|
|
12
|
+
const selectedRows = computed(() => table.selectedRows)
|
|
13
|
+
const selectedAll = computed(() => table.selectedAll)
|
|
14
|
+
const pages: Ref<number[]> = ref([])
|
|
15
|
+
const indeterminate = computed(() => (table?.selectedRows?.length ?? 0) > 0 && (table?.selectedRows?.length ?? 0) < hits.value.length)
|
|
16
|
+
const lastColumn = computed(() => {
|
|
17
|
+
return table.columns[table.columns.length - 1]
|
|
18
|
+
})
|
|
19
|
+
const readableLastColumn = computed(() => lastColumn[0]?.includes(':') ? lastColumn[0].split(':')[1].trim() : lastColumn[0])
|
|
20
|
+
|
|
21
|
+
// this watchEffect picks up any reactivity changes from `query` and `searchParams` and it will then trigger a search
|
|
22
|
+
watchEffect(async () => {
|
|
23
|
+
// console.log('watchEffect', query, searchParams)
|
|
24
|
+
|
|
25
|
+
const results = await search(query.value, searchParams.value)
|
|
26
|
+
|
|
27
|
+
if (results) {
|
|
28
|
+
table.results = results
|
|
29
|
+
table.hits = results.hits
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
setTotalHits(table.results?.nbHits ?? 1)
|
|
33
|
+
calculatePagination()
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
watchDebounced(
|
|
37
|
+
query,
|
|
38
|
+
() => {
|
|
39
|
+
// eslint-disable-next-line no-console
|
|
40
|
+
console.log('watchDebounced')
|
|
41
|
+
|
|
42
|
+
if (table === undefined)
|
|
43
|
+
return
|
|
44
|
+
|
|
45
|
+
if (isRef(table.query))
|
|
46
|
+
table.query = query.value
|
|
47
|
+
},
|
|
48
|
+
{ debounce: 500 },
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
function determineState(): TableStore {
|
|
52
|
+
const ls = localStorage.getItem('table')
|
|
53
|
+
|
|
54
|
+
if (isString(ls))
|
|
55
|
+
return JSON.parse(ls)
|
|
56
|
+
|
|
57
|
+
// initial default state - overwrite with properties passed down from parent component
|
|
58
|
+
const table: TableStore = {
|
|
59
|
+
source: '',
|
|
60
|
+
password: '',
|
|
61
|
+
index: '',
|
|
62
|
+
columns: [],
|
|
63
|
+
filters: [],
|
|
64
|
+
perPage: 20,
|
|
65
|
+
currentPage: 1,
|
|
66
|
+
query: '',
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return table
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function isColumnSortable(col: string): Boolean {
|
|
73
|
+
if (!hasTableLoaded(table))
|
|
74
|
+
return false
|
|
75
|
+
|
|
76
|
+
if (col === undefined)
|
|
77
|
+
return false
|
|
78
|
+
|
|
79
|
+
if (col.includes(':'))
|
|
80
|
+
col = col.split(':')[0]
|
|
81
|
+
|
|
82
|
+
if (table.sorts?.includes(col))
|
|
83
|
+
return true
|
|
84
|
+
|
|
85
|
+
return false
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function hasTableLoaded(state?: any): Boolean {
|
|
89
|
+
if (state?.index !== '')
|
|
90
|
+
return true
|
|
91
|
+
|
|
92
|
+
return isString(table?.index) && table.index !== '' // a lazy way to check if the table is loaded
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function isColumnUsedAsSort(col: string | object) {
|
|
96
|
+
let sortKey
|
|
97
|
+
|
|
98
|
+
if (isObject(col))
|
|
99
|
+
sortKey = col[0].includes(':') ? col[0].split(':')[0].trim() : col[0]
|
|
100
|
+
|
|
101
|
+
else
|
|
102
|
+
sortKey = col.includes(':') ? col.split(':')[0].trim() : col
|
|
103
|
+
|
|
104
|
+
return table.sort?.includes(sortKey)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function toggleSort(col: string | Ref<string>) {
|
|
108
|
+
if (isRef(col))
|
|
109
|
+
col = unref(col)
|
|
110
|
+
|
|
111
|
+
const sortKey = (col as string).includes(':') ? (col as string).split(':')[0].trim() : col
|
|
112
|
+
|
|
113
|
+
if (table.sort?.includes('desc')) {
|
|
114
|
+
table.sort = `${sortKey}:asc`
|
|
115
|
+
|
|
116
|
+
// eslint-disable-next-line no-console
|
|
117
|
+
console.log('sort included asc it is now desc for', sortKey)
|
|
118
|
+
|
|
119
|
+
return
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (table.sort?.includes('asc')) {
|
|
123
|
+
table.sort = undefined
|
|
124
|
+
|
|
125
|
+
// eslint-disable-next-line no-console
|
|
126
|
+
console.log('sort included desc it is now "" for', sortKey)
|
|
127
|
+
|
|
128
|
+
return
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// eslint-disable-next-line no-console
|
|
132
|
+
console.log('there was no sort. Setting it now in asc order for', sortKey)
|
|
133
|
+
|
|
134
|
+
table.sort = `${sortKey}:desc`
|
|
135
|
+
|
|
136
|
+
// eslint-disable-next-line no-console
|
|
137
|
+
console.log('table.sort', table.sort)
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function columnName(col: string) {
|
|
141
|
+
return col.split(':')[0].trim()
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export async function useTable(store?: TableStore) {
|
|
145
|
+
return {
|
|
146
|
+
store,
|
|
147
|
+
table,
|
|
148
|
+
index,
|
|
149
|
+
columns,
|
|
150
|
+
isColumnSortable,
|
|
151
|
+
filters,
|
|
152
|
+
sort,
|
|
153
|
+
sorts,
|
|
154
|
+
query,
|
|
155
|
+
results,
|
|
156
|
+
hits,
|
|
157
|
+
perPage,
|
|
158
|
+
currentPage,
|
|
159
|
+
goToPrevPage,
|
|
160
|
+
goToNextPage,
|
|
161
|
+
goToPage,
|
|
162
|
+
search,
|
|
163
|
+
searchFilters,
|
|
164
|
+
searchParams,
|
|
165
|
+
toggleSort,
|
|
166
|
+
isColumnUsedAsSort,
|
|
167
|
+
actionable,
|
|
168
|
+
actions,
|
|
169
|
+
columnName,
|
|
170
|
+
indeterminate,
|
|
171
|
+
lastColumn,
|
|
172
|
+
readableLastColumn,
|
|
173
|
+
lastPageNumber,
|
|
174
|
+
selectedRows,
|
|
175
|
+
selectedAll,
|
|
176
|
+
totalPages,
|
|
177
|
+
pages,
|
|
178
|
+
filterName,
|
|
179
|
+
}
|
|
180
|
+
}
|
|
@@ -11,7 +11,7 @@ else
|
|
|
11
11
|
export NODE_PATH="$NODE_PATH:/home/runner/work/stacks/stacks/node_modules/.pnpm/node_modules"
|
|
12
12
|
fi
|
|
13
13
|
if [ -x "$basedir/node" ]; then
|
|
14
|
-
exec "$basedir/node" "$basedir/../../../../../node_modules/.pnpm/vitest@0.26.
|
|
14
|
+
exec "$basedir/node" "$basedir/../../../../../node_modules/.pnpm/vitest@0.26.3_@vitest+ui@0.26.3/node_modules/vitest/vitest.mjs" "$@"
|
|
15
15
|
else
|
|
16
|
-
exec node "$basedir/../../../../../node_modules/.pnpm/vitest@0.26.
|
|
16
|
+
exec node "$basedir/../../../../../node_modules/.pnpm/vitest@0.26.3_@vitest+ui@0.26.3/node_modules/vitest/vitest.mjs" "$@"
|
|
17
17
|
fi
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stacksjs/testing",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.48.2",
|
|
5
5
|
"packageManager": "pnpm@7.21.0",
|
|
6
|
-
"description": "The Stacks way
|
|
6
|
+
"description": "The Stacks way of testing.",
|
|
7
7
|
"author": "Chris Breuer",
|
|
8
8
|
"license": "MIT",
|
|
9
9
|
"funding": "https://github.com/sponsors/chrisbbreuer",
|
|
@@ -18,11 +18,14 @@
|
|
|
18
18
|
},
|
|
19
19
|
"keywords": [
|
|
20
20
|
"tests",
|
|
21
|
-
"e2e",
|
|
22
21
|
"unit",
|
|
22
|
+
"feature",
|
|
23
|
+
"e2e",
|
|
23
24
|
"testing",
|
|
24
25
|
"utilities",
|
|
25
26
|
"functions",
|
|
27
|
+
"playwright",
|
|
28
|
+
"vitest",
|
|
26
29
|
"stacks"
|
|
27
30
|
],
|
|
28
31
|
"main": "dist/index.mjs",
|
|
@@ -47,9 +50,9 @@
|
|
|
47
50
|
},
|
|
48
51
|
"peerDependencies": {
|
|
49
52
|
"@playwright/test": "^1.29.1",
|
|
50
|
-
"@vitest/coverage-istanbul": "^0.26.
|
|
51
|
-
"@vitest/ui": "^0.26.
|
|
52
|
-
"vitest": "^0.26.
|
|
53
|
+
"@vitest/coverage-istanbul": "^0.26.3",
|
|
54
|
+
"@vitest/ui": "^0.26.3",
|
|
55
|
+
"vitest": "^0.26.3"
|
|
53
56
|
},
|
|
54
57
|
"devDependencies": {
|
|
55
58
|
"mkdist": "^1.0.0",
|
|
@@ -11,7 +11,7 @@ else
|
|
|
11
11
|
export NODE_PATH="$NODE_PATH:/home/runner/work/stacks/stacks/node_modules/.pnpm/node_modules"
|
|
12
12
|
fi
|
|
13
13
|
if [ -x "$basedir/node" ]; then
|
|
14
|
-
exec "$basedir/node" "$basedir/../../../../../node_modules/.pnpm/vitepress@1.0.0-alpha.
|
|
14
|
+
exec "$basedir/node" "$basedir/../../../../../node_modules/.pnpm/vitepress@1.0.0-alpha.34_j73j5xdbzpkigstapj6vkce2xy/node_modules/vitepress/bin/vitepress.js" "$@"
|
|
15
15
|
else
|
|
16
|
-
exec node "$basedir/../../../../../node_modules/.pnpm/vitepress@1.0.0-alpha.
|
|
16
|
+
exec node "$basedir/../../../../../node_modules/.pnpm/vitepress@1.0.0-alpha.34_j73j5xdbzpkigstapj6vkce2xy/node_modules/vitepress/bin/vitepress.js" "$@"
|
|
17
17
|
fi
|
package/core/types/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stacksjs/types",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.48.2",
|
|
5
5
|
"packageManager": "pnpm@7.21.0",
|
|
6
6
|
"description": "The Stacks framework types.",
|
|
7
7
|
"author": "Chris Breuer",
|
|
@@ -46,6 +46,7 @@
|
|
|
46
46
|
"@mdit-vue/plugin-component": "^0.11.2",
|
|
47
47
|
"@mdit-vue/plugin-frontmatter": "^0.11.1",
|
|
48
48
|
"@mdit-vue/types": "^0.11.0",
|
|
49
|
+
"@prisma/client": "^4.8.0",
|
|
49
50
|
"@rollup/pluginutils": "^5.0.2",
|
|
50
51
|
"@types/bcryptjs": "^2.4.2",
|
|
51
52
|
"@types/crypto-js": "^4.1.1",
|
|
@@ -63,9 +64,9 @@
|
|
|
63
64
|
"typescript": "^4.9.4",
|
|
64
65
|
"unplugin-auto-import": "^0.12.1",
|
|
65
66
|
"unplugin-vue-components": "^0.22.12",
|
|
66
|
-
"vite-plugin-inspect": "^0.7.
|
|
67
|
+
"vite-plugin-inspect": "^0.7.12",
|
|
67
68
|
"vite-plugin-vue-layouts": "^0.7.0",
|
|
68
69
|
"vite-ssg": "^0.22.1",
|
|
69
|
-
"vitepress": "1.0.0-alpha.
|
|
70
|
+
"vitepress": "1.0.0-alpha.34"
|
|
70
71
|
}
|
|
71
72
|
}
|