Add cobalt JSON field type

This commit is contained in:
garrettmills 2020-05-21 23:10:47 -05:00
parent b275391674
commit c74e3b0685
No known key found for this signature in database
GPG Key ID: 6ACD58D6ADACFC6E
4 changed files with 59 additions and 5 deletions

View File

@ -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

View File

@ -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 = ''
} }

View File

@ -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)

View File

@ -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',