diff --git a/src/foam/core/reflow/LibraryScript.js b/src/foam/core/reflow/LibraryScript.js new file mode 100644 index 00000000000..8d9c6b1139b --- /dev/null +++ b/src/foam/core/reflow/LibraryScript.js @@ -0,0 +1,30 @@ +/** + * @license + * Copyright 2015 The FOAM Authors. All Rights Reserved. + * http://www.apache.org/licenses/LICENSE-2.0 + */ + +foam.CLASS({ + package: 'foam.core.reflow', + name: 'LibraryScript', + extends: 'foam.core.reflow.Script', + + documentation: 'Script subtype for persisted Library entries with required id and scriptName.', + + ids: [ 'id' ], + + properties: [ + { + class: 'Long', + name: 'id', + visibility: 'RO', + }, + { + class: 'String', + name: 'scriptName', + required: true + } + ] +}); + + diff --git a/src/foam/core/reflow/Script.js b/src/foam/core/reflow/Script.js index 3b7a75ed251..ff97d44c122 100644 --- a/src/foam/core/reflow/Script.js +++ b/src/foam/core/reflow/Script.js @@ -11,7 +11,8 @@ foam.CLASS({ imports: [ 'data as block', 'eval_', - 'scope' + 'scope', + 'notify?' ], documentation: ` @@ -24,6 +25,19 @@ foam.CLASS({ `, properties: [ + { + class: 'Long', + name: 'id', + visibility: 'RO' + }, + { + class: 'String', + name: 'scriptName' + }, + { + class: 'String', + name: 'description' + }, { class: 'String', name: 'code', @@ -61,10 +75,16 @@ foam.CLASS({ actions: [ function run() { let self = this; - with ( this.scope ) { + var _scope = this.scope || {}; + with ( _scope ) { with ( { log: this.log.bind(this) } ) { var ret = eval('(async function() {' + self.code + '})').call(self.block); - ret.then(v => this.log(v), v => this.log(v)).catch(e => this.log(e.stack)); + ret + .then(v => { + this.log(v); + try { this.notify && this.notify(`Script${this.scriptName ? ' "' + this.scriptName + '"' : ''} executed successfully`); } catch (e) {} + }, v => this.log(v)) + .catch(e => this.log(e.stack)); return ret; } } diff --git a/src/foam/core/reflow/cmd/Commands.js b/src/foam/core/reflow/cmd/Commands.js index d5754ca82a2..87dad149f33 100644 --- a/src/foam/core/reflow/cmd/Commands.js +++ b/src/foam/core/reflow/cmd/Commands.js @@ -332,6 +332,47 @@ foam.CLASS({ }); +foam.CLASS({ + package: 'foam.core.reflow.cmd', + name: 'Scripts', + extends: 'foam.core.reflow.cmd.Command', + + requires: [ 'foam.core.reflow.Script', 'foam.core.reflow.cmd.DAORowView' ], + + imports: [ 'reflowLibDAO', 'scope' ], + + + + properties: [ + [ 'description', 'Display available scripts' ] + ], + + methods: [ + function execute(opt_nameQuery) { + var self = this; + var dao = this.reflowLibDAO; + var count = foam.lang.SimpleSlot.create({value: 0}); + if ( opt_nameQuery ) dao = dao.where( + this.OR( + this.CONTAINS_IC(foam.core.reflow.Script.SCRIPT_NAME, opt_nameQuery), + )); + this.out.tag('br'); + this.out.start('table').attr('width', '100%'). + select(dao, function(n) { + count.value++; + + this.start('tr'). + start('td').attr('align', 'left').add(n.scriptName).end(). + start('td').attr('align', 'left').add(n.description).end(). + start('td').attr('align', 'left').start(foam.u2.Link).add('Run').on('click', function() { n.run(); }).end(). + end(); + }). + end(). + start('b').add(count, ' selected').end(); + } + ] +}) + foam.CLASS({ package: 'foam.core.reflow.cmd', name: 'DAOS', @@ -391,6 +432,80 @@ foam.CLASS({ ] }); +foam.CLASS({ + package: 'foam.core.reflow.cmd', + name: 'RunScript', + extends: 'foam.core.reflow.cmd.Command', + + mixins: [ 'foam.mlang.Expressions' ], + + imports: [ 'reflowLibDAO', 'notify?' ], + + properties: [ + { name: 'id', value: 'runScript' }, + [ 'description', 'Run a saved script by name: runScript ' ] + ], + + methods: [ + async function execute(scriptName) { + if ( ! scriptName ) { + this.notify && this.notify('Usage: runScript '); + this.out && this.out.add('Usage: runScript '); + return; + } + + let script = null; + try { + // Try exact match on scriptName field + script = await this.reflowLibDAO.find(this.EQ(foam.core.reflow.Script.SCRIPT_NAME, scriptName)); + } catch (e) {} + + if ( ! script ) { + try { + // Fallback: try DAO find by id + script = await this.reflowLibDAO.find(scriptName); + } catch (e) {} + } + + if ( ! script ) { + const msg = `Script "${scriptName}" not found`; + (this.notify && this.notify(msg)) || (this.out && this.out.add(msg)); + return; + } + + try { + await script.run(); + this.notify && this.notify(`Script "${script.scriptName || scriptName}" executed successfully`); + } catch (e) { + const errMsg = `Script "${scriptName}" failed: ${e && e.message ? e.message : e}`; + (this.notify && this.notify(errMsg)) || (this.out && this.out.add(errMsg)); + } + } + ] +}); + +foam.CLASS({ + package: 'foam.core.reflow.cmd', + name: 'HelpScript', + extends: 'foam.core.reflow.cmd.Command', + + properties: [ + { name: 'id', value: 'helpScript' }, + [ 'description', 'Display usage for scripts-related commands' ] + ], + + methods: [ + function execute() { + this.out + .start('div') + .start('h3').add('Script Commands').end() + .start('p').add('scripts: Display available scripts').end() + .start('p').add('runScript : Run a saved script by name').end() + .end(); + } + ] +}); + /* foam.CLASS({ package: 'foam.core.reflow', diff --git a/src/foam/core/reflow/cmd/cmds.jrl b/src/foam/core/reflow/cmd/cmds.jrl index 252108a8800..5715a320210 100644 --- a/src/foam/core/reflow/cmd/cmds.jrl +++ b/src/foam/core/reflow/cmd/cmds.jrl @@ -3,6 +3,9 @@ p({"class":"foam.core.reflow.cmd.Clear", "id": "clear"}) p({"class":"foam.core.reflow.cmd.DAO", "id": "dao"}) p({"class":"foam.core.reflow.cmd.DAOCreate", "id": "add", linkable: false}) p({"class":"foam.core.reflow.cmd.DAOS", "id": "daos"}) +p({"class":"foam.core.reflow.cmd.Scripts", "id": "scripts"}) +p({"class":"foam.core.reflow.cmd.RunScript", "id": "run"}) +p({"class":"foam.core.reflow.cmd.HelpScript", "id": "helpScript"}) p({"class":"foam.core.reflow.cmd.Describe", "id": "describe", linkable: false}) p({"class":"foam.core.reflow.cmd.Flows", "id": "flows"}) p({"class":"foam.core.reflow.cmd.Help", "id": "help"}) diff --git a/src/foam/core/reflow/pom.js b/src/foam/core/reflow/pom.js index da0642e3798..34c37f56118 100644 --- a/src/foam/core/reflow/pom.js +++ b/src/foam/core/reflow/pom.js @@ -49,7 +49,8 @@ foam.POM({ { name: 'DynamicReflowData', flags: 'js' }, { name: 'DynamicReflowComponents', flags: 'js' }, { name: 'DynamicReflowHelp', flags: 'js' }, - { name: 'Script', flags: 'js' }, + { name: 'Script', flags: 'js|java' }, + { name: 'LibraryScript', flags: 'js|java' }, { name: 'Signature', flags: 'js' }, { name: 'SinkView', flags: 'js' }, { name: 'CopyFromBorder', flags: 'js' }, diff --git a/src/foam/core/reflow/services.jrl b/src/foam/core/reflow/services.jrl index 091c38e5e44..63bbf945c90 100644 --- a/src/foam/core/reflow/services.jrl +++ b/src/foam/core/reflow/services.jrl @@ -86,3 +86,30 @@ p({ } """ }) + +p({ + "class": "foam.core.boot.CSpec", + "name": "reflowLibDAO", + "description": "Stores Reflow Scripts", + "serve":true, + "authenticate":false, + "serviceScript":` + return new foam.dao.EasyDAO.Builder(x) + .setPm(true) + .setAuthorize(true) + .setPermissioned(true) + .setSeqNo(true) + .setJournalType(foam.dao.JournalType.SINGLE_JOURNAL) + .setJournalName("libs") + .setOf(foam.core.reflow.LibraryScript.getOwnClassInfo()) + .build(); + `, + "client":""" + { + "of":"foam.core.reflow.LibraryScript", + "cache":true, + "ttlSelectPurgeTime": 0, + "ttlPurgeTime": 0 + } + """ +})