use hash for field options
This commit is contained in:
@@ -57,7 +57,7 @@ module Api
|
|||||||
schema: [%i[attachment_uuid name]],
|
schema: [%i[attachment_uuid name]],
|
||||||
submitters: [%i[name uuid]],
|
submitters: [%i[name uuid]],
|
||||||
fields: [[:uuid, :submitter_uuid, :name, :type, :required, :readonly, :default_value,
|
fields: [[:uuid, :submitter_uuid, :name, :type, :required, :readonly, :default_value,
|
||||||
{ options: [], areas: [%i[x y w h cell_w attachment_uuid page]] }]]
|
{ options: [%i[value uuid]], areas: [%i[x y w h cell_w attachment_uuid option_uuid page]] }]]
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -99,12 +99,12 @@
|
|||||||
{{ t('select_your_option') }}
|
{{ t('select_your_option') }}
|
||||||
</option>
|
</option>
|
||||||
<option
|
<option
|
||||||
v-for="(option, index) in currentField.options"
|
v-for="option in currentField.options"
|
||||||
:key="index"
|
:key="option.uuid"
|
||||||
:selected="values[currentField.uuid] == option"
|
:selected="values[currentField.uuid] == option.value"
|
||||||
:value="option"
|
:value="option.value"
|
||||||
>
|
>
|
||||||
{{ option }}
|
{{ option.value }}
|
||||||
</option>
|
</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
@@ -119,24 +119,24 @@
|
|||||||
<div class="flex w-full">
|
<div class="flex w-full">
|
||||||
<div class="space-y-3.5 mx-auto">
|
<div class="space-y-3.5 mx-auto">
|
||||||
<div
|
<div
|
||||||
v-for="(option, index) in currentField.options"
|
v-for="option in currentField.options"
|
||||||
:key="index"
|
:key="option.uuid"
|
||||||
>
|
>
|
||||||
<label
|
<label
|
||||||
:for="currentField.uuid + option"
|
:for="option.uuid"
|
||||||
class="flex items-center space-x-3"
|
class="flex items-center space-x-3"
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
:id="currentField.uuid + option"
|
:id="option.uuid"
|
||||||
v-model="values[currentField.uuid]"
|
v-model="values[currentField.uuid]"
|
||||||
type="radio"
|
type="radio"
|
||||||
class="base-radio !h-7 !w-7"
|
class="base-radio !h-7 !w-7"
|
||||||
:name="`values[${currentField.uuid}]`"
|
:name="`values[${currentField.uuid}]`"
|
||||||
:value="option"
|
:value="option.value"
|
||||||
:required="currentField.required"
|
:required="currentField.required"
|
||||||
>
|
>
|
||||||
<span class="text-xl">
|
<span class="text-xl">
|
||||||
{{ option }}
|
{{ option.value }}
|
||||||
</span>
|
</span>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -7,25 +7,25 @@
|
|||||||
<div class="flex w-full">
|
<div class="flex w-full">
|
||||||
<div class="space-y-3.5 mx-auto">
|
<div class="space-y-3.5 mx-auto">
|
||||||
<div
|
<div
|
||||||
v-for="(option, index) in field.options"
|
v-for="option in field.options"
|
||||||
:key="index"
|
:key="option.uuid"
|
||||||
>
|
>
|
||||||
<label
|
<label
|
||||||
:for="field.uuid + option"
|
:for="option.uuid"
|
||||||
class="flex items-center space-x-3"
|
class="flex items-center space-x-3"
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
:id="field.uuid + option"
|
:id="option.uuid"
|
||||||
:ref="setInputRef"
|
:ref="setInputRef"
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
:name="`values[${field.uuid}][]`"
|
:name="`values[${field.uuid}][]`"
|
||||||
:value="option"
|
:value="option.value"
|
||||||
class="base-checkbox !h-7 !w-7"
|
class="base-checkbox !h-7 !w-7"
|
||||||
:checked="(modelValue || []).includes(option)"
|
:checked="(modelValue || []).includes(option.value)"
|
||||||
@change="onChange"
|
@change="onChange"
|
||||||
>
|
>
|
||||||
<span class="text-xl">
|
<span class="text-xl">
|
||||||
{{ option }}
|
{{ option.value }}
|
||||||
</span>
|
</span>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -140,6 +140,7 @@ import FieldSubmitter from './field_submitter'
|
|||||||
import FieldType from './field_type'
|
import FieldType from './field_type'
|
||||||
import Field from './field'
|
import Field from './field'
|
||||||
import { IconX } from '@tabler/icons-vue'
|
import { IconX } from '@tabler/icons-vue'
|
||||||
|
import { v4 } from 'uuid'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'FieldArea',
|
name: 'FieldArea',
|
||||||
@@ -303,7 +304,7 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (['select', 'multiple', 'radio'].includes(this.field.type)) {
|
if (['select', 'multiple', 'radio'].includes(this.field.type)) {
|
||||||
this.field.options ||= ['']
|
this.field.options ||= [{ value: '', uuid: v4() }]
|
||||||
}
|
}
|
||||||
|
|
||||||
(this.field.areas || []).forEach((area) => {
|
(this.field.areas || []).forEach((area) => {
|
||||||
|
|||||||
@@ -429,7 +429,7 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (['select', 'multiple', 'radio'].includes(type)) {
|
if (['select', 'multiple', 'radio'].includes(type)) {
|
||||||
field.options = ['']
|
field.options = [{ value: '', uuid: v4() }]
|
||||||
}
|
}
|
||||||
|
|
||||||
this.drawField = field
|
this.drawField = field
|
||||||
@@ -592,7 +592,7 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (['select', 'multiple', 'radio'].includes(field.type)) {
|
if (['select', 'multiple', 'radio'].includes(field.type)) {
|
||||||
field.options = ['']
|
field.options = [{ value: '', uuid: v4() }]
|
||||||
}
|
}
|
||||||
|
|
||||||
const fieldArea = {
|
const fieldArea = {
|
||||||
|
|||||||
@@ -194,17 +194,19 @@
|
|||||||
<div
|
<div
|
||||||
v-if="field.options"
|
v-if="field.options"
|
||||||
class="border-t border-base-300 mx-2 pt-2 space-y-1.5"
|
class="border-t border-base-300 mx-2 pt-2 space-y-1.5"
|
||||||
|
draggable="true"
|
||||||
|
@dragstart.prevent.stop
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
v-for="(option, index) in field.options"
|
v-for="(option, index) in field.options"
|
||||||
:key="index"
|
:key="option.uuid"
|
||||||
class="flex space-x-1.5 items-center"
|
class="flex space-x-1.5 items-center"
|
||||||
>
|
>
|
||||||
<span class="text-sm w-3.5">
|
<span class="text-sm w-3.5">
|
||||||
{{ index + 1 }}.
|
{{ index + 1 }}.
|
||||||
</span>
|
</span>
|
||||||
<input
|
<input
|
||||||
v-model="field.options[index]"
|
v-model="option.value"
|
||||||
class="w-full input input-primary input-xs text-sm bg-transparent"
|
class="w-full input input-primary input-xs text-sm bg-transparent"
|
||||||
type="text"
|
type="text"
|
||||||
required
|
required
|
||||||
@@ -220,7 +222,7 @@
|
|||||||
<button
|
<button
|
||||||
v-if="field.options"
|
v-if="field.options"
|
||||||
class="text-center text-sm w-full pb-1"
|
class="text-center text-sm w-full pb-1"
|
||||||
@click="[field.options.push(''), save()]"
|
@click="addOption"
|
||||||
>
|
>
|
||||||
+ Add option
|
+ Add option
|
||||||
</button>
|
</button>
|
||||||
@@ -233,6 +235,7 @@
|
|||||||
import Contenteditable from './contenteditable'
|
import Contenteditable from './contenteditable'
|
||||||
import FieldType from './field_type'
|
import FieldType from './field_type'
|
||||||
import { IconShape, IconNewSection, IconTrashX, IconCopy, IconSettings } from '@tabler/icons-vue'
|
import { IconShape, IconNewSection, IconTrashX, IconCopy, IconSettings } from '@tabler/icons-vue'
|
||||||
|
import { v4 } from 'uuid'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'TemplateField',
|
name: 'TemplateField',
|
||||||
@@ -309,6 +312,11 @@ export default {
|
|||||||
closeDropdown () {
|
closeDropdown () {
|
||||||
document.activeElement.blur()
|
document.activeElement.blur()
|
||||||
},
|
},
|
||||||
|
addOption () {
|
||||||
|
this.field.options.push({ value: '', uuid: v4() })
|
||||||
|
|
||||||
|
this.save()
|
||||||
|
},
|
||||||
maybeUpdateOptions () {
|
maybeUpdateOptions () {
|
||||||
delete this.field.default_value
|
delete this.field.default_value
|
||||||
|
|
||||||
@@ -317,7 +325,7 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (['radio', 'multiple', 'select'].includes(this.field.type)) {
|
if (['radio', 'multiple', 'select'].includes(this.field.type)) {
|
||||||
this.field.options ||= ['']
|
this.field.options ||= [{ value: '', uuid: v4() }]
|
||||||
}
|
}
|
||||||
|
|
||||||
(this.field.areas || []).forEach((area) => {
|
(this.field.areas || []).forEach((area) => {
|
||||||
|
|||||||
@@ -252,7 +252,7 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (['select', 'multiple', 'radio'].includes(type)) {
|
if (['select', 'multiple', 'radio'].includes(type)) {
|
||||||
field.options = ['']
|
field.options = [{ value: '', uuid: v4() }]
|
||||||
}
|
}
|
||||||
|
|
||||||
this.fields.push(field)
|
this.fields.push(field)
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class UpdateFieldOptions < ActiveRecord::Migration[7.0]
|
||||||
|
class MigrationTemplate < ApplicationRecord
|
||||||
|
self.table_name = 'templates'
|
||||||
|
end
|
||||||
|
|
||||||
|
class MigrationSubmission < ApplicationRecord
|
||||||
|
self.table_name = 'submissions'
|
||||||
|
end
|
||||||
|
|
||||||
|
# rubocop:disable Metrics
|
||||||
|
def up
|
||||||
|
MigrationTemplate.find_each do |template|
|
||||||
|
next if template.fields.blank?
|
||||||
|
|
||||||
|
template_fields = JSON.parse(template.fields)
|
||||||
|
|
||||||
|
new_fields = template_fields.deep_dup
|
||||||
|
|
||||||
|
new_fields.each do |field|
|
||||||
|
if field['options'].present? && !field['options'].first.is_a?(Hash)
|
||||||
|
field['options'] = field['options'].map { |o| { value: o || '', uuid: SecureRandom.uuid } }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
template.update_columns(fields: new_fields.to_json) if template_fields != new_fields
|
||||||
|
end
|
||||||
|
|
||||||
|
MigrationSubmission.find_each do |submission|
|
||||||
|
next if submission.template_fields.blank?
|
||||||
|
|
||||||
|
template_fields = JSON.parse(submission.template_fields)
|
||||||
|
|
||||||
|
new_fields = template_fields.deep_dup
|
||||||
|
|
||||||
|
new_fields.each do |field|
|
||||||
|
if field['options'].present? && !field['options'].first.is_a?(Hash)
|
||||||
|
field['options'] = field['options'].map { |o| { value: o || '', uuid: SecureRandom.uuid } }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
submission.update_columns(template_fields: new_fields.to_json) if template_fields != new_fields
|
||||||
|
end
|
||||||
|
end
|
||||||
|
# rubocop:enable Metrics
|
||||||
|
|
||||||
|
def down
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
end
|
||||||
+1
-1
@@ -10,7 +10,7 @@
|
|||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema[7.0].define(version: 2023_11_02_171817) do
|
ActiveRecord::Schema[7.0].define(version: 2023_11_12_224432) do
|
||||||
# These are extensions that must be enabled in order to support this database
|
# These are extensions that must be enabled in order to support this database
|
||||||
enable_extension "plpgsql"
|
enable_extension "plpgsql"
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user