Skip to content

Commit

Permalink
Merge pull request #82 from ansibleguy76/release/v4.0.9
Browse files Browse the repository at this point in the history
v4.0.9 into main
  • Loading branch information
ansibleguy76 authored May 7, 2023
2 parents d8e347d + c1dae3d commit bdde059
Show file tree
Hide file tree
Showing 8 changed files with 168 additions and 67 deletions.
19 changes: 18 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [4.0.9] - 2023-05-07

### Added

- model can now be an array
- html field

### Fixed

- form could be executed while non-required fields were being evaluated

### Changed

- expression field can have newlines, they will be removed.

## [4.0.8] - 2023-05-03

### Added
Expand Down Expand Up @@ -484,7 +499,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Allow change password for current local user
- Start tracking versions

[Unreleased]: https://github.com/ansibleguy76/ansibleforms/compare/4.0.8...HEAD
[Unreleased]: https://github.com/ansibleguy76/ansibleforms/compare/4.0.9...HEAD

[4.0.9]: https://github.com/ansibleguy76/ansibleforms/compare/4.0.8...4.0.9

[4.0.8]: https://github.com/ansibleguy76/ansibleforms/compare/4.0.7...4.0.8

Expand Down
4 changes: 2 additions & 2 deletions app_versions.gradle
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
ext.version_code = 40008
ext.version_name = "4.0.8"
ext.version_code = 40009
ext.version_name = "4.0.9"
2 changes: 1 addition & 1 deletion client/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ansible_forms_vue",
"version": "4.0.8",
"version": "4.0.9",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
Expand Down
110 changes: 57 additions & 53 deletions client/src/components/Form.vue
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@
<span v-show="!hideForm" title="Copy form link with values" class="icon is-clickable is-pulled-right has-text-link" @click="getFormUrl()">
<font-awesome-icon icon="link" />
</span>
<span class="icon is-pulled-right">
<font-awesome-icon :icon="loopicon.icon" size="lg" :class="loopicon.color" :spin="loopicon.spin" />
<span class="icon is-pulled-right" v-show="loopbusy">
<font-awesome-icon icon="spinner" size="lg" class="has-text-warning" spin />
</span>
<!-- reload button -->
<button @click="reloadForm" class="button is-white is-small mr-3">
Expand Down Expand Up @@ -67,7 +67,7 @@

<div class="field mt-3">
<!-- field label -->
<label class="label" :class="{'has-text-dark':!field.hide,'has-text-grey':field.hide}">{{ field.label || field.name }} <span v-if="field.required" class="has-text-danger">*</span>
<label v-show="field.type!='html'" class="label" :class="{'has-text-dark':!field.hide,'has-text-grey':field.hide}">{{ field.label || field.name }} <span v-if="field.required" class="has-text-danger">*</span>
<!-- field buttons -->
<span class="is-pulled-right">
<!-- refresh auto -->
Expand Down Expand Up @@ -159,6 +159,8 @@
<div v-if="field.type=='checkbox'">
<BulmaCheckRadio checktype="checkbox" v-model="$v.form[field.name].$model" :name="field.name" :type="{'is-danger is-block':$v.form[field.name].$invalid}" :label="field.placeholder" @change="evaluateDynamicFields(field.name)" />
</div>
<!-- type = html -->
<div class="mt-3" v-if="field.type=='html'" v-html="$v.form[field.name].$model || ''"></div>
<!-- type = enum/query -->
<div v-if="field.type=='query' || field.type=='enum'">
<BulmaAdvancedSelect
Expand Down Expand Up @@ -343,7 +345,7 @@
<div class="columns">
<!-- progress/close button -->
<div class="column">
<button v-if="!!jobResult.message" class="button is-fullwidth has-text-light" @click="resetResult()" :class="{ 'has-background-success' : jobResult.status=='success', 'has-background-warning' : jobResult.status=='warning', 'has-background-danger' : jobResult.status=='error','has-background-info cursor-progress' : jobResult.status=='info' }">
<button v-if="!!jobResult.message" class="button is-fullwidth has-text-light" @click="resetResult()" :class="{ 'has-background-success' : jobResult.status=='success', 'has-background-warning' : jobResult.status=='warning', 'has-background-danger' : jobResult.status=='error','has-background-info cursor-progress' : ['info',''].includes(jobResult.status) }">
<span class="icon" v-if="jobResult.status=='info'"><font-awesome-icon icon="spinner" spin /></span>
<span class="icon" v-if="jobResult.status!='info'"><font-awesome-icon icon="times" /></span>
<span>{{ jobResult.message }}</span>
Expand Down Expand Up @@ -626,14 +628,12 @@
return []
}
},
loopicon(){
if(this.loopdelay==500){
return {icon:['fa-regular','face-smile'],color:"has-text-success",spin:false}
}else{
return {icon:['fa-solid','spinner'],color:"has-text-warning",spin:true}
}
}
loopbusy(){
return this.loopdelay!=500
},
loopdivider(){
return 5000/this.loopdelay
}
},
methods:{
// used for enum field, to know the width of the container
Expand Down Expand Up @@ -1172,6 +1172,7 @@
// console.log("item = " + value)
// console.log(typeof value)
// console.log(testRegex)
value = value.replace(/\n+/g, '') // put everything in 1 line.
matches=[...value.matchAll(testRegex)] // force match array
for(match of matches){
// console.log("-> match : " + match[0] + "->" + match[1])
Expand Down Expand Up @@ -1391,9 +1392,7 @@
if(item.expression && (flag==undefined || ref.hasDefaultDependencies(item.name))){ // if expression and not evaluated yet
// console.log("eval expression " + item.name)
// console.log(`[${item.name}][${flag}] : evaluating`)
if(item.required){
hasUnevaluatedFields=true // set the un-eval flag if this is required
}
hasUnevaluatedFields=true // set the un-eval flag if this is required
// set flag running
ref.setFieldStatus(item.name,"running",false)
placeholderCheck = ref.replacePlaceholders(item) // check and replace placeholders
Expand All @@ -1402,9 +1401,8 @@
if(placeholderCheck.value!=undefined){ // expression is clean ?
// console.log(`[${item.name}] 2 : ${placeholderCheck.value}`)
// allow local run in browser
if(item.runLocal){
if(item.runLocal || item.type=="html"){
// console.log("Running local expression : " + placeholderCheck.value)
var result
try{
// check if direct object attempt
Expand All @@ -1415,7 +1413,7 @@
result=eval(placeholderCheck.value)
}
if(item.type=="expression") Vue.set(ref.form, item.name, result);
if(item.type=="expression" || item.type=="html") Vue.set(ref.form, item.name, result);
if((item.type=="query")||(item.type=="enum")) Vue.set(ref.queryresults, item.name, [].concat(result));
// table is special. if external data is passed. we take that instead of results.
if(item.type=="table" && !ref.defaults(item.name)){
Expand Down Expand Up @@ -1510,9 +1508,7 @@
} else if(item.query && flag==undefined){
// console.log("eval query : " + item.name)
// set flag running
if(item.required){
hasUnevaluatedFields=true
}
hasUnevaluatedFields=true
ref.setFieldStatus(item.name,"running",false)
placeholderCheck = ref.replacePlaceholders(item) // check and replace placeholders
if(placeholderCheck.value!=undefined){ // expression is clean ?
Expand Down Expand Up @@ -1607,39 +1603,44 @@
if(!hasUnevaluatedFields){
ref.canSubmit=true;
if(ref.watchdog>0){
//ref.$toast.info("All fields are found")
// ref.$toast.info("All fields are found")
}
ref.watchdog=0
}
if(ref.jobResult.message=="initializing"){ // has a request been made to execute ?
// ref.$toast.info("Requesting execution")
if(ref.validateForm()){ // form is valid ?
ref.jobResult.message="stabilizing"
// ref.$toast.info("Waiting for form to stabilize")
ref.watchdog=0
}else{
ref.jobResult.message="" // reset status, form not valid
}
ref.jobResult.message="" // immediately reset => we don't want to initialized twice
Vue.nextTick(()=>{ // we want to make sure the the last form action (lostfocus field) is processed
if(ref.validateForm()){ // form is valid ?
ref.jobResult.message="stabilizing"
// ref.$toast.info("Waiting for form to stabilize")
ref.watchdog=0
}else{
ref.jobResult.message="" // reset status, form not valid
}
})
}
if(ref.jobResult.message=="stabilizing"){ // are we waiting to execute ?
if(ref.canSubmit){
ref.jobResult.message="triggering execution"
ref.executeForm()
// ref.$toast.info("Executing form...");ref.jobResult.message=""
}else{
// continue to stabilize
if(ref.watchdog>15){ // is it taking too long ?
if(ref.watchdog>50){ // is it taking too long ?
ref.jobResult.message="" // stop and reset
ref.$toast.warning("It is taking too long to evaluate all fields before run")
ref.$toast.warning("It took too long to evaluate all fields before run.\r\nLet the form stabilize and try again.")
}else{
// ref.$toast.info("Stabalizing form...")
//ref.$toast.info(`Stabilizing form...${ref.watchdog}`)
}
}
}
refreshCounter++;
if(refreshCounter%10==0){
if(refreshCounter%ref.loopdivider==0){
ref.generateJsonOutput() // refresh json output
}
if(ref.watchdog>30 || ref.watchdog==0){
if(ref.watchdog>50 || ref.watchdog==0){
ref.loopdelay=500
}else{
ref.loopdelay=4
Expand Down Expand Up @@ -1815,34 +1816,37 @@
this.currentForm.fields.forEach((item, i) => {
// this.checkDependencies(item) // hide field based on dependency
if(this.visibility[item.name] && !item.noOutput){
var fieldmodel = item.model
var fieldmodel = [].concat(item.model || [])
var outputObject = item.outputObject || item.type=="expression" || item.type=="table" || false
var outputValue = this.form[item.name]
// if no model is given, we assign to the root
if(!outputObject){ // do we need to flatten output ?
outputValue=this.getFieldValue(outputValue,item.valueColumn || "",true)
}
if(fieldmodel=="" || fieldmodel===undefined){
if(fieldmodel.length==0){
this.formdata[item.name]=outputValue
}else{
// convert fieldmodel for actual object
// svm.lif.name => svm["lif"].name = formvalue
// using reduce, which is a recursive function
fieldmodel.split(/\s*\.\s*/).reduce((master,obj, level,arr) => {
// if last
if (level === (arr.length - 1)){
// the last piece we assign the value to
master[obj]=outputValue
}else{
// initialize first time to object
if(master[obj]===undefined){
master[obj]={}
}
}
// return the result for next reduce iteration
return master[obj]
fieldmodel.forEach((f)=>{
// convert fieldmodel for actual object
// svm.lif.name => svm["lif"].name = formvalue
// using reduce, which is a recursive function
f.split(/\s*\.\s*/).reduce((master,obj, level,arr) => {
// if last
if (level === (arr.length - 1)){
// the last piece we assign the value to
master[obj]=outputValue
}else{
// initialize first time to object
if(master[obj]===undefined){
master[obj]={}
}
}
// return the result for next reduce iteration
return master[obj]
},ref.formdata);
})
},ref.formdata);
}
}
});
Expand Down
2 changes: 1 addition & 1 deletion server/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ansible_forms",
"version": "4.0.8",
"version": "4.0.9",
"repository": {
"type": "git",
"url": "git://github.com/ansibleguy76/ansibleforms.git"
Expand Down
63 changes: 60 additions & 3 deletions server/schema/forms_schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -829,6 +829,59 @@
},
"required": ["query", "dbConfig"]
},
{
"properties": {
"type": {
"enum": ["html"]
},
"label": {"not":{}},
"placeholder": {"not":{}},
"dateType": {"not":{}},
"asCredential": {"not":{}},
"required": {"not":{}},
"sameAs": {"not":{}},
"validIf": {"not":{}},
"validIfNot": {"not":{}},
"regex": {"not":{}},
"notIn": {"not":{}},
"in": {"not":{}},
"minValue": {"not":{}},
"maxValue": {"not":{}},
"minLength": {"not":{}},
"maxLength": {"not":{}},
"keydown": {"not":{}},
"refresh": {"not":{}},
"isHtml": {"not":{}},
"runLocal": {"not":{}},
"query": {"not":{}},
"outputObject": {"not":{}},
"columns": {"not":{}},
"pctColumns": {"not":{}},
"filterColumns": {"not":{}},
"allowDelete": {"not":{}},
"allowInsert": {"not":{}},
"deleteMarker": {"not":{}},
"insertMarker": {"not":{}},
"readonlyColumns": {"not":{}},
"insertColumns": {"not":{}},
"sticky": {"not":{}},
"horizontal": {"not":{}},
"editable": {"not":{}},
"valueColumn": {"not":{}},
"previewColumn": {"not":{}},
"placeholderColumn": {"not":{}},
"dbConfig": {"not":{}},
"model": {"not":{}},
"help": {"not":{}},
"values": {"not":{}},
"multiple": {"not":{}},
"size": {"not":{}},
"hide": {"not":{}},
"icon": {"not":{}},
"tableFields": {"not":{}}
},
"required": ["expression"]
},
{
"properties": {
"type": {
Expand Down Expand Up @@ -879,7 +932,7 @@
"properties": {
"type": {
"type": "string",
"enum": ["text","textarea", "password", "checkbox", "enum", "query", "number", "radio", "expression", "table","datetime"]
"enum": ["text","textarea", "password", "checkbox", "enum", "query", "number", "radio", "expression", "table","datetime","html"]
},
"name": {
"$id": "/formfield",
Expand Down Expand Up @@ -1025,7 +1078,11 @@
}
}
},
"model": {"type": "string"},
"model": {
"anyOf": [{"type": "string"},
{"type": "array"}
]
},
"help": {"type": "string"},
"values": {
"type": "array",
Expand Down Expand Up @@ -1220,7 +1277,7 @@
"properties": {
"type": {
"type": "string",
"enum": ["text","textarea", "password", "checkbox", "enum", "query", "number","datetime"]
"enum": ["text","textarea", "password", "checkbox", "enum", "query", "number","datetime","html"]
},
"name": {"type": "string"},
"label": {"type": "string"},
Expand Down
Loading

0 comments on commit bdde059

Please sign in to comment.