Skip to content

Commit 1476c0b

Browse files
authored
Merge pull request binary-com#1621 from sam-binary/webhook-blocks
Webhook blocks
2 parents 99490d1 + 9ae9ced commit 1476c0b

File tree

6 files changed

+236
-1
lines changed

6 files changed

+236
-1
lines changed

src/botPage/bot/Interface/ToolsInterface.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import CandleInterface from './CandleInterface';
22
import MiscInterface from './MiscInterface';
33
import IndicatorsInterface from './IndicatorsInterface';
4+
import WebhookInterface from './WebhookInterface';
45
import { translate } from '../../../common/i18n';
56

67
// prettier-ignore
78
export default Interface => class extends IndicatorsInterface(
8-
MiscInterface(CandleInterface(Interface))) {
9+
MiscInterface(CandleInterface(WebhookInterface(Interface)))) {
910
getToolsInterface() {
1011
return {
1112
getTime : () => parseInt(new Date().getTime() / 1000),
@@ -76,6 +77,7 @@ export default Interface => class extends IndicatorsInterface(
7677
...this.getCandleInterface(),
7778
...this.getMiscInterface(),
7879
...this.getIndicatorsInterface(),
80+
...this.getWebhookInterface(),
7981
};
8082
}
8183
};
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { notify } from '../broadcast';
2+
import { translate } from '../../../common/i18n';
3+
4+
export default Interface =>
5+
class extends Interface {
6+
// eslint-disable-next-line class-methods-use-this
7+
sendWebhook(url, payload) {
8+
const onError = () => notify('warn', translate('Unable to send webhook'));
9+
const fetchOption = {
10+
method : 'POST',
11+
mode : 'cors',
12+
headers: { 'Content-Type': 'application/json' },
13+
};
14+
15+
if (payload) {
16+
fetchOption.body = JSON.stringify(payload);
17+
}
18+
19+
fetch(url, fetchOption)
20+
.then(response => {
21+
if (!response.ok) {
22+
onError();
23+
}
24+
})
25+
.catch(onError);
26+
}
27+
28+
getWebhookInterface() {
29+
return {
30+
sendWebhook: this.sendWebhook,
31+
};
32+
}
33+
};

src/botPage/view/blockly/blocks/tools/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,5 @@ import './block_holder';
77
import './loader';
88
import './candle';
99
import './time';
10+
import './webhook';
11+
import './key_value_pair';
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { translate } from '../../../../../common/i18n';
2+
3+
Blockly.Blocks.key_value_pair = {
4+
init() {
5+
this.jsonInit({
6+
message0: translate('Key: %1 Value: %2'),
7+
args0 : [
8+
{
9+
type: 'field_input',
10+
name: 'KEY',
11+
text: 'default',
12+
},
13+
{
14+
type: 'input_value',
15+
name: 'VALUE',
16+
},
17+
],
18+
colour : '#dedede',
19+
output : null,
20+
tooltip: translate('Returns a string representation of a key value pair'),
21+
});
22+
},
23+
};
24+
25+
Blockly.JavaScript.key_value_pair = block => {
26+
const key = block.getFieldValue('KEY') || '';
27+
const value = Blockly.JavaScript.valueToCode(block, 'VALUE', Blockly.JavaScript.ORDER_ATOMIC) || null;
28+
29+
if (!key) {
30+
return '';
31+
}
32+
33+
return [`{"${key}":${value}}`, Blockly.JavaScript.ORDER_ATOMIC];
34+
};
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
/* eslint-disable no-underscore-dangle */
2+
import { translate } from '../../../../../common/i18n';
3+
import { expectValue } from '../shared';
4+
5+
Blockly.Blocks.webhook = {
6+
init() {
7+
this.jsonInit({
8+
message0: translate('Webhook URL: %1'),
9+
args0 : [
10+
{
11+
type: 'input_value',
12+
name: 'WEBHOOK_URL',
13+
},
14+
],
15+
colour : '#dedede',
16+
previousStatement: null,
17+
nextStatement : null,
18+
tooltip : translate('Sends a POST request to a URL'),
19+
});
20+
21+
this.itemCount_ = 1;
22+
this.updateShape_(false);
23+
this.setMutator(new Blockly.Mutator(['lists_create_with_item']));
24+
},
25+
/**
26+
* Create XML to represent list inputs.
27+
* @return {!Element} XML storage element.
28+
* @this Blockly.Block
29+
*/
30+
mutationToDom() {
31+
const container = document.createElement('mutation');
32+
container.setAttribute('items', this.itemCount_);
33+
return container;
34+
},
35+
/**
36+
* Parse XML to restore the list inputs.
37+
* @param {!Element} xmlElement XML storage element.
38+
* @this Blockly.Block
39+
*/
40+
domToMutation(xmlElement) {
41+
this.itemCount_ = parseInt(xmlElement.getAttribute('items'));
42+
this.updateShape_(false);
43+
},
44+
/**
45+
* Populate the mutator's dialog with this block's components.
46+
* @param {!Blockly.Workspace} workspace Mutator's workspace.
47+
* @return {!Blockly.Block} Root block in mutator.
48+
* @this Blockly.Block
49+
*/
50+
decompose(workspace) {
51+
const containerBlock = workspace.newBlock('lists_create_with_container');
52+
containerBlock.initSvg();
53+
54+
let { connection } = containerBlock.getInput('STACK');
55+
for (let i = 0; i < this.itemCount_; i++) {
56+
const itemBlock = workspace.newBlock('lists_create_with_item');
57+
itemBlock.initSvg();
58+
connection.connect(itemBlock.previousConnection);
59+
connection = itemBlock.nextConnection;
60+
}
61+
return containerBlock;
62+
},
63+
/**
64+
* Reconfigure this block based on the mutator dialog's components.
65+
* @param {!Blockly.Block} containerBlock Root block in mutator.
66+
* @this Blockly.Block
67+
*/
68+
compose(containerBlock) {
69+
let itemBlock = containerBlock.getInputTargetBlock('STACK');
70+
// Count number of inputs.
71+
const connections = [];
72+
while (itemBlock) {
73+
connections.push(itemBlock.valueConnection_);
74+
itemBlock = itemBlock.nextConnection && itemBlock.nextConnection.targetBlock();
75+
}
76+
this.itemCount_ = connections.length;
77+
this.updateShape_(true);
78+
},
79+
/**
80+
* Modify this block to have the correct number of inputs.
81+
* @private
82+
* @this Blockly.Block
83+
*/
84+
updateShape_(attachInput) {
85+
if (this.itemCount_ && this.getInput('EMPTY')) {
86+
this.removeInput('EMPTY');
87+
} else if (!this.itemCount_ && !this.getInput('EMPTY')) {
88+
this.appendDummyInput('EMPTY').appendField(translate('Empty payload'));
89+
}
90+
let i;
91+
for (i = 0; i < this.itemCount_; i++) {
92+
if (!this.getInput(`ADD${i}`)) {
93+
const input = this.appendValueInput(`ADD${i}`);
94+
95+
if (i === 0) {
96+
input.appendField(translate('Payload:'));
97+
}
98+
99+
if (!attachInput) {
100+
return;
101+
}
102+
const { connection } = input;
103+
const keypair = this.workspace.newBlock('key_value_pair', `keyvalue${i}`);
104+
keypair.initSvg();
105+
keypair.render();
106+
keypair.outputConnection.connect(connection);
107+
}
108+
}
109+
// Remove deleted inputs.
110+
while (this.getInput(`ADD${i}`)) {
111+
this.removeInput(`ADD${i}`);
112+
i++;
113+
}
114+
},
115+
onchange: function onchange(ev) {
116+
if (!this.workspace || this.isInFlyout || this.workspace.isDragging()) {
117+
return;
118+
}
119+
120+
if (ev.type === Blockly.Events.MOVE) {
121+
for (let i = 0; i < this.itemCount_; i++) {
122+
const currentBlock = this.getInputTargetBlock(`ADD${i}`);
123+
if (currentBlock && currentBlock.type !== 'key_value_pair') {
124+
currentBlock.unplug(true);
125+
}
126+
}
127+
}
128+
},
129+
};
130+
131+
Blockly.JavaScript.webhook = block => {
132+
const url = expectValue(block, 'WEBHOOK_URL');
133+
134+
if (!block.itemCount_) {
135+
return `Bot.sendWebhook(${url}, null);\n`;
136+
}
137+
138+
const keypairs = new Array(block.itemCount_);
139+
for (let i = 0; i < block.itemCount_; i++) {
140+
keypairs[i] = Blockly.JavaScript.valueToCode(block, `ADD${i}`, Blockly.JavaScript.ORDER_ATOMIC) || null;
141+
}
142+
143+
const params = keypairs
144+
.filter(item => item !== null)
145+
.map(item => {
146+
const regExp = /^{(.*?)}$/;
147+
return item && item.match(regExp)[1];
148+
});
149+
150+
return `Bot.sendWebhook(${url}, {${params}});\n`;
151+
};

static/xml/toolbox.xml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -469,6 +469,19 @@
469469
</block>
470470
<block type="loader"></block>
471471
<block type="block_holder"></block>
472+
<block type="webhook">
473+
<value name="WEBHOOK_URL">
474+
<shadow type="text">
475+
<field name="TEXT">https://example.com</field>
476+
</shadow>
477+
</value>
478+
<value name="ADD0">
479+
<block type="key_value_pair">
480+
</block>
481+
</value>
482+
</block>
483+
<block type="key_value_pair">
484+
</block>
472485
</category>
473486
</category>
474487
</category>

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy