Add cobalt JSON field type
This commit is contained in:
parent
b275391674
commit
c74e3b0685
@ -1,4 +1,3 @@
|
|||||||
- Cobalt form JSON field type - Setting resource
|
|
||||||
- MFA recovery codes handling
|
- MFA recovery codes handling
|
||||||
- Forgot password handling
|
- Forgot password handling
|
||||||
- Admin password reset mechanism -> flag users as needing PW resets
|
- Admin password reset mechanism -> flag users as needing PW resets
|
||||||
|
@ -74,6 +74,20 @@ const template = `
|
|||||||
></textarea>
|
></textarea>
|
||||||
<small class="form-text" style="color: darkred;" v-if="field.error">{{ field.error }}</small>
|
<small class="form-text" style="color: darkred;" v-if="field.error">{{ field.error }}</small>
|
||||||
</span>
|
</span>
|
||||||
|
<span v-if="field.type === 'json' && (Array.isArray(field.hidden) ? !field.hidden.includes(mode) : !field.hidden) && (typeof field.if !== 'function' || field.if(data))">
|
||||||
|
<label :for="uuid+field.field">{{ field.name }}</label>
|
||||||
|
<textarea
|
||||||
|
class="form-control"
|
||||||
|
:id="uuid+field.field"
|
||||||
|
v-model="data[field.field]"
|
||||||
|
:required="Array.isArray(field.required) ? field.required.includes(mode) : field.required"
|
||||||
|
:placeholder="field.placeholder"
|
||||||
|
:readonly="mode === 'view' || (Array.isArray(field.readonly) ? field.readonly.includes(mode) : field.readonly)"
|
||||||
|
ref="input"
|
||||||
|
rows="10"
|
||||||
|
></textarea>
|
||||||
|
<small class="form-text" style="color: darkred;" v-if="field.error">{{ field.error }}</small>
|
||||||
|
</span>
|
||||||
<span v-if="field.type === 'password' && (Array.isArray(field.hidden) ? !field.hidden.includes(mode) : !field.hidden) && (typeof field.if !== 'function' || field.if(data))">
|
<span v-if="field.type === 'password' && (Array.isArray(field.hidden) ? !field.hidden.includes(mode) : !field.hidden) && (typeof field.if !== 'function' || field.if(data))">
|
||||||
<label :for="uuid+field.field">{{ field.name }}</label>
|
<label :for="uuid+field.field">{{ field.name }}</label>
|
||||||
<input
|
<input
|
||||||
@ -207,6 +221,10 @@ export default class FormComponent extends Component {
|
|||||||
if ( field.type.endsWith('.multiple') && !this.data[field.field] ) {
|
if ( field.type.endsWith('.multiple') && !this.data[field.field] ) {
|
||||||
this.data[field.field] = []
|
this.data[field.field] = []
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( field.type === 'json' ) {
|
||||||
|
this.data[field.field] = JSON.stringify(this.data[field.field], undefined, 4)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.title = title_map[this.mode] + ' ' + this.resource_class.item
|
this.title = title_map[this.mode] + ' ' + this.resource_class.item
|
||||||
@ -224,25 +242,55 @@ export default class FormComponent extends Component {
|
|||||||
location_service.set_query(`mode=update&id=${this.id}`)
|
location_service.set_query(`mode=update&id=${this.id}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data_to_save() {
|
||||||
|
const data = Object.assign({}, this.data)
|
||||||
|
for ( const field of this.definition.fields ) {
|
||||||
|
if ( field.type === 'json' ) {
|
||||||
|
data[field.field] = JSON.parse(data[field.field])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
data_to_restore(data) {
|
||||||
|
const new_data = Object.assign({}, data)
|
||||||
|
for ( const field of this.definition.fields ) {
|
||||||
|
if ( field.type === 'json' ) {
|
||||||
|
new_data[field.field] = JSON.stringify(data[field.field], undefined, 4)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.data = new_data
|
||||||
|
}
|
||||||
|
|
||||||
async save_click() {
|
async save_click() {
|
||||||
if ( !this.validate() ) return
|
if ( !this.validate() ) return
|
||||||
try {
|
try {
|
||||||
if (this.mode === 'insert') {
|
if (this.mode === 'insert') {
|
||||||
this.data = await this.resource_class.create(this.data)
|
this.data_to_restore(await this.resource_class.create(this.data_to_save()))
|
||||||
await this.on_create()
|
await this.on_create()
|
||||||
} else if (this.mode === 'update') {
|
} else if (this.mode === 'update') {
|
||||||
await this.resource_class.update(this.id, this.data)
|
await this.resource_class.update(this.id, this.data_to_save())
|
||||||
}
|
}
|
||||||
|
|
||||||
this.error_message = ''
|
this.error_message = ''
|
||||||
this.other_message = `The ${this.resource_class.item} was saved.`
|
this.other_message = `The ${this.resource_class.item} was saved.`
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
console.error(e)
|
||||||
if ( e.response && e.response.data && e.response.data.message )
|
if ( e.response && e.response.data && e.response.data.message )
|
||||||
this.error_message = e.response.data.message
|
this.error_message = e.response.data.message
|
||||||
else this.error_message = 'An unknown error occurred while saving the form.'
|
else this.error_message = 'An unknown error occurred while saving the form.'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
is_json(string) {
|
||||||
|
try {
|
||||||
|
JSON.parse(string)
|
||||||
|
return true
|
||||||
|
} catch (e) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
validate() {
|
validate() {
|
||||||
let valid = true
|
let valid = true
|
||||||
for ( const field of this.definition.fields ) {
|
for ( const field of this.definition.fields ) {
|
||||||
@ -252,6 +300,9 @@ export default class FormComponent extends Component {
|
|||||||
} else if ( field.type === 'password' && this.data[field.field] !== this.data[field.field + '-confirm'] ) {
|
} else if ( field.type === 'password' && this.data[field.field] !== this.data[field.field + '-confirm'] ) {
|
||||||
field.error = field.name + ' confirmation does not match.'
|
field.error = field.name + ' confirmation does not match.'
|
||||||
valid = false
|
valid = false
|
||||||
|
} else if ( field.type === 'json' && !this.is_json(this.data[field.field]) ) {
|
||||||
|
field.error = field.name + ' must be valid JSON.'
|
||||||
|
valid = false
|
||||||
} else {
|
} else {
|
||||||
field.error = ''
|
field.error = ''
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ export default class CRUDBase {
|
|||||||
|
|
||||||
async create(properties) {
|
async create(properties) {
|
||||||
for ( const field of this.required_fields ) {
|
for ( const field of this.required_fields ) {
|
||||||
if ( !properties[field] ) throw new Error(`Missing required field: ${field}`)
|
if ( !(field in properties) ) throw new Error(`Missing required field: ${field}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
const results = await axios.post(this._endpoint(), properties)
|
const results = await axios.post(this._endpoint(), properties)
|
||||||
@ -40,7 +40,7 @@ export default class CRUDBase {
|
|||||||
|
|
||||||
async update(id, properties) {
|
async update(id, properties) {
|
||||||
for ( const field of this.required_fields ) {
|
for ( const field of this.required_fields ) {
|
||||||
if ( !properties[field] ) throw new Error(`Missing required field: ${field}`)
|
if ( !(field in properties) ) throw new Error(`Missing required field: ${field}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
await axios.patch(this._endpoint(id), properties)
|
await axios.patch(this._endpoint(id), properties)
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import CRUDBase from './CRUDBase.js'
|
import CRUDBase from './CRUDBase.js'
|
||||||
|
import { session } from '../service/Session.service.js'
|
||||||
|
|
||||||
class SettingResource extends CRUDBase {
|
class SettingResource extends CRUDBase {
|
||||||
endpoint = '/api/v1/settings'
|
endpoint = '/api/v1/settings'
|
||||||
@ -9,6 +10,9 @@ class SettingResource extends CRUDBase {
|
|||||||
plural = 'Settings'
|
plural = 'Settings'
|
||||||
|
|
||||||
listing_definition = {
|
listing_definition = {
|
||||||
|
display: `
|
||||||
|
<p>These are advanced settings that allow you to tweak the way ${session.get('app.name')} behaves. Tweak them at your own risk.</p>
|
||||||
|
`,
|
||||||
columns: [
|
columns: [
|
||||||
{
|
{
|
||||||
name: 'Setting Key',
|
name: 'Setting Key',
|
||||||
|
Loading…
Reference in New Issue
Block a user