-
Notifications
You must be signed in to change notification settings - Fork 25
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: set_item action: optionally target an index or id #2215
Changes from 24 commits
882cc4e
33ac196
a406ad2
93d7102
11831a9
63f4d7f
4107611
60d5ef0
89885d5
40e86f9
e1ea106
8b3b134
afad693
c3a014d
06cc641
3ca52ca
c75bb43
989a715
5108803
f9f17ca
5c21fd8
fda82d6
f96209d
40c98cf
ef3047a
b8074b9
e262c20
350bd47
9f9f483
1b1e782
2e04f56
b315003
72f89bb
9ea2aeb
c327d3a
8a95b0d
2a2f1e5
daddda1
a0120e3
378f256
149c868
04168d3
74a3efb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,7 +6,7 @@ import { FlowTypes } from "data-models"; | |
import { environment } from "src/environments/environment"; | ||
import { AppDataService } from "../data/app-data.service"; | ||
import { AsyncServiceBase } from "../asyncService.base"; | ||
import { arrayToHashmap, deepMergeObjects } from "../../utils"; | ||
import { arrayToHashmap, deepMergeObjects, evaluateJSExpression } from "../../utils"; | ||
import { PersistedMemoryAdapter } from "./adapters/persistedMemory"; | ||
import { ReactiveMemoryAdapater, REACTIVE_SCHEMA_BASE } from "./adapters/reactiveMemory"; | ||
import { TemplateActionRegistry } from "../../components/template/services/instance/template-action.registry"; | ||
|
@@ -66,9 +66,39 @@ export class DynamicDataService extends AsyncServiceBase { | |
} | ||
private registerTemplateActionHandlers() { | ||
this.templateActionRegistry.register({ | ||
/** | ||
* Write properties on the current item (default), or on an explicitly targeted item, | ||
* e.g. | ||
* click | set_item | completed:true; | ||
* click | set_item | _id: @item.id, completed:true; | ||
* click | set_item | _index: @item._index + 1, completed:true; | ||
*/ | ||
set_item: async ({ args, params }) => { | ||
const [flow_name, row_id] = args; | ||
await this.update("data_list", flow_name, row_id, params); | ||
const [flow_name, itemDataIDs, itemIndex] = args; | ||
const { _index, _id, ...writeableProps } = params; | ||
|
||
// Target current row if another target is not explicitly provided | ||
let targetRowId = itemDataIDs[itemIndex]; | ||
if (_index !== undefined) { | ||
targetRowId = itemDataIDs[_index]; | ||
} | ||
if (_id) { | ||
targetRowId = _id; | ||
} | ||
|
||
if (itemDataIDs.includes(targetRowId)) { | ||
console.log( | ||
`[SET ITEM] - Setting properties on ${targetRowId}: ${JSON.stringify(writeableProps)}` | ||
); | ||
await this.update("data_list", flow_name, targetRowId, writeableProps); | ||
} else { | ||
if (_id) { | ||
console.warn(`[SET ITEM] - No item with ID ${_id}`); | ||
} | ||
if (_index !== undefined) { | ||
console.warn(`[SET ITEM] - No item at index ${_index}`); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit(blocking): I feel like this is a large amount of item-specific logic being handled in the dynamic-data service. Would it be possible to move the item selection logic to the items component instead, so that the action is always triggered with the correct item index instead? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeh, I can see why having the logic here isn't great, but there's an issue with putting it in the data-items component itself: In order to extract the item-specific logic from the dynamic data service, perhaps it would be sensible to add a new For now, I've just tidied the logic and extracted it to a (testable) function. I muddled the commits somewhat, but looking at the differences since your last review should be instructive. |
||
} | ||
}, | ||
set_items: async ({ args, params }) => { | ||
const [flow_name, row_ids] = args; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This took me ages to figure out! There may be a nicer solution, but this is why something like this is needed:
Even though we have the check lower down (line 393), without this additional check then the string gets evaluated as JS, without the dynamic evaluator value being replaced. This meant that my string
@item._index + 1
was being evaluated as JS beforeitemContext
was available, evaluating to@item._index1
because it was treated as the addition of a string and a number,"@item._index" + 1
. Then, when the expression was re-evaluated after the data-items component had added theitemContext
,@item._index1
was evaluated with the value of@item_index
replaced. For the item at index0
, this actually meant the expression evaluated as01
, i.e.1
, and so for that one case the evaluation actually gave the expected value, which appeared as a false positive in my testing...There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Really useful to catch, it would be good to include such things in spec test if possible