diff --git a/components/process-flow/ApiNodeConfiguration.vue b/components/process-flow/ApiNodeConfiguration.vue
index c5214a8..4de51a3 100644
--- a/components/process-flow/ApiNodeConfiguration.vue
+++ b/components/process-flow/ApiNodeConfiguration.vue
@@ -172,6 +172,7 @@
v-model="localNodeData.outputVariable"
:availableVariables="availableVariables"
:allowCreate="true"
+ :allowObjectPath="false"
@change="saveChanges"
/>
@@ -188,6 +189,7 @@
v-model="localNodeData.errorVariable"
:availableVariables="availableVariables"
:allowCreate="true"
+ :allowObjectPath="false"
@change="saveChanges"
/>
diff --git a/components/process-flow/VariableBrowser.vue b/components/process-flow/VariableBrowser.vue
index 41d9aa3..0903148 100644
--- a/components/process-flow/VariableBrowser.vue
+++ b/components/process-flow/VariableBrowser.vue
@@ -4,7 +4,7 @@
@@ -995,6 +1095,23 @@ const pendingNavigation = ref(null);
const navigationTarget = ref(null);
const activeSettingsTab = ref('info');
+// Helper function to get submit button CSS classes and styles based on category and color
+const getSubmitButtonStyles = (category, color) => {
+ const baseClasses = 'px-4 py-2 rounded font-medium transition-all duration-200 text-white border-0';
+
+ // Use CSS custom properties from theme.css with opacity based on category
+ const opacity = category === 'primary' ? '1' : '0.8';
+ const hoverOpacity = category === 'primary' ? '0.9' : '0.7';
+
+ return {
+ classes: baseClasses,
+ style: {
+ backgroundColor: `rgba(var(--color-${color}), ${opacity})`,
+ '--hover-bg': `rgba(var(--color-${color}), ${hoverOpacity})`
+ }
+ };
+};
+
// Responsive device preview state
const selectedDevice = ref('Desktop');
const deviceSizes = ref([
@@ -1032,6 +1149,7 @@ const conditionalLogicEngine = ref(null);
// Settings tabs configuration
const settingsTabs = [
{ key: 'info', label: 'Form Info', icon: 'material-symbols:info-outline' },
+ { key: 'submit', label: 'Submit Button', icon: 'material-symbols:play-arrow' },
{ key: 'javascript', label: 'JavaScript', icon: 'material-symbols:code' },
{ key: 'css', label: 'CSS', icon: 'material-symbols:palette-outline' },
{ key: 'events', label: 'Events', icon: 'material-symbols:event-outline' },
@@ -1062,7 +1180,8 @@ const formJson = computed(() => {
customScript: formStore.formCustomScript,
customCSS: formStore.formCustomCSS,
formEvents: formStore.formEvents,
- scriptMode: formStore.scriptMode
+ scriptMode: formStore.scriptMode,
+ submitButton: formStore.submitButton
};
});
@@ -1269,6 +1388,30 @@ const applyJsonChanges = () => {
formStore.scriptMode = importedJson.scriptMode;
}
+ // Import submit button settings if available
+ if (importedJson.submitButton) {
+ formStore.submitButton = {
+ enabled: importedJson.submitButton.enabled !== undefined ? importedJson.submitButton.enabled : true,
+ label: importedJson.submitButton.label || 'Submit',
+ category: importedJson.submitButton.category || 'primary',
+ color: importedJson.submitButton.color || 'primary'
+ };
+
+ // Handle backward compatibility with old variant format
+ if (importedJson.submitButton.variant && !importedJson.submitButton.category && !importedJson.submitButton.color) {
+ const variantMapping = {
+ 'primary': { category: 'primary', color: 'primary' },
+ 'secondary': { category: 'secondary', color: 'secondary' },
+ 'success': { category: 'primary', color: 'success' },
+ 'warning': { category: 'primary', color: 'warning' },
+ 'danger': { category: 'primary', color: 'danger' }
+ };
+ const mapping = variantMapping[importedJson.submitButton.variant] || { category: 'primary', color: 'primary' };
+ formStore.submitButton.category = mapping.category;
+ formStore.submitButton.color = mapping.color;
+ }
+ }
+
// Mark as having unsaved changes
formStore.hasUnsavedChanges = true;
@@ -2634,6 +2777,10 @@ const handleFormRestored = (restoredForm) => {
\ No newline at end of file
diff --git a/prisma/json/json-schema.json b/prisma/json/json-schema.json
index de2955f..65e9f23 100644
--- a/prisma/json/json-schema.json
+++ b/prisma/json/json-schema.json
@@ -198,6 +198,16 @@
],
"default": "safe"
},
+ "submitButton": {
+ "type": [
+ "number",
+ "string",
+ "boolean",
+ "object",
+ "array",
+ "null"
+ ]
+ },
"creator": {
"anyOf": [
{
@@ -281,6 +291,16 @@
"null"
]
},
+ "submitButton": {
+ "type": [
+ "number",
+ "string",
+ "boolean",
+ "object",
+ "array",
+ "null"
+ ]
+ },
"versionNumber": {
"type": "integer"
},
diff --git a/prisma/schema.prisma b/prisma/schema.prisma
index a9b05f4..b793d7c 100644
--- a/prisma/schema.prisma
+++ b/prisma/schema.prisma
@@ -64,6 +64,7 @@ model form {
customScript String? @db.LongText
formEvents Json?
scriptMode String? @default("safe") @db.VarChar(20)
+ submitButton Json?
creator user? @relation(fields: [formCreatedBy], references: [userID])
formHistory formHistory[]
task task[]
@@ -83,6 +84,7 @@ model formHistory {
customScript String? @db.LongText
formEvents Json?
scriptMode String? @db.VarChar(20)
+ submitButton Json?
versionNumber Int
changeDescription String? @db.Text
savedBy Int?
diff --git a/server/api/forms/[id].put.js b/server/api/forms/[id].put.js
index 1dd23a2..a66cf59 100644
--- a/server/api/forms/[id].put.js
+++ b/server/api/forms/[id].put.js
@@ -58,6 +58,7 @@ export default defineEventHandler(async (event) => {
customScript: currentForm.customScript,
formEvents: currentForm.formEvents,
scriptMode: currentForm.scriptMode,
+ submitButton: currentForm.submitButton,
versionNumber: nextVersionNumber,
changeDescription: body.changeDescription || null,
savedBy: body.savedBy || currentForm.formCreatedBy,
@@ -104,6 +105,10 @@ export default defineEventHandler(async (event) => {
if (body.scriptMode !== undefined) {
updateData.scriptMode = body.scriptMode;
}
+
+ if (body.submitButton !== undefined) {
+ updateData.submitButton = body.submitButton;
+ }
// Try to update by UUID first
let form;
diff --git a/server/api/forms/create.post.js b/server/api/forms/create.post.js
index 040ec08..5bdeaf0 100644
--- a/server/api/forms/create.post.js
+++ b/server/api/forms/create.post.js
@@ -29,7 +29,8 @@ export default defineEventHandler(async (event) => {
customScript: body.customScript || null,
customCSS: body.customCSS || null,
formEvents: body.formEvents || null,
- scriptMode: body.scriptMode || 'safe'
+ scriptMode: body.scriptMode || 'safe',
+ submitButton: body.submitButton || null
}
});
diff --git a/stores/formBuilder.js b/stores/formBuilder.js
index 0a1b4a2..d3d47a9 100644
--- a/stores/formBuilder.js
+++ b/stores/formBuilder.js
@@ -26,6 +26,14 @@ export const useFormBuilderStore = defineStore('formBuilder', {
},
scriptMode: 'safe', // 'safe' or 'advanced'
+ // Submit button configuration
+ submitButton: {
+ enabled: true,
+ label: 'Submit',
+ category: 'primary', // primary, secondary
+ color: 'primary' // primary, secondary, success, info, warning, danger
+ },
+
// Form preview data
previewFormData: {},
@@ -670,6 +678,7 @@ export const useFormBuilderStore = defineStore('formBuilder', {
customCSS: this.formCustomCSS,
formEvents: this.formEvents,
scriptMode: this.scriptMode,
+ submitButton: this.submitButton,
// Add user info and change description for history tracking
savedBy: 1, // TODO: Get from authenticated user
changeDescription: this.lastChangeDescription || null
@@ -761,6 +770,12 @@ export const useFormBuilderStore = defineStore('formBuilder', {
onValidation: false
};
this.scriptMode = result.form.scriptMode || 'safe';
+ this.submitButton = result.form.submitButton || {
+ enabled: true,
+ label: 'Submit',
+ category: 'primary',
+ color: 'primary'
+ };
// Transform components from DB format to store format
if (Array.isArray(result.form.formComponents)) {