caixanegra 0.3.4 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/app/assets/javascripts/caixanegra/api.js +16 -0
- data/app/assets/javascripts/caixanegra/designer.js +289 -18
- data/app/assets/stylesheets/caixanegra/designer.scss +201 -5
- data/app/controllers/caixanegra/api/designer/inputs_controller.rb +32 -0
- data/app/views/caixanegra/designer/index.html.erb +47 -2
- data/app/views/layouts/caixanegra/application.html.erb +1 -1
- data/config/routes.rb +3 -0
- data/lib/caixanegra/manager.rb +1 -1
- data/lib/caixanegra/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 182cc119673359db756adcca903e137025ed5283bdae367d7d6c662fc5fdc061
|
4
|
+
data.tar.gz: f075d702d2f361678a7775d286cb7f3b9ec1cb556778b22c4180588efe32d830
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 29c0edd8fab4949cab99f6d513b987cda6c87b2fb29fbeb33e447616ff580c0a9fbd3413a2fe4281828f28a8ac1123942fcecbdbeedf7511c64cb000384bd797
|
7
|
+
data.tar.gz: 23e9e398d71b3900759d8a944f20ddf1920ac1f38bb5961d3e36a34d112e36a488301d3c4709de8c9cfc48a8a9f995869ebfea90ed20acf72915b6c61ac48345
|
data/README.md
CHANGED
@@ -46,7 +46,7 @@ This will give you the UID that **caixanegra** designer will understand, using t
|
|
46
46
|
|
47
47
|
```ruby
|
48
48
|
my_flow = somewhere.get_flow # get from your own persistence or transport solution
|
49
|
-
uid = Caixanegra::Manager.handler(my_flow || {})
|
49
|
+
uid = Caixanegra::Manager.handler(flow_definition: my_flow || {})
|
50
50
|
```
|
51
51
|
|
52
52
|
You can then safely navigate to the designer.
|
@@ -66,4 +66,20 @@ window.Caixanegra.API = class {
|
|
66
66
|
request.send(JSON.stringify(initialCarryOver));
|
67
67
|
});
|
68
68
|
}
|
69
|
+
|
70
|
+
evaluateRegex(expression, sample) {
|
71
|
+
return new Promise((resolve, reject) => {
|
72
|
+
const request = new XMLHttpRequest();
|
73
|
+
|
74
|
+
request.addEventListener("load", (event) => {
|
75
|
+
resolve(JSON.parse(event.target.response));
|
76
|
+
});
|
77
|
+
request.addEventListener("error", () => {
|
78
|
+
reject();
|
79
|
+
});
|
80
|
+
|
81
|
+
request.open("GET", `${this.mountedPath()}/api/designer/inputs/evaluate_regex?expression=${encodeURIComponent(expression)}&sample=${encodeURIComponent(sample)}`);
|
82
|
+
request.send();
|
83
|
+
});
|
84
|
+
}
|
69
85
|
}
|
@@ -303,6 +303,15 @@ window.Caixanegra.Designer = {
|
|
303
303
|
document.querySelector("#console").addEventListener("click", this.toggleExecutionConsole.bind(this));
|
304
304
|
document.querySelector("#clearCarryOverObject").addEventListener("click", this.clearCarryOverObject.bind(this));
|
305
305
|
document.querySelector("#reset").addEventListener("click", this.resetExecution.bind(this));
|
306
|
+
document.querySelector("#duplicate").addEventListener("click", this.duplicateUnit.bind(this));
|
307
|
+
document.querySelector("#importFlow").addEventListener("click", this.#importFlow.bind(this));
|
308
|
+
document.querySelector("#exportFlow").addEventListener("click", this.#exportFlow.bind(this));
|
309
|
+
document.querySelector("#importFlowFile").addEventListener("change", this.#importFlowFileChanged.bind(this));
|
310
|
+
document.querySelector("#regexInput").addEventListener("keyup", this.#updateRegexInput.bind(this));
|
311
|
+
document.querySelector("#regexSample").addEventListener("keyup", this.#startRegexEvaluation.bind(this));
|
312
|
+
document.querySelector("#addRegexVariables").addEventListener("click", this.#addRegexVariablesRow.bind(this))
|
313
|
+
document.querySelector("#regexEditorToggleVars").addEventListener("click", this.#toggleRegexVariables.bind(this));
|
314
|
+
document.querySelector("#dismissRegexEditor").addEventListener("click", this.#dismissRegexEditor.bind(this));
|
306
315
|
this.toggleBlocker(true, "loading your flow");
|
307
316
|
window.addEventListener("resize", this.#windowResized.bind(drawingSurface));
|
308
317
|
drawingSurface.addEventListener("update_start", this.#engineUpdate.bind(this));
|
@@ -315,7 +324,6 @@ window.Caixanegra.Designer = {
|
|
315
324
|
|
316
325
|
this.gre.disable();
|
317
326
|
this.getUnits();
|
318
|
-
this.loadFlow();
|
319
327
|
this.gre.enable();
|
320
328
|
}
|
321
329
|
|
@@ -385,6 +393,8 @@ window.Caixanegra.Designer = {
|
|
385
393
|
}
|
386
394
|
|
387
395
|
container.append(wrapper);
|
396
|
+
|
397
|
+
return wrapper;
|
388
398
|
}
|
389
399
|
|
390
400
|
deleteUnit() {
|
@@ -394,6 +404,12 @@ window.Caixanegra.Designer = {
|
|
394
404
|
this.toggleDeleteConfirmation();
|
395
405
|
}
|
396
406
|
|
407
|
+
duplicateUnit() {
|
408
|
+
this.unitDetailPane.classList.remove("-open");
|
409
|
+
this.unitDebugHitsPane.classList.remove("-open");
|
410
|
+
this.cloneUnit(this.selectedUnit.oid);
|
411
|
+
}
|
412
|
+
|
397
413
|
flushToConsole(entries) {
|
398
414
|
const container = document.querySelector("#executionConsole");
|
399
415
|
container.innerHTML = "";
|
@@ -468,7 +484,8 @@ window.Caixanegra.Designer = {
|
|
468
484
|
flowSnapshot() {
|
469
485
|
const snapshot = {
|
470
486
|
entrypoint: this.#units.find((unit) => {return unit.type === "starter"})?.oid,
|
471
|
-
units: []
|
487
|
+
units: [],
|
488
|
+
initialCarryover: this.digInitialCarryOver(document.querySelector("#carryOverObject"))
|
472
489
|
};
|
473
490
|
|
474
491
|
this.#units.forEach((unit) => {
|
@@ -587,33 +604,85 @@ window.Caixanegra.Designer = {
|
|
587
604
|
});
|
588
605
|
|
589
606
|
this.#loadedComponents.catalog = true;
|
590
|
-
this
|
607
|
+
this.loadFlow();
|
591
608
|
});
|
592
609
|
}
|
593
610
|
|
594
611
|
loadFlow() {
|
595
612
|
this.api.getFlow(this.flowId).then((response) => {
|
596
613
|
const flowData = response;
|
597
|
-
this.gre.clear();
|
598
|
-
this.#units = [];
|
599
614
|
|
600
|
-
(flowData
|
601
|
-
this.createUnit(unit);
|
602
|
-
});
|
603
|
-
|
604
|
-
this.#units.forEach((unit) => {
|
605
|
-
(unit?.exits || []).forEach((exit) => {
|
606
|
-
const object = this.#units.find((targetUnit) => targetUnit.oid === exit.target);
|
607
|
-
if (object) { exit.target = object; }
|
608
|
-
});
|
609
|
-
});
|
615
|
+
this.#loadFlowFromJSON(flowData);
|
610
616
|
|
611
617
|
this.#loadedComponents.flow = true;
|
612
|
-
this
|
618
|
+
this.reveal();
|
619
|
+
});
|
620
|
+
}
|
621
|
+
|
622
|
+
#loadFlowFromJSON(flowData) {
|
623
|
+
this.gre.clear();
|
624
|
+
this.#units = [];
|
625
|
+
|
626
|
+
(flowData?.units || []).forEach((unit) => {
|
627
|
+
const catalogUnit = this.#catalog.find((cUnit) => cUnit.class === unit.class);
|
628
|
+
if (catalogUnit) {
|
629
|
+
unit.color = catalogUnit.color;
|
630
|
+
}
|
631
|
+
this.createUnit(unit);
|
632
|
+
});
|
633
|
+
|
634
|
+
this.#units.forEach((unit) => {
|
635
|
+
(unit?.exits || []).forEach((exit) => {
|
636
|
+
const object = this.#units.find((targetUnit) => targetUnit.oid === exit.target);
|
637
|
+
if (object) { exit.target = object; }
|
638
|
+
});
|
613
639
|
});
|
640
|
+
|
641
|
+
this.buildInitialCarryover(flowData.initialCarryover);
|
614
642
|
}
|
615
643
|
|
616
|
-
|
644
|
+
digBuildInitialCarryover(container, key, objectPointer) {
|
645
|
+
const lastChild = container.childNodes[container.childNodes.length -1];
|
646
|
+
|
647
|
+
if (key !== null) {
|
648
|
+
container.childNodes[0].querySelector("input").value = key;
|
649
|
+
}
|
650
|
+
|
651
|
+
if (Array.isArray(objectPointer)) {
|
652
|
+
this.coeAssignType(lastChild, "array");
|
653
|
+
|
654
|
+
for (let idx = 0; idx < objectPointer.length; idx++) {
|
655
|
+
this.digBuildInitialCarryover(
|
656
|
+
this.coeAddRow(container.querySelector(".rows")),
|
657
|
+
null,
|
658
|
+
objectPointer[idx]
|
659
|
+
);
|
660
|
+
}
|
661
|
+
} else if (typeof objectPointer === "object") {
|
662
|
+
this.coeAssignType(lastChild, "object");
|
663
|
+
|
664
|
+
for (const key in objectPointer) {
|
665
|
+
this.digBuildInitialCarryover(this.coeAddRow(container.querySelector(".rows")), key, objectPointer[key]);
|
666
|
+
}
|
667
|
+
} else if (typeof objectPointer === "number") {
|
668
|
+
this.coeAssignType(lastChild, "number");
|
669
|
+
lastChild.querySelector("input").value = objectPointer;
|
670
|
+
} else {
|
671
|
+
this.coeAssignType(lastChild, "string");
|
672
|
+
lastChild.querySelector("input").value = objectPointer;
|
673
|
+
}
|
674
|
+
}
|
675
|
+
|
676
|
+
buildInitialCarryover(initialCarryover) {
|
677
|
+
this.clearCarryOverObject();
|
678
|
+
const base = document.querySelector("#carryOverObject > .rows");
|
679
|
+
|
680
|
+
for (const key in initialCarryover) {
|
681
|
+
this.digBuildInitialCarryover(this.coeAddRow(base), key, initialCarryover[key]);
|
682
|
+
}
|
683
|
+
}
|
684
|
+
|
685
|
+
reveal() {
|
617
686
|
if (this.#loadedComponents.flow && this.#loadedComponents.catalog) {
|
618
687
|
this.toggleBlocker(false);
|
619
688
|
}
|
@@ -713,6 +782,21 @@ window.Caixanegra.Designer = {
|
|
713
782
|
});
|
714
783
|
}
|
715
784
|
|
785
|
+
cloneUnit(oid) {
|
786
|
+
const unit = this.#units.find((unit) => unit.oid === oid);
|
787
|
+
const dup = this.#dupObject(unit);
|
788
|
+
|
789
|
+
dup.oid = Sabertooth.Utils.generateOId();
|
790
|
+
dup.position = { x: unit.position.x + 25, y: unit.position.y + 25 };
|
791
|
+
dup.title = `${dup.title} (copy)`;
|
792
|
+
|
793
|
+
dup.exits.forEach(exit => {
|
794
|
+
delete exit.target;
|
795
|
+
});
|
796
|
+
|
797
|
+
this.createUnit(dup);
|
798
|
+
}
|
799
|
+
|
716
800
|
showError(message) {
|
717
801
|
this.actionMessage(true, message, "error");
|
718
802
|
setTimeout(() => {this.actionMessage(false)}, 5000);
|
@@ -762,6 +846,73 @@ window.Caixanegra.Designer = {
|
|
762
846
|
this.unitDebugHitsPane.classList.remove("-open");
|
763
847
|
}
|
764
848
|
|
849
|
+
#dupObject(obj) {
|
850
|
+
if (typeof obj !== 'object' || obj === null) {
|
851
|
+
return obj;
|
852
|
+
}
|
853
|
+
|
854
|
+
const clonedObject = Array.isArray(obj) ? [] : {};
|
855
|
+
|
856
|
+
for (const key in obj) {
|
857
|
+
if (obj.hasOwnProperty(key)) {
|
858
|
+
clonedObject[key] = this.#dupObject(obj[key]);
|
859
|
+
}
|
860
|
+
}
|
861
|
+
|
862
|
+
return clonedObject;
|
863
|
+
}
|
864
|
+
|
865
|
+
#importFlow() {
|
866
|
+
document.querySelector("#importFlowFile").click();
|
867
|
+
}
|
868
|
+
|
869
|
+
#importFlowFileChanged() {
|
870
|
+
const fileInput = document.querySelector("#importFlowFile");
|
871
|
+
|
872
|
+
if (fileInput.files.length === 0) {
|
873
|
+
return;
|
874
|
+
}
|
875
|
+
|
876
|
+
const selectedFile = fileInput.files[0];
|
877
|
+
const reader = new FileReader();
|
878
|
+
|
879
|
+
reader.onload = (event) => {
|
880
|
+
this.toggleBlocker(true, "importing your flow");
|
881
|
+
this.gre.disable();
|
882
|
+
const flowBackup = this.flowSnapshot();
|
883
|
+
|
884
|
+
try {
|
885
|
+
this.#loadFlowFromJSON(JSON.parse(event.target.result));
|
886
|
+
|
887
|
+
this.actionMessage(true, "Flow imported", "ok");
|
888
|
+
setTimeout(() => {this.actionMessage(false)}, 4000);
|
889
|
+
} catch (error) {
|
890
|
+
this.#loadFlowFromJSON(flowBackup);
|
891
|
+
|
892
|
+
this.actionMessage(true, "Failed to import flow. Rolled back", "error");
|
893
|
+
setTimeout(() => {this.actionMessage(false)}, 4000);
|
894
|
+
}
|
895
|
+
|
896
|
+
this.gre.enable();
|
897
|
+
this.reveal();
|
898
|
+
};
|
899
|
+
|
900
|
+
reader.readAsText(selectedFile);
|
901
|
+
}
|
902
|
+
|
903
|
+
#exportFlow() {
|
904
|
+
const blob = new Blob([JSON.stringify(this.flowSnapshot())], { type: "application/json" });
|
905
|
+
const url = URL.createObjectURL(blob);
|
906
|
+
const link = document.createElement('a');
|
907
|
+
link.href = url;
|
908
|
+
link.download = "flow_definition.cxn";
|
909
|
+
link.click();
|
910
|
+
URL.revokeObjectURL(url);
|
911
|
+
|
912
|
+
this.actionMessage(true, "Flow exported", "ok");
|
913
|
+
setTimeout(() => {this.actionMessage(false)}, 4000);
|
914
|
+
}
|
915
|
+
|
765
916
|
#executeFlow() {
|
766
917
|
this.toggleBlocker(true, "saving your flow");
|
767
918
|
|
@@ -1135,9 +1286,10 @@ window.Caixanegra.Designer = {
|
|
1135
1286
|
case "regex":
|
1136
1287
|
{
|
1137
1288
|
valueInput = document.createElement("input");
|
1138
|
-
if(matrix.type === "regex") { valueInput.classList.add("-
|
1289
|
+
if(matrix.type === "regex") { valueInput.classList.add("-regex")}
|
1139
1290
|
valueInput.value = unit.mappings[input]?.value || matrix.default || "";
|
1140
1291
|
valueInput.addEventListener("change", this.#unitInputValueChanged.bind(this));
|
1292
|
+
valueInput.addEventListener("click", this.#regexEditor.bind(this));
|
1141
1293
|
}
|
1142
1294
|
break;
|
1143
1295
|
case "dataset":
|
@@ -1237,6 +1389,125 @@ window.Caixanegra.Designer = {
|
|
1237
1389
|
this.selectedUnit.mappings[input].value = ev.target.value;
|
1238
1390
|
}
|
1239
1391
|
|
1392
|
+
#toggleRegexVariables() {
|
1393
|
+
const target = document.querySelector("#blocker .regexEditor > div:last-child");
|
1394
|
+
if(target.classList.contains("-visible")) {
|
1395
|
+
target.classList.remove("-visible");
|
1396
|
+
} else {
|
1397
|
+
target.classList.add("-visible");
|
1398
|
+
}
|
1399
|
+
}
|
1400
|
+
|
1401
|
+
#updateRegexInput() {
|
1402
|
+
this.blocker.editorListener.value = this.blocker.querySelector("#regexInput").value;
|
1403
|
+
|
1404
|
+
this.#startRegexEvaluation();
|
1405
|
+
}
|
1406
|
+
|
1407
|
+
#startRegexEvaluation() {
|
1408
|
+
window.clearTimeout(this.blocker.evalTimeout);
|
1409
|
+
this.blocker.querySelector("#regexResults").innerHTML = "wating input end...";
|
1410
|
+
this.blocker.evalTimeout = window.setTimeout(this.#evaluateRegex.bind(this), 1500);
|
1411
|
+
}
|
1412
|
+
|
1413
|
+
#evaluateRegex() {
|
1414
|
+
this.blocker.querySelector("#regexResults").innerHTML = "evaluating...";
|
1415
|
+
let expression = this.blocker.querySelector("#regexInput").value;
|
1416
|
+
const sample = this.blocker.querySelector("#regexSample").value;
|
1417
|
+
document.querySelectorAll("#regexVariablesList .regex-variable-entry").forEach((pair) => {
|
1418
|
+
const placeholder = pair.querySelector("input.placeholder").value;
|
1419
|
+
const value = pair.querySelector("input.value").value;
|
1420
|
+
expression = expression.replace(new RegExp(placeholder, "g"), value);
|
1421
|
+
});
|
1422
|
+
|
1423
|
+
this.api.evaluateRegex(expression, sample).then((response) => {
|
1424
|
+
const tableEntries = Object.keys(response).length - 2 > 0;
|
1425
|
+
|
1426
|
+
this.blocker.querySelector("#regexResults").innerHTML = "";
|
1427
|
+
const expression = document.createElement("div");
|
1428
|
+
const full_match = document.createElement("div");
|
1429
|
+
expression.innerHTML = `<strong>Expression: </strong><code>${response["_expression"] || "unable to get expression"}</code>`;
|
1430
|
+
full_match.innerHTML = `<strong>Full Match: </strong><code>${response["_full"] || "unable to get full match"}</code>`;
|
1431
|
+
|
1432
|
+
this.blocker.querySelector("#regexResults").append(expression, full_match);
|
1433
|
+
|
1434
|
+
if (tableEntries) {
|
1435
|
+
const table = document.createElement("table");
|
1436
|
+
let tr = document.createElement("tr");
|
1437
|
+
let th = document.createElement("th");
|
1438
|
+
th.innerHTML = "capture";
|
1439
|
+
tr.append(th);
|
1440
|
+
th = document.createElement("th");
|
1441
|
+
th.innerHTML = "match";
|
1442
|
+
tr.append(th);
|
1443
|
+
table.append(tr);
|
1444
|
+
|
1445
|
+
for (const key of Object.keys(response)) {
|
1446
|
+
if (key.startsWith("_")) { continue; }
|
1447
|
+
|
1448
|
+
tr = document.createElement("tr");
|
1449
|
+
let td = document.createElement("td");
|
1450
|
+
td.innerHTML = key;
|
1451
|
+
tr.append(td);
|
1452
|
+
td = document.createElement("td");
|
1453
|
+
td.innerHTML = response[key];
|
1454
|
+
tr.append(td);
|
1455
|
+
|
1456
|
+
table.append(tr);
|
1457
|
+
}
|
1458
|
+
|
1459
|
+
this.blocker.querySelector("#regexResults").append(table);
|
1460
|
+
}
|
1461
|
+
}).catch((error) => {
|
1462
|
+
this.blocker.querySelector("#regexResults").innerHTML = "unable to evaluate";
|
1463
|
+
});
|
1464
|
+
}
|
1465
|
+
|
1466
|
+
#regexEditor(ev) {
|
1467
|
+
this.blocker.classList.add("-in-regex-editor");
|
1468
|
+
this.blocker.classList.remove("-released");
|
1469
|
+
this.blocker.editorListener = ev.target;
|
1470
|
+
this.blocker.querySelector("#regexInput").value = ev.target.value;
|
1471
|
+
|
1472
|
+
this.#startRegexEvaluation();
|
1473
|
+
}
|
1474
|
+
|
1475
|
+
#dismissRegexEditor() {
|
1476
|
+
this.blocker.classList.remove("-in-regex-editor");
|
1477
|
+
this.blocker.classList.add("-released");
|
1478
|
+
}
|
1479
|
+
|
1480
|
+
#removeRegexVariable() {
|
1481
|
+
this.parentElement.remove();
|
1482
|
+
}
|
1483
|
+
|
1484
|
+
#addRegexVariablesRow() {
|
1485
|
+
const list = document.querySelector("#regexVariablesList");
|
1486
|
+
|
1487
|
+
const wrapper = document.createElement("div");
|
1488
|
+
const name = document.createElement("input");
|
1489
|
+
const value = document.createElement("input");
|
1490
|
+
const remove = document.createElement("button");
|
1491
|
+
|
1492
|
+
name.placeholder = "placeholder";
|
1493
|
+
name.classList.add("placeholder");
|
1494
|
+
value.classList.add("value");
|
1495
|
+
name.autocomplete=false;
|
1496
|
+
value.autocomplete=false;
|
1497
|
+
value.placeholder = "value";
|
1498
|
+
remove.innerHTML = "-";
|
1499
|
+
|
1500
|
+
remove.addEventListener("click", this.#removeRegexVariable.bind(remove));
|
1501
|
+
|
1502
|
+
name.addEventListener("keyup", this.#startRegexEvaluation.bind(this));
|
1503
|
+
value.addEventListener("keyup", this.#startRegexEvaluation.bind(this));
|
1504
|
+
|
1505
|
+
wrapper.classList.add("regex-variable-entry");
|
1506
|
+
|
1507
|
+
wrapper.append(name, value, remove);
|
1508
|
+
list.append(wrapper);
|
1509
|
+
}
|
1510
|
+
|
1240
1511
|
#addUnitExitMapping(ev) {
|
1241
1512
|
const unit = this.selectedUnit;
|
1242
1513
|
const mapping = { use: "", as: "" };
|
@@ -3,6 +3,10 @@ $accent-color: rgb(105, 105, 105);
|
|
3
3
|
$accent-highlight-color: lighten($accent-color, 20%);
|
4
4
|
$accent-contrast-color: darken($accent-color, 20%);
|
5
5
|
|
6
|
+
#importFlowFile {
|
7
|
+
display: none;
|
8
|
+
}
|
9
|
+
|
6
10
|
#execution {
|
7
11
|
position: fixed;
|
8
12
|
display: flex;
|
@@ -37,6 +41,33 @@ $accent-contrast-color: darken($accent-color, 20%);
|
|
37
41
|
}
|
38
42
|
}
|
39
43
|
|
44
|
+
#io {
|
45
|
+
position: fixed;
|
46
|
+
display: flex;
|
47
|
+
flex-direction: row;
|
48
|
+
bottom: 8px;
|
49
|
+
right: 8px;
|
50
|
+
|
51
|
+
div {
|
52
|
+
cursor: pointer;
|
53
|
+
transition: all 250ms ease-in-out;
|
54
|
+
height: 18px;
|
55
|
+
width: 18px;
|
56
|
+
margin-left: 8px;
|
57
|
+
|
58
|
+
&:hover {
|
59
|
+
transform: scale(1.1);
|
60
|
+
}
|
61
|
+
|
62
|
+
svg {
|
63
|
+
path, polygon, line, polyline {
|
64
|
+
fill: white;
|
65
|
+
stroke: white;
|
66
|
+
}
|
67
|
+
}
|
68
|
+
}
|
69
|
+
}
|
70
|
+
|
40
71
|
#addUnit {
|
41
72
|
position: fixed;
|
42
73
|
border-radius: 50%;
|
@@ -507,6 +538,7 @@ $accent-contrast-color: darken($accent-color, 20%);
|
|
507
538
|
}
|
508
539
|
|
509
540
|
input {
|
541
|
+
position: relative;
|
510
542
|
width: 100%;
|
511
543
|
box-sizing: border-box;
|
512
544
|
background-color: $accent-highlight-color;
|
@@ -514,7 +546,7 @@ $accent-contrast-color: darken($accent-color, 20%);
|
|
514
546
|
border: none;
|
515
547
|
outline: none;
|
516
548
|
|
517
|
-
&.-
|
549
|
+
&.-regex {
|
518
550
|
font-family: monospace;
|
519
551
|
}
|
520
552
|
}
|
@@ -649,10 +681,25 @@ $accent-contrast-color: darken($accent-color, 20%);
|
|
649
681
|
flex-direction: row;
|
650
682
|
justify-content: space-between;
|
651
683
|
|
652
|
-
.name {
|
653
|
-
font-size: 1em;
|
654
|
-
font-weight: bold;
|
684
|
+
.name-holder {
|
655
685
|
width: 100%;
|
686
|
+
display: flex;
|
687
|
+
flex-direction: row;
|
688
|
+
|
689
|
+
.name {
|
690
|
+
font-size: 1em;
|
691
|
+
font-weight: bold;
|
692
|
+
}
|
693
|
+
|
694
|
+
#duplicate {
|
695
|
+
margin-left: 5px;
|
696
|
+
width: 10px;
|
697
|
+
cursor: pointer;
|
698
|
+
|
699
|
+
svg path {
|
700
|
+
fill: $accent-contrast-color;
|
701
|
+
}
|
702
|
+
}
|
656
703
|
}
|
657
704
|
|
658
705
|
.delete {
|
@@ -744,7 +791,7 @@ $accent-contrast-color: darken($accent-color, 20%);
|
|
744
791
|
left:0;
|
745
792
|
right:0;
|
746
793
|
bottom:0;
|
747
|
-
background-color:
|
794
|
+
background-color: rgba(0,0,0, .5);
|
748
795
|
transition: opacity 250ms ease-in-out;
|
749
796
|
opacity: 1;
|
750
797
|
|
@@ -771,6 +818,155 @@ $accent-contrast-color: darken($accent-color, 20%);
|
|
771
818
|
}
|
772
819
|
}
|
773
820
|
|
821
|
+
.regexEditor {
|
822
|
+
position: absolute;
|
823
|
+
top: 50%;
|
824
|
+
left: 50%;
|
825
|
+
transform: translate(-50%, -50%);
|
826
|
+
display: none;
|
827
|
+
font-family: Verdana, Geneva, Tahoma, sans-serif;
|
828
|
+
min-width: 70%;
|
829
|
+
flex-direction: row;
|
830
|
+
align-items: center;
|
831
|
+
justify-content: center;
|
832
|
+
|
833
|
+
& > div {
|
834
|
+
background-color: $accent-color;
|
835
|
+
box-shadow: $accent-shadow;
|
836
|
+
border-radius: 5px;
|
837
|
+
display: flex;
|
838
|
+
flex-direction: column;
|
839
|
+
padding: 12px;
|
840
|
+
position: relative;
|
841
|
+
font-size: 16px;
|
842
|
+
|
843
|
+
&:first-child {
|
844
|
+
margin-right: 15px;
|
845
|
+
width: 70%;
|
846
|
+
z-index: 10;
|
847
|
+
font-size: 0.8em;
|
848
|
+
}
|
849
|
+
|
850
|
+
&:last-child {
|
851
|
+
font-size: 0.8em;
|
852
|
+
transform: translateX(-200%);
|
853
|
+
width: 0;
|
854
|
+
box-shadow: 0 0 0 rgba(0,0,0,0);
|
855
|
+
z-index: 9;
|
856
|
+
overflow: hidden;
|
857
|
+
transition: all 250ms ease-in-out;
|
858
|
+
|
859
|
+
&.-visible {
|
860
|
+
transform: translateX(0%);
|
861
|
+
width: 30%;
|
862
|
+
}
|
863
|
+
}
|
864
|
+
}
|
865
|
+
|
866
|
+
label {
|
867
|
+
margin-bottom: 4px;
|
868
|
+
}
|
869
|
+
|
870
|
+
input {
|
871
|
+
margin-bottom: 6px;
|
872
|
+
box-sizing: border-box;
|
873
|
+
background-color: #9c9c9c;
|
874
|
+
padding: 6px 4px;
|
875
|
+
border: none;
|
876
|
+
outline: none;
|
877
|
+
}
|
878
|
+
|
879
|
+
#regexInput {
|
880
|
+
font-family: monospace;
|
881
|
+
font-size: 1.1em;
|
882
|
+
}
|
883
|
+
|
884
|
+
#regexSample {
|
885
|
+
font-size: 0.8em;
|
886
|
+
}
|
887
|
+
|
888
|
+
#regexResults {
|
889
|
+
padding: 8px;
|
890
|
+
background-color:rgb(200, 200, 200);
|
891
|
+
color: black;
|
892
|
+
max-height: 50vh;
|
893
|
+
overflow: auto;
|
894
|
+
display: block;
|
895
|
+
margin-bottom: 30px;
|
896
|
+
font-size: 0.7em;
|
897
|
+
|
898
|
+
table {
|
899
|
+
margin-top: 15px;
|
900
|
+
width: 100%;
|
901
|
+
border-collapse: collapse;
|
902
|
+
|
903
|
+
th, td {
|
904
|
+
text-align: left;
|
905
|
+
border: 1px solid rgba(0,0,0,.3);
|
906
|
+
padding: 4px;
|
907
|
+
}
|
908
|
+
|
909
|
+
tr:nth-child(even) {
|
910
|
+
background-color: rgba(0,0,0,.15);
|
911
|
+
}
|
912
|
+
}
|
913
|
+
}
|
914
|
+
|
915
|
+
#regexVariables {
|
916
|
+
#regexVariablesList {
|
917
|
+
margin-bottom: 15px;
|
918
|
+
}
|
919
|
+
|
920
|
+
.regex-variable-entry {
|
921
|
+
display: flex;
|
922
|
+
flex-direction: row;
|
923
|
+
margin: 2px 0;
|
924
|
+
align-items: center;
|
925
|
+
|
926
|
+
input {
|
927
|
+
width: 100%;
|
928
|
+
margin-bottom: 0;
|
929
|
+
|
930
|
+
&:first-child {
|
931
|
+
margin-right: 5px;
|
932
|
+
}
|
933
|
+
}
|
934
|
+
|
935
|
+
button {
|
936
|
+
margin-left: 5px;
|
937
|
+
}
|
938
|
+
}
|
939
|
+
}
|
940
|
+
|
941
|
+
button {
|
942
|
+
background-color: $accent-highlight-color;
|
943
|
+
border: 1px solid $accent-color;
|
944
|
+
color: black;
|
945
|
+
padding: 3px 6px;
|
946
|
+
cursor: pointer;
|
947
|
+
transition: all 250ms ease-in-out;
|
948
|
+
|
949
|
+
&:hover {
|
950
|
+
background-color: $accent-contrast-color;
|
951
|
+
color: $accent-highlight-color;
|
952
|
+
}
|
953
|
+
}
|
954
|
+
|
955
|
+
#regexEditorToggleVars {
|
956
|
+
float: right;
|
957
|
+
}
|
958
|
+
}
|
959
|
+
|
960
|
+
&.-in-regex-editor {
|
961
|
+
.information {
|
962
|
+
display: none;
|
963
|
+
}
|
964
|
+
|
965
|
+
.regexEditor {
|
966
|
+
display: flex;
|
967
|
+
}
|
968
|
+
}
|
969
|
+
|
774
970
|
&.-released {
|
775
971
|
pointer-events: none;
|
776
972
|
opacity: 0;
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Caixanegra
|
2
|
+
module API
|
3
|
+
module Designer
|
4
|
+
class InputsController < ::Caixanegra::APIController
|
5
|
+
def evaluate_regex
|
6
|
+
full_match = sample.match(Regexp.new(expression, Regexp::IGNORECASE))
|
7
|
+
direct = { "_full": full_match.to_s, "_expression": expression }
|
8
|
+
captures = {}
|
9
|
+
|
10
|
+
(full_match&.captures || []).each_with_index do |capture, index|
|
11
|
+
captures["c#{index}"] = capture
|
12
|
+
end
|
13
|
+
named_captures = full_match&.named_captures || {}
|
14
|
+
|
15
|
+
render json: direct.merge(captures).merge(named_captures).symbolize_keys
|
16
|
+
rescue RegexpError
|
17
|
+
head 422
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def expression
|
23
|
+
@expression ||= params[:expression]
|
24
|
+
end
|
25
|
+
|
26
|
+
def sample
|
27
|
+
@sample ||= params[:sample]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -25,11 +25,28 @@
|
|
25
25
|
</svg>
|
26
26
|
</div>
|
27
27
|
<div id="console">
|
28
|
-
<svg version="1.1"
|
28
|
+
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24" xml:space="preserve">
|
29
29
|
<path d="M24,24H0V0h24V24z M2,22h20V2H6v2h16v2H2V22z M2,4h2V2H2V4z M16,16h-6v-2h6V16z M5.7,15.7l-1.4-1.4L6.6,12L4.3,9.7 l1.4-1.4L9.4,12L5.7,15.7z"/>
|
30
30
|
</svg>
|
31
31
|
</div>
|
32
32
|
</div>
|
33
|
+
<div id="io">
|
34
|
+
<input type="file" id="importFlowFile" accept=".cxn">
|
35
|
+
<div id="importFlow">
|
36
|
+
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24" xml:space="preserve">
|
37
|
+
<polyline id="primary" points="13 9 13 13 9 13" style="fill: none; stroke-linecap: round; stroke-linejoin: round; stroke-width: 2;"></polyline>
|
38
|
+
<line id="primary-2" data-name="primary" x1="3" y1="3" x2="13" y2="13" style="fill: none; stroke-linecap: round; stroke-linejoin: round; stroke-width: 2;"></line>
|
39
|
+
<path id="primary-3" data-name="primary" d="M13.89,5H20a1,1,0,0,1,1,1V20a1,1,0,0,1-1,1H6a1,1,0,0,1-1-1V13.89" style="fill: none; stroke-linecap: round; stroke-linejoin: round; stroke-width: 2;"></path>
|
40
|
+
</svg>
|
41
|
+
</div>
|
42
|
+
<div id="exportFlow">
|
43
|
+
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24" xml:space="preserve">
|
44
|
+
<polyline id="primary" points="17 3 21 3 21 7" style="fill: none; stroke-linecap: round; stroke-linejoin: round; stroke-width: 2;"></polyline>
|
45
|
+
<line id="primary-2" data-name="primary" x1="11" y1="13" x2="21" y2="3" style="fill: none; stroke-linecap: round; stroke-linejoin: round; stroke-width: 2;"></line>
|
46
|
+
<path id="primary-3" data-name="primary" d="M19,13.89V20a1,1,0,0,1-1,1H4a1,1,0,0,1-1-1V6A1,1,0,0,1,4,5h6.11" style="fill: none; stroke-linecap: round; stroke-linejoin: round; stroke-width: 2;"></path>
|
47
|
+
</svg>
|
48
|
+
</div>
|
49
|
+
</div>
|
33
50
|
<div id="addUnit"><span>+</span></div>
|
34
51
|
<div id="save"><span>save</span></div>
|
35
52
|
<div id="unitMenu"></div>
|
@@ -51,7 +68,14 @@
|
|
51
68
|
<div class="color-code"></div>
|
52
69
|
<div class="content">
|
53
70
|
<div id="unitDetailClass" class="unit-detail-headers">
|
54
|
-
<div class="name"
|
71
|
+
<div class="name-holder">
|
72
|
+
<div class="name"></div>
|
73
|
+
<span id="duplicate">
|
74
|
+
<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
|
75
|
+
<path d="M6 6V2c0-1.1.9-2 2-2h10a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2h-4v4a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V8c0-1.1.9-2 2-2h4zm2 0h4a2 2 0 0 1 2 2v4h4V2H8v4zM2 8v10h10V8H2zm4 4v-2h2v2h2v2H8v2H6v-2H4v-2h2z"/>
|
76
|
+
</svg>
|
77
|
+
</span>
|
78
|
+
</div>
|
55
79
|
<div class="delete">
|
56
80
|
<div id="toggler">
|
57
81
|
<svg viewBox="0 0 56 56" xmlns="http://www.w3.org/2000/svg">
|
@@ -84,6 +108,27 @@
|
|
84
108
|
<div>caixa<span>negra</span></div>
|
85
109
|
<div class="message">loading your flow</div>
|
86
110
|
</div>
|
111
|
+
<div class="regexEditor">
|
112
|
+
<div>
|
113
|
+
<label for="regexInput">Regular Expression</label>
|
114
|
+
<input id="regexInput" type="text" />
|
115
|
+
<label for="regexSample" placeholder="type sample text here">Sample</label>
|
116
|
+
<input id="regexSample" type="text" />
|
117
|
+
<label for="regexResults">Result</label>
|
118
|
+
<div id="regexResults"></div>
|
119
|
+
<div>
|
120
|
+
<button id="dismissRegexEditor">dismiss</button>
|
121
|
+
<button id="regexEditorToggleVars">vars</button>
|
122
|
+
</div>
|
123
|
+
</div>
|
124
|
+
<div>
|
125
|
+
<label for="regexVariables">Variables</label>
|
126
|
+
<div id="regexVariables">
|
127
|
+
<div id="regexVariablesList"></div>
|
128
|
+
<button id="addRegexVariables">add</button>
|
129
|
+
</div>
|
130
|
+
</div>
|
131
|
+
</div>
|
87
132
|
</div>
|
88
133
|
<div id="action_messenger">
|
89
134
|
<div class="icon icon-error">
|
data/config/routes.rb
CHANGED
data/lib/caixanegra/manager.rb
CHANGED
data/lib/caixanegra/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: caixanegra
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- sergiorribeiro
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-10-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -57,6 +57,7 @@ files:
|
|
57
57
|
- app/assets/stylesheets/caixanegra/application.css
|
58
58
|
- app/assets/stylesheets/caixanegra/designer.scss
|
59
59
|
- app/controllers/caixanegra/api/designer/flows_controller.rb
|
60
|
+
- app/controllers/caixanegra/api/designer/inputs_controller.rb
|
60
61
|
- app/controllers/caixanegra/api/designer/units_controller.rb
|
61
62
|
- app/controllers/caixanegra/api_controller.rb
|
62
63
|
- app/controllers/caixanegra/application_controller.rb
|