diff --git a/app/templating/__tests__/utils.test.js b/app/templating/__tests__/utils.test.js index f2ff43d1e1..0b2428dd88 100644 --- a/app/templating/__tests__/utils.test.js +++ b/app/templating/__tests__/utils.test.js @@ -116,8 +116,8 @@ describe('tokenizeTag()', () => { const expected = { name: 'name', args: [ - {type: 'boolean', value: 'true'}, - {type: 'boolean', value: 'false'} + {type: 'boolean', value: true}, + {type: 'boolean', value: false} ] }; diff --git a/app/templating/extensions/index.js b/app/templating/extensions/index.js index 1e9e33a5d0..a760f7c50c 100644 --- a/app/templating/extensions/index.js +++ b/app/templating/extensions/index.js @@ -46,6 +46,11 @@ export type PluginArgumentString = PluginArgumentBase & { defaultValue?: string }; +export type PluginArgumentBoolean = PluginArgumentBase & { + type: 'boolean'; + defaultValue?: boolean +}; + export type PluginArgumentNumber = PluginArgumentBase & { type: 'number'; placeholder?: string, @@ -56,6 +61,7 @@ export type PluginArgument = PluginArgumentEnum | PluginArgumentModel | PluginArgumentString + | PluginArgumentBoolean | PluginArgumentNumber; export type PluginTemplateTagContext = { diff --git a/app/templating/utils.js b/app/templating/utils.js index 74b1c0b5c7..d5b72e906a 100644 --- a/app/templating/utils.js +++ b/app/templating/utils.js @@ -3,6 +3,7 @@ export type NunjucksParsedTagArg = { type: 'string' | 'number' | 'boolean' | 'number' | 'variable' | 'expression', value: string | number | boolean, + defaultValue?: string | number | boolean, forceVariable?: boolean, quotedBy?: '"' | "'" }; @@ -121,7 +122,7 @@ export function tokenizeTag (tagStr: string): NunjucksParsedTag { if (quotedBy) { arg = {type: 'string', value: currentArg, quotedBy}; } else if (['true', 'false'].includes(currentArg)) { - arg = {type: 'boolean', value: currentArg}; + arg = {type: 'boolean', value: currentArg.toLowerCase() === 'true'}; } else if (currentArg.match(/^\d*\.?\d*$/)) { arg = {type: 'number', value: currentArg}; } else if (currentArg.match(/^[a-zA-Z_$][0-9a-zA-Z_$]*$/)) { @@ -149,6 +150,8 @@ export function unTokenizeTag (tagData: NunjucksParsedTag): string { const re = new RegExp(`([^\\\\])${q}`, 'g'); const str = arg.value.toString().replace(re, `$1\\${q}`); args.push(`${q}${str}${q}`); + } else if (arg.type === 'boolean') { + args.push(arg.value ? 'true' : 'false'); } else { args.push(arg.value); } @@ -160,23 +163,21 @@ export function unTokenizeTag (tagData: NunjucksParsedTag): string { /** Get the default Nunjucks string for an extension */ export function getDefaultFill (name: string, args: Array): string { - const stringArgs = (args || []).map(argDefinition => { - if (argDefinition.type === 'enum') { - const {defaultValue, options} = argDefinition; - const value = defaultValue !== undefined ? defaultValue : options[0].value; - return `'${value}'`; - } else if (argDefinition.type === 'number') { - return argDefinition.defaultValue !== undefined ? argDefinition.defaultValue : 0; - } else if (argDefinition.defaultValue !== undefined) { - switch (typeof argDefinition.defaultValue) { - case 'string': - case 'number': - case 'boolean': - return `'${argDefinition.defaultValue.toString()}'`; - } + const stringArgs: Array = (args || []).map(argDefinition => { + switch (argDefinition.type) { + case 'enum': + const {defaultValue, options} = argDefinition; + const value = defaultValue !== undefined ? defaultValue : options[0].value; + return `'${value}'`; + case 'number': + return `${parseFloat(argDefinition.defaultValue) || 0}`; + case 'boolean': + return argDefinition.defaultValue ? 'true' : 'false'; + case 'string': + return `'${(argDefinition.defaultValue: any) || ''}'`; + default: + return "''"; } - - return "''"; }); return `${name} ${stringArgs.join(', ')}`; diff --git a/app/ui/components/templating/tag-editor.js b/app/ui/components/templating/tag-editor.js index 68ae1da16b..bad6fe7003 100644 --- a/app/ui/components/templating/tag-editor.js +++ b/app/ui/components/templating/tag-editor.js @@ -92,14 +92,12 @@ class TagEditor extends React.PureComponent { } async _handleRefresh () { - if (this.state.tagDefinitions) { - await this._update( - this.state.tagDefinitions, - this.state.activeTagDefinition, - this.state.activeTagData, - true - ); - } + await this._update( + this.state.tagDefinitions, + this.state.activeTagDefinition, + this.state.activeTagData, + true + ); } async _refreshModels (workspace: Workspace) { @@ -198,6 +196,8 @@ class TagEditor extends React.PureComponent { if (e.currentTarget.type === 'number') { return this._updateArg(parseFloat(e.currentTarget.value), argIndex); + } else if (e.currentTarget.type === 'checkbox') { + return this._updateArg(e.currentTarget.checked, argIndex); } else { return this._updateArg(e.currentTarget.value, argIndex); } @@ -282,15 +282,10 @@ class TagEditor extends React.PureComponent { } } - // Make rendering take at least this long so we can see a spinner - await delay(300 - (Date.now() - start)); - this.setState({ tagDefinitions, activeTagData, - preview, error, - rendering: false, activeTagDefinition: tagDefinition }); @@ -298,6 +293,13 @@ class TagEditor extends React.PureComponent { if (!noCallback) { this.props.onChange(template); } + + // Make rendering take at least this long so we can see a spinner + await delay(300 - (Date.now() - start)); + this.setState({ + rendering: false, + preview + }); } renderArgVariable (path: string) { @@ -335,6 +337,12 @@ class TagEditor extends React.PureComponent { ); } + renderArgBoolean (checked: boolean) { + return ( + + ); + } + renderArgEnum (value: string, options: Array) { const argDatas = this.state.activeTagData ? this.state.activeTagData.args : []; return ( @@ -417,9 +425,9 @@ class TagEditor extends React.PureComponent { return null; } - const value = argData.value.toString(); + const strValue = argData.value.toString(); const isVariable = argData.type === 'variable'; - const argInputVariable = isVariable ? this.renderArgVariable(value) : null; + const argInputVariable = isVariable ? this.renderArgVariable(strValue) : null; let argInput; let isVariableAllowed = false; @@ -428,20 +436,20 @@ class TagEditor extends React.PureComponent { const placeholder = typeof argDefinition.placeholder === 'string' ? argDefinition.placeholder : ''; - argInput = this.renderArgString(value, placeholder); + argInput = this.renderArgString(strValue, placeholder); } else if (argDefinition.type === 'enum') { const {options} = argDefinition; - argInput = this.renderArgEnum(value, options); + argInput = this.renderArgEnum(strValue, options); } else if (argDefinition.type === 'model') { const model = typeof argDefinition.model === 'string' ? argDefinition.model : 'unknown'; - const modelId = typeof value === 'string' ? value : 'unknown'; + const modelId = typeof strValue === 'string' ? strValue : 'unknown'; argInput = this.renderArgModel(modelId, model); + } else if (argDefinition.type === 'boolean') { + argInput = this.renderArgBoolean(strValue.toLowerCase() === 'true'); } else if (argDefinition.type === 'number') { isVariableAllowed = true; - const placeholder = typeof argDefinition.placeholder === 'string' - ? argDefinition.placeholder - : ''; - argInput = this.renderArgNumber(value, placeholder || ''); + const placeholder = typeof argDefinition.placeholder === 'string' ? argDefinition.placeholder : ''; + argInput = this.renderArgNumber(strValue, placeholder || ''); } else { return null; } @@ -452,20 +460,20 @@ class TagEditor extends React.PureComponent { typeof argDefinition.displayName === 'function' ) ? fnOrString(argDefinition.displayName, argDatas) : ''; + const formControlClasses = classnames({ + 'form-control': true, + 'form-control--thin': argDefinition.type === 'boolean', + 'form-control--outlined': argDefinition.type !== 'boolean' + }); + return (
-
-
)} +