Choose Visible columns & in csv with removed field (#11)

* Choose Visible columns & in csv with removed field

* toggle UI fixes
This commit is contained in:
Chirag 2022-10-17 13:15:28 +05:30 committed by GitHub
parent 993bab7cff
commit 8f528155f5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 92 additions and 66 deletions

View File

@ -35,7 +35,8 @@ class FormSubmissionController extends Controller
foreach ($form->submissions->toArray() as $row) { foreach ($form->submissions->toArray() as $row) {
$formatter = (new FormSubmissionFormatter($form, $row['data'])) $formatter = (new FormSubmissionFormatter($form, $row['data']))
->outputStringsOnly() ->outputStringsOnly()
->setEmptyForNoValue(); ->setEmptyForNoValue()
->showRemovedFields();
$tmp = $formatter->getCleanKeyValue(); $tmp = $formatter->getCleanKeyValue();
$tmp['Create Date'] = date("Y-m-d H:i", strtotime($row['created_at'])); $tmp['Create Date'] = date("Y-m-d H:i", strtotime($row['created_at']));
$allRows[] = $tmp; $allRows[] = $tmp;

View File

@ -45,6 +45,7 @@ class FormResource extends JsonResource
'visibility' => $this->visibility, 'visibility' => $this->visibility,
'notification_emails' => $this->notification_emails, 'notification_emails' => $this->notification_emails,
'slack_webhook_url' => $this->slack_webhook_url, 'slack_webhook_url' => $this->slack_webhook_url,
'removed_properties' => $this->removed_properties
] : []; ] : [];
$baseData = $this->getFilteredFormData(parent::toArray($request), $this->userIsFormOwner()); $baseData = $this->getFilteredFormData(parent::toArray($request), $this->userIsFormOwner());

View File

@ -27,6 +27,8 @@ class FormSubmissionFormatter
private $setEmptyForNoValue = false; private $setEmptyForNoValue = false;
private $showRemovedFields = false;
public function __construct(private Form $form, private array $formData) public function __construct(private Form $form, private array $formData)
{ {
} }
@ -55,6 +57,12 @@ class FormSubmissionFormatter
return $this; return $this;
} }
public function showRemovedFields()
{
$this->showRemovedFields = true;
return $this;
}
/** /**
* Return a nice "FieldName": "Field Response" array * Return a nice "FieldName": "Field Response" array
* - If createLink enabled, returns html link for emails and links * - If createLink enabled, returns html link for emails and links
@ -63,10 +71,15 @@ class FormSubmissionFormatter
public function getCleanKeyValue() public function getCleanKeyValue()
{ {
$data = $this->formData; $data = $this->formData;
$fields = $this->form->properties; $fields = ($this->showRemovedFields) ? array_merge($this->form->properties, $this->form->removed_properties) : $this->form->properties;
$returnArray = []; $returnArray = [];
foreach ($fields as &$field) { foreach ($fields as &$field) {
$isRemoved = in_array($field['id'], array_column($this->form->removed_properties, 'id')) ?? false;
if($isRemoved){
$field['name'] = $field['name']." (deleted)";
}
// If not present skip // If not present skip
if (!isset($data[$field['id']])) { if (!isset($data[$field['id']])) {
if ($this->setEmptyForNoValue) { if ($this->setEmptyForNoValue) {

View File

@ -1,42 +1,15 @@
<template> <template>
<div> <div @click="onClick">
<Motion <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}">
v-model="value" <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}" />
:options="{ </div>
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> </div>
</template> </template>
<script> <script>
import Motion from 'tinymotion'
export default { export default {
name: 'VSwitch', name: 'VSwitch',
components: { Motion }, components: { },
props: { props: {
value: { type: Boolean, default: false } value: { type: Boolean, default: false }
@ -48,14 +21,7 @@ export default {
} }
}, },
computed: { computed: {},
sizeClasses () {
if (this.size === 'small') {
return 'w-3 h-3'
}
return 'w-5 h-5'
}
},
watch: { watch: {
value (val) { value (val) {
@ -68,12 +34,10 @@ export default {
}, },
methods: { methods: {
onClick () {
this.$emit('input', !this.internalValue)
this.internalValue = !this.internalValue
}
} }
} }
</script> </script>
<style scoped>
.translate-x-6 {
--tw-translate-x: 1.4rem !important;
}
</style>

View File

@ -2,11 +2,41 @@
<div <div
class="my-4 w-full mx-auto"> class="my-4 w-full mx-auto">
<h3 class="font-semibold mb-4"> <h3 class="font-semibold mb-4">
Form Submissions <span v-if="form && !isLoading && tableData.length > 0" Form Submissions
class="text-right text-xs uppercase mb-2"> <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>
- <a :href="exportUrl" target="_blank">Export as CSV</a> <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>
</span>
</h3> </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"/> <loader v-if="!form || isLoading" class="h-6 w-6 text-nt-blue mx-auto"/>
<div v-else> <div v-else>
<scroll-shadow <scroll-shadow
@ -33,10 +63,11 @@ import axios from 'axios'
import ScrollShadow from '../../../common/ScrollShadow' import ScrollShadow from '../../../common/ScrollShadow'
import OpenTable from '../../tables/OpenTable' import OpenTable from '../../tables/OpenTable'
import clonedeep from "clone-deep"; import clonedeep from "clone-deep";
import VSwitch from '../../../forms/components/VSwitch'
export default { export default {
name: 'FormSubmissions', name: 'FormSubmissions',
components: {ScrollShadow, OpenTable}, components: {ScrollShadow, OpenTable, VSwitch},
props: {}, props: {},
data() { data() {
return { return {
@ -45,6 +76,10 @@ export default {
tableData: [], tableData: [],
currentPage: 1, currentPage: 1,
fullyLoaded: false, fullyLoaded: false,
showColumnsModal: false,
properties: [],
removed_properties: [],
displayColumns: {},
} }
}, },
mounted() { mounted() {
@ -69,18 +104,6 @@ export default {
this.$store.commit('open/working_form/set', value) 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() { exportUrl() {
if (!this.form) { if (!this.form) {
return '' return ''
@ -104,6 +127,20 @@ export default {
}) })
this.$set(this.form, 'properties', columns) this.$set(this.form, 'properties', columns)
this.formInitDone = true 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() { getSubmissionsData() {
if (!this.form || this.fullyLoaded) { if (!this.form || this.fullyLoaded) {
@ -131,6 +168,13 @@ export default {
this.$refs.shadows.toggleShadow() this.$refs.shadows.toggleShadow()
this.$refs.shadows.calcDimensions() 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> </script>

3
tailwind.config.js vendored
View File

@ -40,6 +40,9 @@ module.exports = {
10: '10rem', 10: '10rem',
8: '2rem' 8: '2rem'
}, },
translate: {
5.5: '1.4rem'
},
boxShadow: { boxShadow: {
'inner-notion': '#0f0f0f1a 0px 0px 0px 1px inset', 'inner-notion': '#0f0f0f1a 0px 0px 0px 1px inset',
'focus-notion': '#2eaadcb3 0px 0px 0px 1px inset, #2eaadc66 0px 0px 0px 2px !important' 'focus-notion': '#2eaadcb3 0px 0px 0px 1px inset, #2eaadc66 0px 0px 0px 2px !important'