caixanegra 0.2.0 → 0.3.0
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 +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/app/models/caixanegra/unit.rb +19 -2
- 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/lib/caixanegra/version.rb +1 -1
- data/lib/caixanegra.rb +1 -0
- 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: ece5f658699dfddfd51744c4f78b12b207e9e7108359e9d6d4f39366a494987e
|
4
|
+
data.tar.gz: 0e0fca0b8abdcc03cfd9851563105300d4a6033206917df7fe7d3d49a3cd00d7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4db14867bd4861f76e4ffe49be5f8c35094b6f16e045bb6b2023b72067780e06faac4ea6f0afdd483b4f1dec847d6888c28060abc4dbf443aab10505782b64dd
|
7
|
+
data.tar.gz: df495aa1270c312c87f52b194a93a4c3022db83203b71a24256321e3af5f33489cd02b9b01f6c645402299195f4890623253b78fc6f081bee5f157d17aaf22b4
|
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
|
|
@@ -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/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
|
data/lib/caixanegra/version.rb
CHANGED
data/lib/caixanegra.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.3.0
|
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-08-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -71,6 +71,7 @@ files:
|
|
71
71
|
- lib/caixanegra/exceptions.rb
|
72
72
|
- lib/caixanegra/executor.rb
|
73
73
|
- lib/caixanegra/manager.rb
|
74
|
+
- lib/caixanegra/transient_store.rb
|
74
75
|
- lib/caixanegra/unit_helper.rb
|
75
76
|
- lib/caixanegra/version.rb
|
76
77
|
- lib/tasks/caixanegra_tasks.rake
|