Merge branch 'main' into new-ui

This commit is contained in:
Julien Nahum
2022-10-18 08:49:21 +02:00
28 changed files with 271 additions and 95 deletions

View File

@@ -1,7 +1,7 @@
<template>
<div :class="wrapperClass">
<v-checkbox :id="id?id:name" v-model="compVal" :disabled="disabled" :name="name" @input="$emit('input',$event)">
{{ label }}
{{ label }} <span v-if="required" class="text-red-500 required-dot">*</span>
</v-checkbox>
<small v-if="help" :class="theme.default.help">
<slot name="help">{{ help }}</slot>

View File

@@ -6,6 +6,9 @@
{{ label }}
<span v-if="required" class="text-red-500 required-dot">*</span>
</label>
<small v-if="help" :class="theme.SelectInput.help" class="block mb-2">
<slot name="help">{{ help }}</slot>
</small>
<loader v-if="loading" key="loader" class="h-6 w-6 text-nt-blue mx-auto" />
<div v-for="(option, index) in options" v-else :key="option[optionKey]"
@@ -22,9 +25,6 @@
</div>
</div>
<small v-if="help" :class="theme.SelectInput.help">
<slot name="help">{{ help }}</slot>
</small>
<has-error v-if="hasValidation" :form="form" :field="name" />
</div>
</template>

View File

@@ -0,0 +1,31 @@
<template>
<div :class="wrapperClass">
<div class="flex">
<v-switch :id="id?id:name" v-model="compVal" class="inline-block mr-2" :disabled="disabled" :name="name" @input="$emit('input',$event)" />
<span>{{ label }} <span v-if="required" class="text-red-500 required-dot">*</span></span>
</div>
<small v-if="help" :class="theme.default.help">
<slot name="help">{{ help }}</slot>
</small>
<has-error v-if="hasValidation" :form="form" :field="name" />
</div>
</template>
<script>
import inputMixin from '~/mixins/forms/input'
import VSwitch from './components/VSwitch'
export default {
name: 'ToggleSwitchInput',
components: { VSwitch },
mixins: [inputMixin],
props: {},
mounted () {
this.compVal = !!this.compVal
this.$emit('input', !!this.compVal)
}
}
</script>

View File

@@ -1,42 +1,15 @@
<template>
<div>
<Motion
v-model="value"
:options="{
duration: 150,
}"
:trigger="[
'bg-gray-200 border-gray-300 duration-100 dark:bg-gray-700 dark:border-gray-600',
'bg-gray-200 dark:bg-gray-700',
'bg-nt-blue border-nt-blue',
'bg-nt-blue duration-100',
]"
class="inline-flex items-center h-6 w-12 p-1 border rounded-full cursor-pointer focus:outline-none"
@click="$emit('input',!internalValue)"
>
<Motion
v-model="internalValue"
tag="span"
:options="{
duration: 150,
}"
:trigger="[
'translate-x-0 duration-150',
'rounded-2xl scale-75 duration-100',
'translate-x-6 duration-100',
'scale-100 duration-150',
]"
class="inline-block h-4 w-4 rounded-full bg-white dark:bg-gray-500 shadow"
/>
</Motion>
<div @click="onClick">
<div class="inline-flex items-center h-6 w-12 p-1 bg-gray-300 border rounded-full cursor-pointer focus:outline-none transition-all transform ease-in-out duration-100" :class="{'bg-nt-blue': internalValue}">
<div class="inline-block h-4 w-4 rounded-full bg-white shadow transition-all transform ease-in-out duration-150 rounded-2xl scale-100" :class="{'translate-x-5.5': internalValue}" />
</div>
</div>
</template>
<script>
import Motion from 'tinymotion'
export default {
name: 'VSwitch',
components: { Motion },
components: { },
props: {
value: { type: Boolean, default: false }
@@ -48,14 +21,7 @@ export default {
}
},
computed: {
sizeClasses () {
if (this.size === 'small') {
return 'w-3 h-3'
}
return 'w-5 h-5'
}
},
computed: {},
watch: {
value (val) {
@@ -68,12 +34,10 @@ export default {
},
methods: {
onClick () {
this.$emit('input', !this.internalValue)
this.internalValue = !this.internalValue
}
}
}
</script>
<style scoped>
.translate-x-6 {
--tw-translate-x: 1.4rem !important;
}
</style>
</script>

View File

@@ -16,6 +16,7 @@ import ImageInput from './ImageInput'
import DateInput from './DateInput';
import RatingInput from './RatingInput';
import FlatSelectInput from './FlatSelectInput';
import ToggleSwitchInput from './ToggleSwitchInput';
// Components that are registered globaly.
[
@@ -34,7 +35,8 @@ import FlatSelectInput from './FlatSelectInput';
RichTextAreaInput,
DateInput,
RatingInput,
FlatSelectInput
FlatSelectInput,
ToggleSwitchInput
].forEach(Component => {
Vue.component(Component.name, Component)
})

View File

@@ -317,6 +317,9 @@ export default {
if (['select', 'multi_select'].includes(field.type) && field.without_dropdown) {
return 'FlatSelectInput'
}
if (field.type === 'checkbox' && field.use_toggle_switch) {
return 'ToggleSwitchInput'
}
return this.fieldComponents[field.type]
},
getFieldClasses (field) {

View File

@@ -2,11 +2,41 @@
<div
class="my-4 w-full mx-auto">
<h3 class="font-semibold mb-4">
Form Submissions <span v-if="form && !isLoading && tableData.length > 0"
class="text-right text-xs uppercase mb-2">
- <a :href="exportUrl" target="_blank">Export as CSV</a>
</span>
Form Submissions
<span v-if="form && !isLoading && tableData.length > 0" class="text-right text-xs uppercase mb-2"> - <a :href="exportUrl" target="_blank">Export as CSV</a></span>
<span v-if="form && !isLoading && formInitDone" class="float-right text-xs uppercase mb-2"> <a href="javascript:void(0);" @click="showColumnsModal=true">Display columns</a></span>
</h3>
<!-- Table columns modal -->
<modal :show="showColumnsModal" @close="showColumnsModal=false">
<div class="-m-6">
<div class="px-6 py-3">
<h2 class="text-nt-blue text-3xl font-bold">
Display columns
</h2>
</div>
<div class="border-t py-4 px-6">
<template v-if="properties.length > 0">
<h4 class="font-bold mb-2">Form Fields</h4>
<div v-for="field in properties" :key="field.id" class="p-2 border">
{{ field.name }}
<v-switch v-model="displayColumns[field.id]" @input="onChangeDisplayColumns" class="float-right" />
</div>
</template>
<template v-if="removed_properties.length > 0">
<h4 class="font-bold mb-2 mt-4">Removed Fields</h4>
<div v-for="field in removed_properties" :key="field.id" class="p-2 border">
{{ field.name }}
<v-switch v-model="displayColumns[field.id]" @input="onChangeDisplayColumns" class="float-right" />
</div>
</template>
</div>
<div class="flex justify-end mt-4 pb-5 px-6">
<v-button color="gray" shade="light" @click="showColumnsModal=false">Close</v-button>
</div>
</div>
</modal>
<loader v-if="!form || isLoading" class="h-6 w-6 text-nt-blue mx-auto"/>
<div v-else>
<scroll-shadow
@@ -33,10 +63,11 @@ import axios from 'axios'
import ScrollShadow from '../../../common/ScrollShadow'
import OpenTable from '../../tables/OpenTable'
import clonedeep from "clone-deep";
import VSwitch from '../../../forms/components/VSwitch'
export default {
name: 'FormSubmissions',
components: {ScrollShadow, OpenTable},
components: {ScrollShadow, OpenTable, VSwitch},
props: {},
data() {
return {
@@ -45,6 +76,10 @@ export default {
tableData: [],
currentPage: 1,
fullyLoaded: false,
showColumnsModal: false,
properties: [],
removed_properties: [],
displayColumns: {},
}
},
mounted() {
@@ -69,18 +104,6 @@ export default {
this.$store.commit('open/working_form/set', value)
}
},
tableStructure() {
if (!this.form) {
return []
}
let tmp = this.form.properties.filter(property => !property.hasOwnProperty('hidden') || !property.hidden)
tmp.push({
"name": "Create Date",
"id": "create_date",
"type": "date"
});
return tmp
},
exportUrl() {
if (!this.form) {
return ''
@@ -104,6 +127,20 @@ export default {
})
this.$set(this.form, 'properties', columns)
this.formInitDone = true
this.properties = clonedeep(this.form.properties)
this.removed_properties = clonedeep(this.form.removed_properties)
// Get display columns from local storage
const tmpColumns = window.localStorage.getItem('display-columns-formid-'+this.form.id)
if(tmpColumns !== null && tmpColumns){
this.displayColumns = JSON.parse(tmpColumns)
this.onChangeDisplayColumns()
}else{
this.form.properties.forEach((field) => {
this.displayColumns[field.id] = true
})
}
},
getSubmissionsData() {
if (!this.form || this.fullyLoaded) {
@@ -131,6 +168,13 @@ export default {
this.$refs.shadows.toggleShadow()
this.$refs.shadows.calcDimensions()
},
onChangeDisplayColumns(){
window.localStorage.setItem('display-columns-formid-'+this.form.id, JSON.stringify(this.displayColumns))
const final_properties = this.properties.concat(this.removed_properties).filter((field) => {
return this.displayColumns[field.id] === true
})
this.$set(this.form, 'properties', final_properties)
}
},
}
</script>

View File

@@ -46,7 +46,7 @@
>
<img alt="Logo Picture" :src="coverPictureSrc(form.logo_picture)"
:class="{'top-5':!form.cover_picture, '-top-10':form.cover_picture}"
class="w-20 h-20 absolute left-5 transition-all"
class="w-20 h-20 object-contain absolute left-5 transition-all"
>
</div>
</div>

View File

@@ -27,6 +27,11 @@
placeholder="Select Tag(s)" :multiple="true" :allowCreation="true"
:options="allTagsOptions"
/>
<select-input name="visibility" label="Visibility" :form="form" class="mt-3 mb-6"
help="Only public form will be accessible"
placeholder="Select Visibility" :required="true"
:options="visibilityOptions"
/>
<button
v-if="copyFormOptions.length > 0"
class="group mt-3 cursor-pointer relative w-full rounded-lg border-transparent flex-1 appearance-none border border-gray-300 dark:border-gray-600 w-full py-2 px-4 bg-white text-gray-700 dark:bg-notion-dark-light dark:text-gray-300 dark:placeholder-gray-500 placeholder-gray-400 shadow-sm text-base focus:outline-none focus:ring-2 focus:border-transparent focus:ring-opacity-100"
@@ -86,7 +91,17 @@ export default {
data () {
return {
showCopyFormSettingsModal: false,
copyFormId: null
copyFormId: null,
visibilityOptions: [
{
name: "Public",
value: "public"
},
{
name: "Draft (form won't be accessible)",
value: "draft"
}
]
}
},

View File

@@ -37,6 +37,24 @@
</v-checkbox>
</div>
<!-- Checkbox -->
<div v-if="field.type === 'checkbox'" class="-mx-4 sm:-mx-6 p-5 border-b">
<h3 class="font-semibold block text-lg">
Checkbox
</h3>
<p class="text-gray-400 mb-5">
Advanced options for checkbox.
</p>
<v-checkbox v-model="field.use_toggle_switch" class="mt-4"
name="use_toggle_switch" help=""
>
Use toggle switch
</v-checkbox>
<p class="text-gray-400 mb-5">
If enabled, checkbox will be replaced with a toggle switch
</p>
</div>
<!-- File Uploads -->
<div v-if="field.type === 'files'" class="-mx-4 sm:-mx-6 p-5 border-b">
<h3 class="font-semibold block text-lg">