Submission table pagination & migrate chart to vue3 (#254)
* Submission table Pagination in background * migrate chart to vue3 * Form submissions pagination * Form submissions * Fix form starts * Fix openSelect key issue --------- Co-authored-by: Forms Dev <chirag+new@notionforms.io> Co-authored-by: Julien Nahum <julien@nahum.net>
This commit is contained in:
parent
25c5e00c41
commit
24276f0b95
|
@ -53,7 +53,7 @@ class Kernel extends HttpKernel
|
||||||
],
|
],
|
||||||
|
|
||||||
'api' => [
|
'api' => [
|
||||||
'throttle:60,1',
|
'throttle:100,1',
|
||||||
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||||
\App\Http\Middleware\EncryptCookies::class,
|
\App\Http\Middleware\EncryptCookies::class,
|
||||||
\Illuminate\Session\Middleware\StartSession::class,
|
\Illuminate\Session\Middleware\StartSession::class,
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
"@vueuse/components": "^10.5.0",
|
"@vueuse/components": "^10.5.0",
|
||||||
"@vueuse/core": "^10.5.0",
|
"@vueuse/core": "^10.5.0",
|
||||||
"axios": "^0.21.1",
|
"axios": "^0.21.1",
|
||||||
"chart.js": "^3.7.1",
|
"chart.js": "^4.4.0",
|
||||||
"clone-deep": "^4.0.1",
|
"clone-deep": "^4.0.1",
|
||||||
"date-fns": "^2.28.0",
|
"date-fns": "^2.28.0",
|
||||||
"debounce": "^1.2.1",
|
"debounce": "^1.2.1",
|
||||||
|
@ -28,7 +28,7 @@
|
||||||
"tinymotion": "^0.2.0",
|
"tinymotion": "^0.2.0",
|
||||||
"vform": "^2.1.1",
|
"vform": "^2.1.1",
|
||||||
"vue": "^3.2.13",
|
"vue": "^3.2.13",
|
||||||
"vue-chartjs": "^4.1.0",
|
"vue-chartjs": "^5.2.0",
|
||||||
"vue-codemirror": "^4.0.6",
|
"vue-codemirror": "^4.0.6",
|
||||||
"vue-confetti": "^2.3.0",
|
"vue-confetti": "^2.3.0",
|
||||||
"vue-country-flag-next": "^2.3.2",
|
"vue-country-flag-next": "^2.3.2",
|
||||||
|
@ -2263,6 +2263,11 @@
|
||||||
"@jridgewell/sourcemap-codec": "^1.4.14"
|
"@jridgewell/sourcemap-codec": "^1.4.14"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@kurkle/color": {
|
||||||
|
"version": "0.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.2.tgz",
|
||||||
|
"integrity": "sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw=="
|
||||||
|
},
|
||||||
"node_modules/@mrmlnc/readdir-enhanced": {
|
"node_modules/@mrmlnc/readdir-enhanced": {
|
||||||
"version": "2.2.1",
|
"version": "2.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz",
|
||||||
|
@ -4686,9 +4691,15 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/chart.js": {
|
"node_modules/chart.js": {
|
||||||
"version": "3.9.1",
|
"version": "4.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.9.1.tgz",
|
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.1.tgz",
|
||||||
"integrity": "sha512-Ro2JbLmvg83gXF5F4sniaQ+lTbSv18E+TIf2cOeiH1Iqd2PGFOtem+DUufMZsCJwFE7ywPOpfXFBwRTGq7dh6w=="
|
"integrity": "sha512-C74QN1bxwV1v2PEujhmKjOZ7iUM4w6BWs23Md/6aOZZSlwMzeCIDGuZay++rBgChYru7/+QFeoQW0fQoP534Dg==",
|
||||||
|
"dependencies": {
|
||||||
|
"@kurkle/color": "^0.3.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"pnpm": ">=7"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"node_modules/chokidar": {
|
"node_modules/chokidar": {
|
||||||
"version": "3.5.3",
|
"version": "3.5.3",
|
||||||
|
@ -13398,12 +13409,12 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/vue-chartjs": {
|
"node_modules/vue-chartjs": {
|
||||||
"version": "4.1.2",
|
"version": "5.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/vue-chartjs/-/vue-chartjs-4.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/vue-chartjs/-/vue-chartjs-5.2.0.tgz",
|
||||||
"integrity": "sha512-QSggYjeFv/L4jFSBQpX8NzrAvX0B+Ha6nDgxkTG8tEXxYOOTwKI4phRLe+B4f+REnkmg7hgPY24R0cixZJyXBg==",
|
"integrity": "sha512-d3zpKmGZr2OWHQ1xmxBcAn5ShTG917+/UCLaSpaCDDqT0U7DBsvFzTs69ZnHCgKoXT55GZDW8YEj9Av+dlONLA==",
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"chart.js": "^3.7.0",
|
"chart.js": "^4.1.1",
|
||||||
"vue": "^3.0.0-0 || ^2.6.0"
|
"vue": "^3.0.0-0 || ^2.7.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/vue-codemirror": {
|
"node_modules/vue-codemirror": {
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
"@vueuse/components": "^10.5.0",
|
"@vueuse/components": "^10.5.0",
|
||||||
"@vueuse/core": "^10.5.0",
|
"@vueuse/core": "^10.5.0",
|
||||||
"axios": "^0.21.1",
|
"axios": "^0.21.1",
|
||||||
"chart.js": "^3.7.1",
|
"chart.js": "^4.4.0",
|
||||||
"clone-deep": "^4.0.1",
|
"clone-deep": "^4.0.1",
|
||||||
"date-fns": "^2.28.0",
|
"date-fns": "^2.28.0",
|
||||||
"debounce": "^1.2.1",
|
"debounce": "^1.2.1",
|
||||||
|
@ -29,7 +29,7 @@
|
||||||
"tinymotion": "^0.2.0",
|
"tinymotion": "^0.2.0",
|
||||||
"vform": "^2.1.1",
|
"vform": "^2.1.1",
|
||||||
"vue": "^3.2.13",
|
"vue": "^3.2.13",
|
||||||
"vue-chartjs": "^4.1.0",
|
"vue-chartjs": "^5.2.0",
|
||||||
"vue-codemirror": "^4.0.6",
|
"vue-codemirror": "^4.0.6",
|
||||||
"vue-confetti": "^2.3.0",
|
"vue-confetti": "^2.3.0",
|
||||||
"vue-country-flag-next": "^2.3.2",
|
"vue-country-flag-next": "^2.3.2",
|
||||||
|
|
|
@ -50,7 +50,9 @@ export default {
|
||||||
bottom: false,
|
bottom: false,
|
||||||
left: false
|
left: false
|
||||||
},
|
},
|
||||||
debounceTimeout: null
|
debounceTimeout: null,
|
||||||
|
scrollContainerObserver: null,
|
||||||
|
wrapObserver: null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted () {
|
mounted () {
|
||||||
|
@ -60,20 +62,19 @@ export default {
|
||||||
const scrollContainerObserver = newResizeObserver(this.toggleShadow)
|
const scrollContainerObserver = newResizeObserver(this.toggleShadow)
|
||||||
if (scrollContainerObserver) {
|
if (scrollContainerObserver) {
|
||||||
scrollContainerObserver.observe(this.$refs.scrollContainer)
|
scrollContainerObserver.observe(this.$refs.scrollContainer)
|
||||||
// Cleanup when the component is unmounted.
|
|
||||||
this.$once('hook:unmounted', () => scrollContainerObserver.disconnect())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recalculate the container dimensions when the wrapper is resized.
|
// Recalculate the container dimensions when the wrapper is resized.
|
||||||
const wrapObserver = newResizeObserver(this.calcDimensions)
|
this.wrapObserver = newResizeObserver(this.calcDimensions)
|
||||||
if (wrapObserver) {
|
if (this.wrapObserver) {
|
||||||
wrapObserver.observe(this.$el)
|
this.wrapObserver.observe(this.$el)
|
||||||
// Cleanup when the component is unmounted.
|
|
||||||
this.$once('hook:unmounted', () => wrapObserver.disconnect())
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
unmounted () {
|
unmounted () {
|
||||||
window.removeEventListener('resize', this.calcDimensions)
|
window.removeEventListener('resize', this.calcDimensions)
|
||||||
|
// Cleanup when the component is unmounted.
|
||||||
|
this.wrapObserver.disconnect()
|
||||||
|
this.scrollContainerObserver.disconnect()
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
async calcDimensions () {
|
async calcDimensions () {
|
||||||
|
|
|
@ -20,15 +20,15 @@
|
||||||
</div>
|
</div>
|
||||||
<loader v-else-if="isLoading" class="h-6 w-6 text-nt-blue mx-auto" />
|
<loader v-else-if="isLoading" class="h-6 w-6 text-nt-blue mx-auto" />
|
||||||
<LineChart v-else
|
<LineChart v-else
|
||||||
:chart-options="chartOptions"
|
:options="chartOptions"
|
||||||
:chart-data="chartData"
|
:data="chartData"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import { Line as LineChart } from 'vue-chartjs/legacy'
|
import { Line as LineChart } from 'vue-chartjs'
|
||||||
import {
|
import {
|
||||||
Chart as ChartJS,
|
Chart as ChartJS,
|
||||||
Title,
|
Title,
|
||||||
|
@ -93,7 +93,7 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
responsive: true,
|
responsive: true,
|
||||||
maintainAspectRatio: false
|
maintainAspectRatio: true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -40,19 +40,19 @@
|
||||||
</div>
|
</div>
|
||||||
</modal>
|
</modal>
|
||||||
|
|
||||||
<loader v-if="!form || isLoading" class="h-6 w-6 text-nt-blue mx-auto" />
|
<loader v-if="!form || !formInitDone" class="h-6 w-6 text-nt-blue mx-auto" />
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<div class="flex flex-wrap items-end">
|
<div v-if="form && tableData.length > 0" class="flex flex-wrap items-end">
|
||||||
<div class="flex-grow">
|
<div class="flex-grow">
|
||||||
<text-input class="w-64" :form="searchForm" name="search" placeholder="Search..." />
|
<text-input class="w-64" :form="searchForm" name="search" placeholder="Search..." />
|
||||||
</div>
|
</div>
|
||||||
<div class="font-semibold flex gap-4">
|
<div class="font-semibold flex gap-4">
|
||||||
<p v-if="form && !isLoading && formInitDone" class="float-right text-xs uppercase mb-2">
|
<p class="float-right text-xs uppercase mb-2">
|
||||||
<a
|
<a
|
||||||
href="javascript:void(0);" class="text-gray-500" @click="showColumnsModal=true"
|
href="javascript:void(0);" class="text-gray-500" @click="showColumnsModal=true"
|
||||||
>Display columns</a>
|
>Display columns</a>
|
||||||
</p>
|
</p>
|
||||||
<p v-if="form && !isLoading && tableData.length > 0" class="text-right text-xs uppercase">
|
<p class="text-right text-xs uppercase">
|
||||||
<a
|
<a
|
||||||
:href="exportUrl" target="_blank"
|
:href="exportUrl" target="_blank"
|
||||||
>Export as CSV</a>
|
>Export as CSV</a>
|
||||||
|
@ -101,7 +101,6 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
formInitDone: false,
|
formInitDone: false,
|
||||||
|
@ -153,7 +152,7 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
form () {
|
'form.id' () {
|
||||||
if (this.form === null) {
|
if (this.form === null) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -167,7 +166,7 @@ export default {
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
initFormStructure () {
|
initFormStructure () {
|
||||||
if (!this.form || this.formInitDone) {
|
if (!this.form || !this.form.properties || this.formInitDone) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -215,6 +214,7 @@ export default {
|
||||||
const resData = response.data
|
const resData = response.data
|
||||||
|
|
||||||
this.tableData = this.tableData.concat(resData.data.map((record) => record.data))
|
this.tableData = this.tableData.concat(resData.data.map((record) => record.data))
|
||||||
|
this.dataChanged()
|
||||||
|
|
||||||
if (this.currentPage < resData.meta.last_page) {
|
if (this.currentPage < resData.meta.last_page) {
|
||||||
this.currentPage += 1
|
this.currentPage += 1
|
||||||
|
|
|
@ -182,7 +182,9 @@ export default {
|
||||||
mounted () {
|
mounted () {
|
||||||
const parent = document.getElementById('table-page')
|
const parent = document.getElementById('table-page')
|
||||||
this.tableHash = cyrb53(JSON.stringify(this.form.properties))
|
this.tableHash = cyrb53(JSON.stringify(this.form.properties))
|
||||||
parent.addEventListener('scroll', this.handleScroll, { passive: true })
|
if (parent) {
|
||||||
|
parent.addEventListener('scroll', this.handleScroll, { passive: true })
|
||||||
|
}
|
||||||
window.addEventListener('resize', this.handleScroll)
|
window.addEventListener('resize', this.handleScroll)
|
||||||
this.onStructureChange()
|
this.onStructureChange()
|
||||||
this.handleScroll()
|
this.handleScroll()
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<span class="-mb-2" v-if="value">
|
<span v-if="value" class="-mb-2">
|
||||||
<template v-if="valueIsObject">
|
<template v-if="valueIsObject">
|
||||||
<open-tag v-for="val,index in value" :key="index" :opt="val" />
|
<open-tag v-for="(val,index) in value" :key="index+val" :opt="val" />
|
||||||
</template>
|
</template>
|
||||||
<open-tag v-else :opt="value" />
|
<open-tag v-else :opt="value" />
|
||||||
</span>
|
</span>
|
||||||
|
|
|
@ -59,7 +59,9 @@
|
||||||
</span>
|
</span>
|
||||||
<span>- Edited {{ form.last_edited_human }}</span>
|
<span>- Edited {{ form.last_edited_human }}</span>
|
||||||
</p>
|
</p>
|
||||||
<div v-if="['draft','closed'].includes(form.visibility) || (form.tags && form.tags.length > 0)" class="mt-2 flex items-center flex-wrap gap-3">
|
<div v-if="['draft','closed'].includes(form.visibility) || (form.tags && form.tags.length > 0)"
|
||||||
|
class="mt-2 flex items-center flex-wrap gap-3"
|
||||||
|
>
|
||||||
<span v-if="form.visibility=='draft'"
|
<span v-if="form.visibility=='draft'"
|
||||||
class="inline-flex items-center rounded-full bg-yellow-100 px-2 py-1 text-xs font-medium text-yellow-600 ring-1 ring-inset ring-gray-500/10 dark:text-white dark:bg-gray-700"
|
class="inline-flex items-center rounded-full bg-yellow-100 px-2 py-1 text-xs font-medium text-yellow-600 ring-1 ring-inset ring-gray-500/10 dark:text-white dark:bg-gray-700"
|
||||||
>
|
>
|
||||||
|
@ -110,13 +112,11 @@
|
||||||
<div class="flex bg-white">
|
<div class="flex bg-white">
|
||||||
<div class="w-full md:w-4/5 lg:w-3/5 md:mx-auto md:max-w-4xl px-4">
|
<div class="w-full md:w-4/5 lg:w-3/5 md:mx-auto md:max-w-4xl px-4">
|
||||||
<div class="py-4">
|
<div class="py-4">
|
||||||
<transition name="fade" mode="out-in">
|
<router-view v-slot="{ Component }">
|
||||||
<router-view v-slot="{ Component }">
|
<transition name="page" mode="out-in">
|
||||||
<transition name="page" mode="out-in">
|
<component :is="Component" :form="form" />
|
||||||
<component :is="Component" :form="form" />
|
</transition>
|
||||||
</transition>
|
</router-view>
|
||||||
</router-view>
|
|
||||||
</transition>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -210,7 +210,7 @@ export default {
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
workingForm: {
|
workingForm: {
|
||||||
get () {
|
get () {
|
||||||
return this.workingFormStore.content
|
return this.workingFormStore.content
|
||||||
},
|
},
|
||||||
/* We add a setter */
|
/* We add a setter */
|
||||||
|
|
Loading…
Reference in New Issue