caixanegra 0.2.0 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +10 -14
- data/app/assets/javascripts/caixanegra/designer.js +120 -47
- data/app/assets/stylesheets/caixanegra/designer.scss +15 -0
- data/app/controllers/caixanegra/api/designer/units_controller.rb +2 -1
- data/lib/caixanegra/engine.rb +1 -1
- data/lib/caixanegra/exceptions.rb +18 -2
- data/lib/caixanegra/executor.rb +3 -3
- data/lib/caixanegra/manager.rb +5 -13
- data/lib/caixanegra/transient_store.rb +17 -0
- data/{app/models → lib}/caixanegra/unit.rb +19 -2
- data/lib/caixanegra/version.rb +1 -1
- data/lib/caixanegra.rb +2 -0
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 376caa1d1fc64e8cafb870bbf592dad26520daee9c0ecdb84c3a6d47df67d5c6
|
4
|
+
data.tar.gz: a97853cb0e8e23d05d998a8d10f515784d1699396ee58604f05ce666ebe7d5ee
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cf857f517da162fa54b11aac3e196448b308d7a6dc32776309b37668419af810ea1e62396467a78c96dbd8a6e6b6f9bb6067df6e4c7ea144b6ec757cdd4c7ee1
|
7
|
+
data.tar.gz: 620f9bc6def64b148bfbcfdf0d27a010c75d788275fdfbfe00842a080a60203623db804c0f9951f13b76d516435548f6d966450b4cd1ac3bae9743bf5d42eb5c
|
data/README.md
CHANGED
@@ -16,8 +16,8 @@ or
|
|
16
16
|
bundler add caixanegra
|
17
17
|
```
|
18
18
|
# Getting Started
|
19
|
-
**caixanegra** implements a self-contained designer
|
20
|
-
To get started, the only thing you need is to point to your
|
19
|
+
**caixanegra** implements a self-contained flow designer and executor.
|
20
|
+
To get started, the only thing you need is to point to your [transient store](https://github.com/sergiorribeiro/caixanegra/wiki/The-Transient-Store) implementation and point out which classes on your codebase should represent units.
|
21
21
|
|
22
22
|
First, mount the engine. Add the line below to `routes.rb` file:
|
23
23
|
|
@@ -29,19 +29,17 @@ Then, let's create a `caixanegra.rb` initializer (or any name you prefer)
|
|
29
29
|
|
30
30
|
```ruby
|
31
31
|
Caixanegra.setup do |config|
|
32
|
-
config.units =
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
}
|
39
|
-
config.redis = Redis.new
|
32
|
+
config.units = [
|
33
|
+
Caixanegra::Units::AwesomeUnit,
|
34
|
+
Some::Other::Namespace::AnotherAwesomeUnit,
|
35
|
+
Caixanegra::Units::SuperUnit,
|
36
|
+
]
|
37
|
+
config.transient_store = GreatTransientStore.new
|
40
38
|
end
|
41
39
|
```
|
42
40
|
|
43
41
|
With the designer configured, you can use `Caixanegra::Manager` to handle the previously stored definition (or an empty one).
|
44
|
-
This will give you the UID that **caixanegra** designer will understand.
|
42
|
+
This will give you the UID that **caixanegra** designer will understand, using transient store.
|
45
43
|
|
46
44
|
```ruby
|
47
45
|
my_flow = somewhere.get_flow # get from your own persistence or transport solution
|
@@ -54,15 +52,13 @@ You can then safely navigate to the designer.
|
|
54
52
|
link_to "Some flow", "/caixanegra/design/#{@uid}?unit_scope=optional_scope,another_optional_scope", target: :_blank
|
55
53
|
```
|
56
54
|
|
57
|
-
Saved changes will update the flow definition
|
55
|
+
Saved changes will update the flow definition through the transient store, and you must then persist them. You can get the flow definition for any specified **caixanegra** handled UID, given that the transient store is able to correctly sort them out:
|
58
56
|
|
59
57
|
```ruby
|
60
58
|
updated_flow = Caixanegra::Manager.get(my_uid)
|
61
59
|
persist_flow(updated_flow) # your own persistence or transport solution. It's a JSON
|
62
60
|
```
|
63
61
|
|
64
|
-
**NOTE:** There's currently no managed way to set callbacks on save actions from the designer. Working on it
|
65
|
-
|
66
62
|
Please, refer to [the wiki](https://github.com/sergiorribeiro/caixanegra/wiki) to get to know more about [units](https://github.com/sergiorribeiro/caixanegra/wiki/Anatomy-of-a-unit).
|
67
63
|
|
68
64
|
# License
|
@@ -3,6 +3,7 @@ window.Caixanegra.Designer = {
|
|
3
3
|
#drawValues;
|
4
4
|
title;
|
5
5
|
class;
|
6
|
+
color;
|
6
7
|
type;
|
7
8
|
exits;
|
8
9
|
mappings;
|
@@ -20,6 +21,7 @@ window.Caixanegra.Designer = {
|
|
20
21
|
this.class = params.class || "unspecified";
|
21
22
|
this.exits = params.exits || [];
|
22
23
|
this.mappings = params.mappings || {};
|
24
|
+
this.color = params.color;
|
23
25
|
this.#drawValues = {};
|
24
26
|
this.MARGIN = 10;
|
25
27
|
this.SNAP = 10;
|
@@ -36,7 +38,9 @@ window.Caixanegra.Designer = {
|
|
36
38
|
|
37
39
|
this.size.x = this.UNIT_WIDTH;
|
38
40
|
let hCursor = this.#drawValues.position.y;
|
39
|
-
|
41
|
+
const typeColor = Caixanegra.Designer.typeColor(this);
|
42
|
+
this.#drawValues.unitBgColor = typeColor.background;
|
43
|
+
this.#drawValues.unitFgColor = typeColor.foreground;
|
40
44
|
this.#drawValues.text = {};
|
41
45
|
this.#drawValues.exitRectangles = [];
|
42
46
|
|
@@ -83,25 +87,25 @@ window.Caixanegra.Designer = {
|
|
83
87
|
}
|
84
88
|
|
85
89
|
update(context) {
|
86
|
-
if (context.mouse.down &&
|
90
|
+
if (context.mouse.down &&
|
87
91
|
context.mouse.down.button === 1 &&
|
88
|
-
context.mouse.down.cursorAt &&
|
92
|
+
context.mouse.down.cursorAt &&
|
89
93
|
context.mouse.down.cursorAt.object.oid === this.oid) {
|
90
94
|
this.#beingDragged = true;
|
91
95
|
} else {
|
92
96
|
this.#beingDragged = false;
|
93
97
|
}
|
94
98
|
|
95
|
-
if (context.mouse.move &&
|
99
|
+
if (context.mouse.move &&
|
96
100
|
context.mouse.move.button === 1 &&
|
97
|
-
context.mouse.down &&
|
98
|
-
context.mouse.down.cursorAt &&
|
101
|
+
context.mouse.down &&
|
102
|
+
context.mouse.down.cursorAt &&
|
99
103
|
context.mouse.down.cursorAt.object.oid === this.oid) {
|
100
104
|
const intersection = new Sabertooth.Vector2(
|
101
105
|
context.mouse.down.cursorAt.intersection.x,
|
102
106
|
context.mouse.down.cursorAt.intersection.y
|
103
107
|
);
|
104
|
-
|
108
|
+
|
105
109
|
if (this.connectingExit === null) {
|
106
110
|
for (let eidx = 0; eidx < this.#drawValues.exits.length; eidx++) {
|
107
111
|
if (this.#drawValues.exits[eidx].rectangle.intersectionPoint(intersection)) {
|
@@ -180,7 +184,7 @@ window.Caixanegra.Designer = {
|
|
180
184
|
case "extra":
|
181
185
|
ctx.beginPath();
|
182
186
|
ctx.roundRect(this.#drawValues.position.x, this.#drawValues.position.y, this.size.x, this.size.y, 5);
|
183
|
-
ctx.fillStyle = this.#drawValues.unitBgColor
|
187
|
+
ctx.fillStyle = `rgb(${this.#drawValues.unitBgColor.r}, ${this.#drawValues.unitBgColor.g}, ${this.#drawValues.unitBgColor.b})`;
|
184
188
|
ctx.fill();
|
185
189
|
|
186
190
|
ctx.beginPath();
|
@@ -202,18 +206,20 @@ window.Caixanegra.Designer = {
|
|
202
206
|
);
|
203
207
|
ctx.globalCompositeOperation = gco;
|
204
208
|
|
209
|
+
const rgbString = `${this.#drawValues.unitFgColor.r}, ${this.#drawValues.unitFgColor.g}, ${this.#drawValues.unitFgColor.b}`;
|
210
|
+
|
205
211
|
ctx.textBaseline = "top";
|
206
212
|
ctx.textAlign = "center";
|
207
|
-
ctx.fillStyle =
|
213
|
+
ctx.fillStyle = `rgb(${rgbString})`;
|
208
214
|
ctx.font = "25px Helvetica";
|
209
215
|
ctx.fillText(this.title, this.#drawValues.center.x, this.#drawValues.text.title.y, this.UNIT_WIDTH - this.MARGIN * 2);
|
210
216
|
|
211
|
-
ctx.fillStyle =
|
217
|
+
ctx.fillStyle = `rgba(${rgbString},0.5)`;
|
212
218
|
ctx.font = "18px Helvetica";
|
213
219
|
ctx.fillText(this.class, this.#drawValues.center.x, this.#drawValues.text.class.y, this.UNIT_WIDTH - this.MARGIN * 2);
|
214
220
|
|
215
221
|
ctx.strokeStyle = "#FFF";
|
216
|
-
ctx.fillStyle =
|
222
|
+
ctx.fillStyle = `rgba(${rgbString},0.8)`;
|
217
223
|
ctx.font = "bold 14px monospace";
|
218
224
|
ctx.textAlign = "right";
|
219
225
|
ctx.lineWidth = 2;
|
@@ -269,7 +275,7 @@ window.Caixanegra.Designer = {
|
|
269
275
|
selectedUnit;
|
270
276
|
flowId;
|
271
277
|
unitScope;
|
272
|
-
|
278
|
+
|
273
279
|
constructor(drawingSurface) {
|
274
280
|
this.flowId = this.#extractFlowId();
|
275
281
|
this.unitScope = this.#extractUnitScope();
|
@@ -524,7 +530,7 @@ window.Caixanegra.Designer = {
|
|
524
530
|
unitMenu.innerHTML = "";
|
525
531
|
|
526
532
|
const scopes = [];
|
527
|
-
|
533
|
+
|
528
534
|
this.#catalog.forEach(unit => {
|
529
535
|
if (unit.hasOwnProperty("scope") && Array.isArray(unit.scope)) {
|
530
536
|
scopes.push(...unit.scope);
|
@@ -532,7 +538,7 @@ window.Caixanegra.Designer = {
|
|
532
538
|
scopes.push("_unscoped");
|
533
539
|
}
|
534
540
|
});
|
535
|
-
|
541
|
+
|
536
542
|
[...new Set(scopes)].sort().forEach(scope => {
|
537
543
|
const scopeWrapper = document.createElement("div");
|
538
544
|
const scopeTitle = document.createElement("div");
|
@@ -564,12 +570,13 @@ window.Caixanegra.Designer = {
|
|
564
570
|
colorCode.classList.add("color-code");
|
565
571
|
name.classList.add("name");
|
566
572
|
type.classList.add("type");
|
567
|
-
|
573
|
+
|
568
574
|
name.innerHTML = unitData.title;
|
569
575
|
type.innerHTML = unitData.type;
|
570
576
|
description.innerHTML = unitData.description;
|
571
|
-
|
572
|
-
|
577
|
+
const typeColor = Caixanegra.Designer.typeColor(unitData).background;
|
578
|
+
colorCode.style.backgroundColor = `rgb(${typeColor.r}, ${typeColor.g}, ${typeColor.b})`;
|
579
|
+
|
573
580
|
header.append(name, type);
|
574
581
|
content.append(header, description);
|
575
582
|
item.append(colorCode, content);
|
@@ -641,7 +648,7 @@ window.Caixanegra.Designer = {
|
|
641
648
|
|
642
649
|
this.messenger.querySelector(".message").innerHTML = message;
|
643
650
|
}
|
644
|
-
|
651
|
+
|
645
652
|
createUnit(params) {
|
646
653
|
this.#sequence++;
|
647
654
|
const newUnit = new Caixanegra.Designer.Unit({
|
@@ -649,13 +656,14 @@ window.Caixanegra.Designer = {
|
|
649
656
|
type: params.type,
|
650
657
|
title: params.title,
|
651
658
|
class: params.class,
|
659
|
+
color: params.color,
|
652
660
|
zIndex: this.#sequence
|
653
661
|
});
|
654
662
|
|
655
663
|
if (params.oid) {
|
656
664
|
newUnit.oid = params.oid;
|
657
665
|
newUnit.position = new Sabertooth.Vector2(params.position.x, params.position.y);
|
658
|
-
newUnit.title = params.title;
|
666
|
+
newUnit.title = params.title;
|
659
667
|
}
|
660
668
|
|
661
669
|
if (params.exits && params.exits.length > 0) {
|
@@ -687,7 +695,7 @@ window.Caixanegra.Designer = {
|
|
687
695
|
this.#units.push(newUnit);
|
688
696
|
this.gre.addObject(newUnit);
|
689
697
|
}
|
690
|
-
|
698
|
+
|
691
699
|
removeUnit(oid) {
|
692
700
|
const killIndex = this.#units.findIndex((unit) => {return unit.oid === oid});
|
693
701
|
this.#units.splice(killIndex, 1);
|
@@ -796,7 +804,7 @@ window.Caixanegra.Designer = {
|
|
796
804
|
const endObject = moments.end.cursorAt?.object;
|
797
805
|
|
798
806
|
if (startObject && endObject &&
|
799
|
-
startObject?.connectingExit &&
|
807
|
+
startObject?.connectingExit &&
|
800
808
|
startObject.oid !== endObject.oid) {
|
801
809
|
startObject.connectingExit.reference.target = moments.end.cursorAt.object;
|
802
810
|
startObject.connectingExit = null;
|
@@ -902,7 +910,7 @@ window.Caixanegra.Designer = {
|
|
902
910
|
header.classList.add("hit-header");
|
903
911
|
header.innerHTML = `hit #${idx + 1}`;
|
904
912
|
hitWrapper.append(header);
|
905
|
-
|
913
|
+
|
906
914
|
let section = this.#buildStepHitFold("in", hit.in);
|
907
915
|
if (section !== null) { hitWrapper.append(section); }
|
908
916
|
|
@@ -922,7 +930,8 @@ window.Caixanegra.Designer = {
|
|
922
930
|
const pane = this.unitDetailPane;
|
923
931
|
const debugPane = this.unitDebugHitsPane;
|
924
932
|
const dynamicContent = pane.querySelector("#dynamicContent");
|
925
|
-
|
933
|
+
const typeColor = Caixanegra.Designer.typeColor(object).background;
|
934
|
+
pane.querySelector(".color-code").style.backgroundColor = `rgb(${typeColor.r}, ${typeColor.g}, ${typeColor.b})`;
|
926
935
|
pane.classList.add("-open");
|
927
936
|
|
928
937
|
if (object.debugHits.length > 0) {
|
@@ -932,7 +941,7 @@ window.Caixanegra.Designer = {
|
|
932
941
|
debugPane.querySelector("#debugData").innerHTML = "";
|
933
942
|
debugPane.classList.remove("-open");
|
934
943
|
}
|
935
|
-
|
944
|
+
|
936
945
|
pane.querySelector("#unitDetailTitle").value = object.title;
|
937
946
|
pane.querySelector("#unitDetailClass .name").innerHTML = matrix.class;
|
938
947
|
pane.querySelector("#unitDetailDescription").innerHTML = matrix.description;
|
@@ -1112,7 +1121,7 @@ window.Caixanegra.Designer = {
|
|
1112
1121
|
});
|
1113
1122
|
typeSelector.addEventListener("change", this.#unitInputTypeChanged.bind(this));
|
1114
1123
|
typeSelectorHeader.append(name, typeSelector);
|
1115
|
-
|
1124
|
+
|
1116
1125
|
wrapper.appendChild(typeSelectorHeader);
|
1117
1126
|
wrapper.appendChild(fieldDescription);
|
1118
1127
|
|
@@ -1144,12 +1153,48 @@ window.Caixanegra.Designer = {
|
|
1144
1153
|
valueInput.addEventListener("change", this.#unitInputValueChanged.bind(this));
|
1145
1154
|
}
|
1146
1155
|
break;
|
1156
|
+
case "boolean":
|
1157
|
+
{
|
1158
|
+
const trueInput = document.createElement("input");
|
1159
|
+
const falseInput = document.createElement("input");
|
1160
|
+
const trueInputLabel = document.createElement("label");
|
1161
|
+
const falseInputLabel = document.createElement("label");
|
1162
|
+
const trueRadioGroup = document.createElement("div");
|
1163
|
+
const falseRadioGroup = document.createElement("div");
|
1164
|
+
trueRadioGroup.classList.add("radio-group");
|
1165
|
+
falseRadioGroup.classList.add("radio-group");
|
1166
|
+
trueInput.setAttribute("type", "radio");
|
1167
|
+
falseInput.setAttribute("type", "radio");
|
1168
|
+
trueInput.setAttribute("value", 1);
|
1169
|
+
trueInputLabel.innerHTML = "True";
|
1170
|
+
falseInput.setAttribute("value", 0);
|
1171
|
+
falseInputLabel.innerHTML = "False";
|
1172
|
+
trueInput.setAttribute("name", `b${input}`);
|
1173
|
+
falseInput.setAttribute("name", `b${input}`);
|
1174
|
+
const value = unit.mappings[input]?.value || matrix.default || "0"
|
1175
|
+
if (value === "1") { trueInput.setAttribute("checked", true); }
|
1176
|
+
if (value === "0") { falseInput.setAttribute("checked", true); }
|
1177
|
+
trueInput.addEventListener("change", this.#unitInputValueChanged.bind(this));
|
1178
|
+
falseInput.addEventListener("change", this.#unitInputValueChanged.bind(this));
|
1179
|
+
|
1180
|
+
trueRadioGroup.appendChild(trueInput);
|
1181
|
+
trueRadioGroup.appendChild(trueInputLabel);
|
1182
|
+
falseRadioGroup.appendChild(falseInput);
|
1183
|
+
falseRadioGroup.appendChild(falseInputLabel);
|
1184
|
+
|
1185
|
+
valueWrapper.appendChild(trueRadioGroup);
|
1186
|
+
valueWrapper.appendChild(falseRadioGroup);
|
1187
|
+
}
|
1188
|
+
break;
|
1147
1189
|
}
|
1148
1190
|
|
1149
1191
|
if (unit.mappings[input]?.type !== "user") {
|
1150
1192
|
valueWrapper.classList.add("-disabled");
|
1151
1193
|
}
|
1152
|
-
|
1194
|
+
|
1195
|
+
if(valueInput !== null) {
|
1196
|
+
valueWrapper.appendChild(valueInput);
|
1197
|
+
}
|
1153
1198
|
|
1154
1199
|
wrapper.append(valueWrapper);
|
1155
1200
|
} else {
|
@@ -1212,12 +1257,12 @@ window.Caixanegra.Designer = {
|
|
1212
1257
|
const exitMappings = {};
|
1213
1258
|
|
1214
1259
|
Array.from(exits).forEach((exit) => {
|
1215
|
-
exitMappings[exit.dataset.exit] =
|
1260
|
+
exitMappings[exit.dataset.exit] =
|
1216
1261
|
Array.from(exit.querySelectorAll(".exit-mapping")).map((mapping) => {
|
1217
1262
|
const useValue = mapping.querySelector("input.use").value;
|
1218
1263
|
const asValue = mapping.querySelector("input.as").value;
|
1219
1264
|
return { use: useValue, as: asValue };
|
1220
|
-
});
|
1265
|
+
});
|
1221
1266
|
});
|
1222
1267
|
|
1223
1268
|
for(let idx = 0; idx < unit.exits.length; idx++) {
|
@@ -1262,9 +1307,9 @@ window.Caixanegra.Designer = {
|
|
1262
1307
|
#engineUpdate(ev) {
|
1263
1308
|
const context = ev.detail;
|
1264
1309
|
|
1265
|
-
if (context.mouse.move &&
|
1310
|
+
if (context.mouse.move &&
|
1266
1311
|
[1, 2].includes(context.mouse.move.button) &&
|
1267
|
-
context.mouse.down &&
|
1312
|
+
context.mouse.down &&
|
1268
1313
|
context.mouse.down.cursorAt === null) {
|
1269
1314
|
const offset = {
|
1270
1315
|
x: context.mouse.move.internal_x - context.mouse.down.internal_x,
|
@@ -1273,7 +1318,7 @@ window.Caixanegra.Designer = {
|
|
1273
1318
|
|
1274
1319
|
this.gre.worldCenter.x = context.mouse.down.referential.x + offset.x;
|
1275
1320
|
this.gre.worldCenter.y = context.mouse.down.referential.y + offset.y;
|
1276
|
-
|
1321
|
+
|
1277
1322
|
for (let oidx = 0; oidx < context.objects.length; oidx++) {
|
1278
1323
|
context.objects[oidx].initialize(this.gre.engineContext());
|
1279
1324
|
}
|
@@ -1288,23 +1333,51 @@ window.Caixanegra.Designer = {
|
|
1288
1333
|
}
|
1289
1334
|
},
|
1290
1335
|
|
1291
|
-
typeColor: (
|
1292
|
-
|
1293
|
-
|
1294
|
-
|
1295
|
-
|
1296
|
-
|
1297
|
-
|
1298
|
-
|
1299
|
-
|
1300
|
-
|
1301
|
-
|
1302
|
-
|
1303
|
-
|
1304
|
-
|
1305
|
-
|
1306
|
-
|
1336
|
+
typeColor: (unit) => {
|
1337
|
+
let baseColor = unit.color || undefined;
|
1338
|
+
|
1339
|
+
if (baseColor === undefined) {
|
1340
|
+
switch (unit.type) {
|
1341
|
+
case "starter":
|
1342
|
+
baseColor = "#65CCA9";
|
1343
|
+
break;
|
1344
|
+
case "terminator":
|
1345
|
+
baseColor = "#E44";
|
1346
|
+
break;
|
1347
|
+
case "blackbox":
|
1348
|
+
baseColor = "#EEE";
|
1349
|
+
break;
|
1350
|
+
case "passthrough":
|
1351
|
+
baseColor = "#C4C66A";
|
1352
|
+
break;
|
1353
|
+
case "fork":
|
1354
|
+
baseColor = "#FFCC5C"
|
1355
|
+
break;
|
1356
|
+
case "feeder":
|
1357
|
+
baseColor = "#5A92D8";
|
1358
|
+
break;
|
1359
|
+
default:
|
1360
|
+
baseColor = "#F00";
|
1361
|
+
break;
|
1362
|
+
}
|
1363
|
+
}
|
1364
|
+
|
1365
|
+
hex = baseColor.replace("#", "");
|
1366
|
+
|
1367
|
+
if (hex.length === 3) {
|
1368
|
+
hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];
|
1307
1369
|
}
|
1370
|
+
|
1371
|
+
const r = parseInt(hex.substring(0, 2), 16);
|
1372
|
+
const g = parseInt(hex.substring(2, 4), 16);
|
1373
|
+
const b = parseInt(hex.substring(4, 6), 16);
|
1374
|
+
|
1375
|
+
const luminance = (0.2126 * r + 0.7152 * g + 0.0722 * b) / 255;
|
1376
|
+
|
1377
|
+
return {
|
1378
|
+
background: { r, g, b },
|
1379
|
+
foreground: luminance > 0.5 ? { r: 0, g: 0, b: 0 } : { r: 255, g: 255, b: 255 }
|
1380
|
+
};
|
1308
1381
|
}
|
1309
1382
|
}
|
1310
1383
|
|
@@ -597,6 +597,9 @@ $accent-contrast-color: darken($accent-color, 20%);
|
|
597
597
|
|
598
598
|
.unit-input {
|
599
599
|
.unit-input-value {
|
600
|
+
display: flex;
|
601
|
+
justify-content: center;
|
602
|
+
|
600
603
|
&.-disabled {
|
601
604
|
display: none;
|
602
605
|
|
@@ -604,6 +607,18 @@ $accent-contrast-color: darken($accent-color, 20%);
|
|
604
607
|
pointer-events: none;
|
605
608
|
}
|
606
609
|
}
|
610
|
+
|
611
|
+
.radio-group {
|
612
|
+
display: flex;
|
613
|
+
|
614
|
+
&:first-child {
|
615
|
+
margin-right: 20px;
|
616
|
+
}
|
617
|
+
|
618
|
+
input, label {
|
619
|
+
display: inline;
|
620
|
+
}
|
621
|
+
}
|
607
622
|
}
|
608
623
|
}
|
609
624
|
|
data/lib/caixanegra/engine.rb
CHANGED
@@ -1,7 +1,23 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Caixanegra
|
4
|
-
class UnitScopedException < StandardError
|
5
|
-
|
4
|
+
class UnitScopedException < StandardError
|
5
|
+
attr_reader :unit
|
6
|
+
|
7
|
+
def initialize(exception, unit)
|
8
|
+
@unit = unit
|
9
|
+
super(exception.message)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class UnitIOException < StandardError
|
14
|
+
attr_reader :unit
|
15
|
+
|
16
|
+
def initialize(unit)
|
17
|
+
@unit = unit
|
18
|
+
super
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
6
22
|
class ContinuityException < StandardError; end
|
7
23
|
end
|
data/lib/caixanegra/executor.rb
CHANGED
@@ -29,9 +29,9 @@ module Caixanegra
|
|
29
29
|
log_console_entry 'Started'
|
30
30
|
set_start_unit
|
31
31
|
format_result(flow_through)
|
32
|
-
rescue Caixanegra::UnitScopedException => e
|
32
|
+
rescue Caixanegra::UnitScopedException, Caixanegra::UnitIOException => e
|
33
33
|
log_step_exception(e)
|
34
|
-
log_console_entry("Unit error: #{e.message}")
|
34
|
+
log_console_entry("Unit '#{e.unit.oid}' error: #{e.message}")
|
35
35
|
format_result(e.message)
|
36
36
|
rescue => e
|
37
37
|
log_console_entry("Error: #{e.message}")
|
@@ -107,7 +107,7 @@ module Caixanegra
|
|
107
107
|
@storage.merge! @step_unit.current_storage
|
108
108
|
result
|
109
109
|
rescue => e
|
110
|
-
exception = Caixanegra::UnitScopedException.new(e)
|
110
|
+
exception = Caixanegra::UnitScopedException.new(e, @step_unit)
|
111
111
|
exception.set_backtrace(e.backtrace)
|
112
112
|
raise exception
|
113
113
|
end
|
data/lib/caixanegra/manager.rb
CHANGED
@@ -4,28 +4,20 @@ module Caixanegra
|
|
4
4
|
class Manager
|
5
5
|
class << self
|
6
6
|
def handler(flow_definition = {})
|
7
|
-
|
7
|
+
transient_store = Caixanegra.transient_store
|
8
|
+
uid = transient_store.new_uid
|
8
9
|
|
9
|
-
|
10
|
-
pipeline.hset(:caixanegra, uid, JSON.dump(flow_definition))
|
11
|
-
pipeline.expire(:caixanegra, 1.hour)
|
12
|
-
end
|
10
|
+
transient_store.hold(uid, flow_definition)
|
13
11
|
|
14
12
|
uid
|
15
13
|
end
|
16
14
|
|
17
|
-
def destroy
|
18
|
-
Caixanegra.redis.hdel(:caixanegra, key)
|
19
|
-
end
|
20
|
-
|
21
15
|
def get(uid)
|
22
|
-
|
23
|
-
|
24
|
-
JSON.parse(value) if value.present?
|
16
|
+
Caixanegra.transient_store.get(uid)
|
25
17
|
end
|
26
18
|
|
27
19
|
def set(uid, flow_definition)
|
28
|
-
Caixanegra.
|
20
|
+
Caixanegra.transient_store.hold(uid, definition: flow_definition)
|
29
21
|
end
|
30
22
|
end
|
31
23
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Caixanegra
|
4
|
+
class TransientStore
|
5
|
+
def get(uid)
|
6
|
+
raise NotImplementedError, "Transient Store needs to implement 'get(uid)'"
|
7
|
+
end
|
8
|
+
|
9
|
+
def hold(uid, definition: {})
|
10
|
+
raise NotImplementedError, "Transient Store needs to implement 'hold(uid, definition: {})'"
|
11
|
+
end
|
12
|
+
|
13
|
+
def new_uid
|
14
|
+
raise NotImplementedError, "Transient Store needs to implement 'new_uid'"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -73,7 +73,7 @@ module Caixanegra
|
|
73
73
|
|
74
74
|
input_value.presence || @inputs[id][:default]
|
75
75
|
rescue StandardError
|
76
|
-
raise(UnitIOException.new, "Unable to fetch input '#{id}'")
|
76
|
+
raise(UnitIOException.new(self), "Unable to fetch input '#{id}'")
|
77
77
|
end
|
78
78
|
|
79
79
|
def scope
|
@@ -100,6 +100,10 @@ module Caixanegra
|
|
100
100
|
self.class.set || []
|
101
101
|
end
|
102
102
|
|
103
|
+
def color
|
104
|
+
self.class.color
|
105
|
+
end
|
106
|
+
|
103
107
|
private
|
104
108
|
|
105
109
|
def set_mapping_defaults
|
@@ -112,7 +116,16 @@ module Caixanegra
|
|
112
116
|
end
|
113
117
|
|
114
118
|
class << self
|
115
|
-
attr_reader
|
119
|
+
attr_reader(
|
120
|
+
:unit_name,
|
121
|
+
:description,
|
122
|
+
:inputs,
|
123
|
+
:exits,
|
124
|
+
:assignments,
|
125
|
+
:type,
|
126
|
+
:scope,
|
127
|
+
:color
|
128
|
+
)
|
116
129
|
|
117
130
|
@type = :passthrough
|
118
131
|
|
@@ -143,6 +156,10 @@ module Caixanegra
|
|
143
156
|
def configure_assignments(assignments)
|
144
157
|
@assignments = assignments
|
145
158
|
end
|
159
|
+
|
160
|
+
def configure_color(color)
|
161
|
+
@color = color
|
162
|
+
end
|
146
163
|
end
|
147
164
|
end
|
148
165
|
end
|
data/lib/caixanegra/version.rb
CHANGED
data/lib/caixanegra.rb
CHANGED
@@ -1,10 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'caixanegra/exceptions'
|
4
|
+
require 'caixanegra/unit'
|
4
5
|
require 'caixanegra/unit_helper'
|
5
6
|
require 'caixanegra/engine'
|
6
7
|
require 'caixanegra/version'
|
7
8
|
require 'caixanegra/executor'
|
8
9
|
require 'caixanegra/manager'
|
10
|
+
require 'caixanegra/transient_store'
|
9
11
|
|
10
12
|
module Caixanegra ; 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
|
+
version: 0.3.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-09-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -61,7 +61,6 @@ files:
|
|
61
61
|
- app/controllers/caixanegra/api_controller.rb
|
62
62
|
- app/controllers/caixanegra/application_controller.rb
|
63
63
|
- app/controllers/caixanegra/designer_controller.rb
|
64
|
-
- app/models/caixanegra/unit.rb
|
65
64
|
- app/views/caixanegra/designer/index.html.erb
|
66
65
|
- app/views/layouts/caixanegra/application.html.erb
|
67
66
|
- app/views/shared/caixanegra/_js_dependencies.html.erb
|
@@ -71,6 +70,8 @@ files:
|
|
71
70
|
- lib/caixanegra/exceptions.rb
|
72
71
|
- lib/caixanegra/executor.rb
|
73
72
|
- lib/caixanegra/manager.rb
|
73
|
+
- lib/caixanegra/transient_store.rb
|
74
|
+
- lib/caixanegra/unit.rb
|
74
75
|
- lib/caixanegra/unit_helper.rb
|
75
76
|
- lib/caixanegra/version.rb
|
76
77
|
- lib/tasks/caixanegra_tasks.rake
|