-
-
-
Column {{ index + 1 }}
-
+
+
+
+
+
+
+
+
+
+
Nested Components
+
+
+
+
+
+ Components in this section: {{ (configModel.children || []).length }}
+
+
+ Drag form components into the section to group them here
+
-
-
-
-
-
-
-
-
-
+
+
+ {{ (configModel.children || []).length }} {{ (configModel.children || []).length === 1 ? 'component' : 'components' }}
+
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+ {{ child.props.label || getComponentTypeName(child.type) }}
+
+
+ ({{ child.type }})
+
-
+
+
+
+
+
No components in this section
+
+ Drag components from the sidebar into the section area
+
+
-
-
-
-
No columns defined yet
-
-
-
-
-
-
-
-
@@ -1433,6 +1371,7 @@ const getComponentIcon = (type) => {
heading: 'heroicons:h1',
paragraph: 'heroicons:document-text',
divider: 'heroicons:minus',
+ 'form-section': 'material-symbols:view-module-outline',
'info-display': 'heroicons:information-circle',
'dynamic-list': 'heroicons:list-bullet',
'repeating-table': 'heroicons:table-cells'
@@ -1467,6 +1406,7 @@ const getComponentTypeName = (type) => {
heading: 'Heading Text',
paragraph: 'Paragraph Text',
divider: 'Divider Line',
+ 'form-section': 'Form Section',
'info-display': 'Information Display',
'dynamic-list': 'Dynamic List',
'repeating-table': 'Data Table'
@@ -1501,6 +1441,7 @@ const getComponentDescription = (type) => {
heading: 'Section heading to organize form content',
paragraph: 'Text content for instructions and descriptions',
divider: 'Visual separator to organize form sections',
+ 'form-section': 'Visual container to group related form fields into sections',
'info-display': 'Read-only information display in organized format',
'dynamic-list': 'Dynamic list for displaying and managing items',
'repeating-table': 'Structured table for collecting multiple records with forms'
@@ -1528,14 +1469,14 @@ const showField = (fieldName) => {
if (!props.component) return false
const fieldConfig = {
- label: ['text', 'textarea', 'number', 'email', 'password', 'url', 'tel', 'mask', 'select', 'checkbox', 'radio', 'switch', 'date', 'time', 'datetime-local', 'range', 'color', 'file', 'otp', 'dropzone', 'button', 'dynamic-list', 'repeating-table'],
- name: ['text', 'textarea', 'number', 'email', 'password', 'url', 'tel', 'mask', 'hidden', 'select', 'checkbox', 'radio', 'switch', 'date', 'time', 'datetime-local', 'range', 'color', 'file', 'otp', 'dropzone', 'button', 'dynamic-list', 'repeating-table'],
+ label: ['text', 'textarea', 'number', 'email', 'password', 'url', 'tel', 'mask', 'select', 'checkbox', 'radio', 'switch', 'date', 'time', 'datetime-local', 'range', 'color', 'file', 'otp', 'dropzone', 'button', 'form-section', 'dynamic-list', 'repeating-table'],
+ name: ['text', 'textarea', 'number', 'email', 'password', 'url', 'tel', 'mask', 'hidden', 'select', 'checkbox', 'radio', 'switch', 'date', 'time', 'datetime-local', 'range', 'color', 'file', 'otp', 'dropzone', 'button', 'form-section', 'dynamic-list', 'repeating-table'],
placeholder: ['text', 'textarea', 'number', 'email', 'password', 'url', 'tel', 'mask', 'select', 'dynamic-list'],
- help: ['text', 'textarea', 'number', 'email', 'password', 'url', 'tel', 'mask', 'hidden', 'select', 'checkbox', 'radio', 'switch', 'date', 'time', 'datetime-local', 'range', 'color', 'file', 'otp', 'dropzone', 'button', 'dynamic-list', 'repeating-table'],
+ help: ['text', 'textarea', 'number', 'email', 'password', 'url', 'tel', 'mask', 'hidden', 'select', 'checkbox', 'radio', 'switch', 'date', 'time', 'datetime-local', 'range', 'color', 'file', 'otp', 'dropzone', 'button', 'form-section', 'dynamic-list', 'repeating-table'],
value: ['heading', 'paragraph', 'hidden'],
- width: ['text', 'textarea', 'number', 'email', 'password', 'url', 'tel', 'mask', 'select', 'checkbox', 'radio', 'switch', 'date', 'time', 'datetime-local', 'range', 'color', 'file', 'otp', 'dropzone', 'button', 'heading', 'paragraph', 'info-display', 'dynamic-list', 'repeating-table'],
+ width: ['text', 'textarea', 'number', 'email', 'password', 'url', 'tel', 'mask', 'select', 'checkbox', 'radio', 'switch', 'date', 'time', 'datetime-local', 'range', 'color', 'file', 'otp', 'dropzone', 'button', 'heading', 'paragraph', 'form-section', 'info-display', 'dynamic-list', 'repeating-table'],
options: ['select', 'checkbox', 'radio'],
- conditionalLogic: ['text', 'textarea', 'number', 'email', 'password', 'url', 'tel', 'select', 'checkbox', 'radio', 'switch', 'date', 'time', 'datetime-local', 'range', 'color', 'file', 'dynamic-list', 'repeating-table']
+ conditionalLogic: ['text', 'textarea', 'number', 'email', 'password', 'url', 'tel', 'select', 'checkbox', 'radio', 'switch', 'date', 'time', 'datetime-local', 'range', 'color', 'file', 'form-section', 'dynamic-list', 'repeating-table']
}
return fieldConfig[fieldName]?.includes(props.component.type) || false
@@ -1544,7 +1485,7 @@ const showField = (fieldName) => {
const hasOptions = computed(() => showField('options'))
const hasSpecificSettings = computed(() => {
if (!props.component) return false
- const specificTypes = ['mask', 'otp', 'dropzone', 'range', 'heading', 'paragraph', 'button', 'dynamic-list', 'repeating-table']
+ const specificTypes = ['mask', 'otp', 'dropzone', 'range', 'heading', 'paragraph', 'button', 'form-section', 'dynamic-list', 'repeating-table']
return specificTypes.includes(props.component.type)
})
@@ -1704,7 +1645,16 @@ watch(() => props.component, (newComponent) => {
}
}, { immediate: true })
-// Methods
+// Methods - Define resetValidationState first before it's used above
+const resetValidationState = () => {
+ hasLengthValidation.value = false
+ hasNumberValidation.value = false
+ minLength.value = null
+ maxLength.value = null
+ minNumber.value = null
+ maxNumber.value = null
+}
+
const updateValidation = (rule, enabled) => {
let current = configModel.value.validation || ''
const rules = current.split('|').filter(r => r && r !== rule)
@@ -1716,15 +1666,6 @@ const updateValidation = (rule, enabled) => {
configModel.value.validation = rules.join('|')
}
-const resetValidationState = () => {
- hasLengthValidation.value = false
- hasNumberValidation.value = false
- minLength.value = null
- maxLength.value = null
- minNumber.value = null
- maxNumber.value = null
-}
-
const setComponentWidth = (percentage, gridColumns) => {
configModel.value.width = `${percentage}%`
configModel.value.gridColumn = `span ${gridColumns}`
@@ -1921,6 +1862,12 @@ const removeColumnOption = (columnIndex, optionIndex) => {
configModel.value.columns[columnIndex].options.splice(optionIndex, 1)
}
}
+
+const removeNestedComponent = (index) => {
+ if (configModel.value.children) {
+ configModel.value.children.splice(index, 1)
+ }
+}
diff --git a/prisma/json/json-schema.json b/prisma/json/json-schema.json
index 321d8ec..5125336 100644
--- a/prisma/json/json-schema.json
+++ b/prisma/json/json-schema.json
@@ -63,6 +63,18 @@
],
"format": "date-time"
},
+ "caseInstance": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/caseInstance"
+ }
+ },
+ "caseTimeline": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/caseTimeline"
+ }
+ },
"forms": {
"type": "array",
"items": {
@@ -87,6 +99,12 @@
"$ref": "#/definitions/processHistory"
}
},
+ "task": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/task"
+ }
+ },
"userrole": {
"type": "array",
"items": {
@@ -473,6 +491,12 @@
],
"format": "date-time"
},
+ "caseInstance": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/caseInstance"
+ }
+ },
"creator": {
"anyOf": [
{
diff --git a/prisma/schema.prisma b/prisma/schema.prisma
index d26580d..b56d256 100644
--- a/prisma/schema.prisma
+++ b/prisma/schema.prisma
@@ -23,10 +23,13 @@ model user {
userStatus String? @db.VarChar(255)
userCreatedDate DateTime? @db.DateTime(0)
userModifiedDate DateTime? @db.DateTime(0)
+ caseInstance caseInstance[]
+ caseTimeline caseTimeline[]
forms form[] @relation("FormCreator")
formHistoryEntries formHistory[]
processes process[] @relation("ProcessCreator")
processHistoryEntries processHistory[]
+ task task[]
userrole userrole[]
startedCases caseInstance[] @relation("CaseStartedBy")
assignedTasks task[] @relation("TaskAssignedTo")
@@ -121,6 +124,7 @@ model process {
processVariables Json?
templateCategory String? @db.VarChar(100)
processDeletedDate DateTime? @db.DateTime(0)
+ caseInstance caseInstance[]
creator user? @relation("ProcessCreator", fields: [processCreatedBy], references: [userID])
history processHistory[] @relation("ProcessHistoryEntries")
cases caseInstance[]