caixanegra 0.4.0 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 002efa6f5c1a220426d102e5f055b50eff9fb55e5742d6c2c33d6474f890fd8a
4
- data.tar.gz: 03c265dbfa950af4d043bfc56711593b2cb1661f76fc2ca40327fbc7a7f5e309
3
+ metadata.gz: 182cc119673359db756adcca903e137025ed5283bdae367d7d6c662fc5fdc061
4
+ data.tar.gz: f075d702d2f361678a7775d286cb7f3b9ec1cb556778b22c4180588efe32d830
5
5
  SHA512:
6
- metadata.gz: da48c854b8646515af968b7c685cece267a5bed236f1f58d5331de39a2d75bded3f0896b84d09de7cbe70c0fad7f388ef5891684bc04f45995e0b1afdc9d1784
7
- data.tar.gz: 28b98d23640368db0f32475c4cd6209fb39648e723e63d70ae2fd814e88c05ca6c9033dccc1accfa3c2c331413569fb54e1b52f115cc26841703019dec4fa0a2
6
+ metadata.gz: 29c0edd8fab4949cab99f6d513b987cda6c87b2fb29fbeb33e447616ff580c0a9fbd3413a2fe4281828f28a8ac1123942fcecbdbeedf7511c64cb000384bd797
7
+ data.tar.gz: 23e9e398d71b3900759d8a944f20ddf1920ac1f38bb5961d3e36a34d112e36a488301d3c4709de8c9cfc48a8a9f995869ebfea90ed20acf72915b6c61ac48345
@@ -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
  }
@@ -307,6 +307,11 @@ window.Caixanegra.Designer = {
307
307
  document.querySelector("#importFlow").addEventListener("click", this.#importFlow.bind(this));
308
308
  document.querySelector("#exportFlow").addEventListener("click", this.#exportFlow.bind(this));
309
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));
310
315
  this.toggleBlocker(true, "loading your flow");
311
316
  window.addEventListener("resize", this.#windowResized.bind(drawingSurface));
312
317
  drawingSurface.addEventListener("update_start", this.#engineUpdate.bind(this));
@@ -319,7 +324,6 @@ window.Caixanegra.Designer = {
319
324
 
320
325
  this.gre.disable();
321
326
  this.getUnits();
322
- this.loadFlow();
323
327
  this.gre.enable();
324
328
  }
325
329
 
@@ -600,7 +604,7 @@ window.Caixanegra.Designer = {
600
604
  });
601
605
 
602
606
  this.#loadedComponents.catalog = true;
603
- this.reveal();
607
+ this.loadFlow();
604
608
  });
605
609
  }
606
610
 
@@ -620,6 +624,10 @@ window.Caixanegra.Designer = {
620
624
  this.#units = [];
621
625
 
622
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
+ }
623
631
  this.createUnit(unit);
624
632
  });
625
633
 
@@ -1278,9 +1286,10 @@ window.Caixanegra.Designer = {
1278
1286
  case "regex":
1279
1287
  {
1280
1288
  valueInput = document.createElement("input");
1281
- if(matrix.type === "regex") { valueInput.classList.add("-monospace")}
1289
+ if(matrix.type === "regex") { valueInput.classList.add("-regex")}
1282
1290
  valueInput.value = unit.mappings[input]?.value || matrix.default || "";
1283
1291
  valueInput.addEventListener("change", this.#unitInputValueChanged.bind(this));
1292
+ valueInput.addEventListener("click", this.#regexEditor.bind(this));
1284
1293
  }
1285
1294
  break;
1286
1295
  case "dataset":
@@ -1380,6 +1389,125 @@ window.Caixanegra.Designer = {
1380
1389
  this.selectedUnit.mappings[input].value = ev.target.value;
1381
1390
  }
1382
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
+
1383
1511
  #addUnitExitMapping(ev) {
1384
1512
  const unit = this.selectedUnit;
1385
1513
  const mapping = { use: "", as: "" };
@@ -538,6 +538,7 @@ $accent-contrast-color: darken($accent-color, 20%);
538
538
  }
539
539
 
540
540
  input {
541
+ position: relative;
541
542
  width: 100%;
542
543
  box-sizing: border-box;
543
544
  background-color: $accent-highlight-color;
@@ -545,7 +546,7 @@ $accent-contrast-color: darken($accent-color, 20%);
545
546
  border: none;
546
547
  outline: none;
547
548
 
548
- &.-monospace {
549
+ &.-regex {
549
550
  font-family: monospace;
550
551
  }
551
552
  }
@@ -790,7 +791,7 @@ $accent-contrast-color: darken($accent-color, 20%);
790
791
  left:0;
791
792
  right:0;
792
793
  bottom:0;
793
- background-color: rgb(0,0,0);
794
+ background-color: rgba(0,0,0, .5);
794
795
  transition: opacity 250ms ease-in-out;
795
796
  opacity: 1;
796
797
 
@@ -817,6 +818,155 @@ $accent-contrast-color: darken($accent-color, 20%);
817
818
  }
818
819
  }
819
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
+
820
970
  &.-released {
821
971
  pointer-events: none;
822
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
@@ -108,6 +108,27 @@
108
108
  <div>caixa<span>negra</span></div>
109
109
  <div class="message">loading your flow</div>
110
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>
111
132
  </div>
112
133
  <div id="action_messenger">
113
134
  <div class="icon icon-error">
data/config/routes.rb CHANGED
@@ -9,6 +9,9 @@ Caixanegra::Engine.routes.draw do
9
9
  patch :debug_run
10
10
  end
11
11
  end
12
+ namespace :inputs do
13
+ get :evaluate_regex
14
+ end
12
15
  end
13
16
  end
14
17
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Caixanegra
4
- VERSION = '0.4.0'
4
+ VERSION = '0.4.1'
5
5
  end
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.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-10-04 00:00:00.000000000 Z
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