Skip to content
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

Refactor/set data action #2454

Draft
wants to merge 65 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
3482d27
refactor: wip set_item action handling
chrismclarke Aug 30, 2024
54b43c2
refactor: dynamic data action tests
chrismclarke Aug 30, 2024
a872922
refactor: set_items refs
chrismclarke Aug 30, 2024
dead04c
chore: code tidying
chrismclarke Aug 30, 2024
ba1f774
chore: code tidying
chrismclarke Aug 30, 2024
75d302e
chore: code tidying
chrismclarke Aug 30, 2024
93a7ee0
Merge branch 'master' of https://github.com/IDEMSInternational/parent…
chrismclarke Sep 3, 2024
a37c6f6
fix: set_items external
chrismclarke Sep 3, 2024
0c207e3
test: bulk set_items
chrismclarke Sep 3, 2024
0b5ac54
Merge branch 'master' into refactor/set-item-action
esmeetewinkel Sep 10, 2024
a27eb0f
test: updated tests for data-items component
jfmcquade Sep 16, 2024
9ed782d
Merge branch 'master' into refactor/set-item-action
jfmcquade Sep 16, 2024
f06ec42
Merge branch 'master' into refactor/set-item-action
esmeetewinkel Sep 20, 2024
a7dbbb5
Merge branch 'master' into refactor/set-item-action
esmeetewinkel Sep 24, 2024
74e57e7
Merge branch 'master' into refactor/set-item-action
esmeetewinkel Oct 1, 2024
e291bd6
Merge branch 'master' into refactor/set-item-action
chrismclarke Oct 2, 2024
0ab89bb
feat: add appStringEvaluator support for any input data types
chrismclarke Oct 3, 2024
b344b84
chore: code tidying
chrismclarke Oct 3, 2024
5ebbbdc
feat: add dynamic-data service mock
chrismclarke Oct 3, 2024
ca8e462
refactor: data-items component, actions and spec tests
chrismclarke Oct 3, 2024
2ea19f3
chore: code tidying
chrismclarke Oct 3, 2024
92cbef9
chore: update data-items to use signals
chrismclarke Oct 3, 2024
23f36aa
feat: wip data-items update
chrismclarke Oct 8, 2024
8a15ed2
chore: code tidying
chrismclarke Oct 8, 2024
f9f212e
chore: code tidying
chrismclarke Oct 8, 2024
48b623a
chore: code tidying
chrismclarke Oct 8, 2024
3a5184f
feat: refactor appDataEvaluator to handle mixed js and string templating
chrismclarke Oct 8, 2024
995e628
fix: appDataEvaluator imports
chrismclarke Oct 8, 2024
fff347e
feat: wip data-items standalone processing
chrismclarke Oct 8, 2024
289941b
chore: code tidying
chrismclarke Oct 8, 2024
b12f538
Merge branch 'master' of https://github.com/IDEMSInternational/parent…
chrismclarke Oct 23, 2024
54fce39
chore: restore auto lint
chrismclarke Oct 23, 2024
9d17e40
refactor: templatedData context variable list
chrismclarke Oct 23, 2024
81a44d9
fix: multiple context delimiters
chrismclarke Oct 24, 2024
02f3225
chore: update appDataEvaluator tests
chrismclarke Oct 24, 2024
e015f58
chore: code tidying
chrismclarke Oct 24, 2024
676074c
feat: wip data-items separate service
chrismclarke Oct 24, 2024
f3cc2dc
fix: app data evaluator js bypass
chrismclarke Oct 24, 2024
dd082ec
chore: code tidying
chrismclarke Oct 24, 2024
8490989
Merge branch 'master' of https://github.com/IDEMSInternational/parent…
chrismclarke Oct 24, 2024
316e497
feat: add template signals and equality check
chrismclarke Oct 24, 2024
3d1af85
chore: add template actionList signal
chrismclarke Oct 24, 2024
33e1b52
Merge branch 'feat/template-signals' of https://github.com/IDEMSInter…
chrismclarke Oct 26, 2024
a027370
chore: move dynamic prefix definitions
chrismclarke Oct 28, 2024
53e927d
Merge branch 'refactor/array-to-hashmap' of https://github.com/IDEMSI…
chrismclarke Oct 29, 2024
1f30d1e
refactor: item pipe standalone
chrismclarke Oct 30, 2024
449ea04
feat: wip data-items updates
chrismclarke Oct 30, 2024
5ffb386
Merge branch 'master' into refactor/set-data-action
chrismclarke Oct 30, 2024
7f24f70
refactor: data-item utils
chrismclarke Nov 1, 2024
3d3dd37
refactor: data actions spec
chrismclarke Nov 7, 2024
0fa81e9
Merge branch 'master' of https://github.com/idemsinternational/open-a…
chrismclarke Nov 7, 2024
0ff8966
refactor: mock error handler service
chrismclarke Nov 7, 2024
1283008
chore: code tidying
chrismclarke Nov 7, 2024
dc06b90
chore: code tidying
chrismclarke Nov 7, 2024
8f1acb3
feat: set_data action standalone
chrismclarke Nov 7, 2024
82ba9ed
refactor: mock error handler service
chrismclarke Nov 7, 2024
f5611bf
fix: item change checks
chrismclarke Nov 7, 2024
839c729
Merge branch 'feat/set-data-action-standalone' of https://github.com/…
chrismclarke Nov 7, 2024
e99ab48
feat: add reset_data action
chrismclarke Nov 8, 2024
8a681c6
fix: template parsed param handling
chrismclarke Nov 8, 2024
2cab98b
feat: add support for data type coercion
chrismclarke Nov 9, 2024
7184921
test: reset action and type coercion
chrismclarke Nov 9, 2024
afe1034
chore: code tidying
chrismclarke Nov 9, 2024
1a4f924
Merge branch 'master' into feat/set-data-action-standalone
chrismclarke Nov 9, 2024
4887284
Merge branch 'feat/set-data-action-standalone' of https://github.com/…
chrismclarke Nov 9, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/data-models/flowTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,7 @@ export namespace FlowTypes {
"pop_up",
"process_template",
"reset_app",
"reset_data",
"save_to_device",
"screen_orientation",
"set_field",
Expand Down
19 changes: 10 additions & 9 deletions packages/shared/src/models/templatedData/templatedData.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ interface ITestData {
output: any; // Expected end parsed data
}

/** This context is applied to all tests. Input will be processed for subsitition into output */
/** This context is applied to all tests. Input will be processed for substitution into output */
const context = {
input: {
row: {
Expand Down Expand Up @@ -127,37 +127,38 @@ describe("Templated Data Parsing", () => {
});

/**
* Text extract method of
* Text extract method
* yarn workspace shared test --filter "Templated Data Extraction"
*/
describe("Templated Data Extraction", () => {
const extractTests: ITestData[] = [
{
input: "hello @row.value_1 @row.value_2",
output: { row: { value_1: true, value_2: true } },
output: { row: { value_1: "", value_2: "" } },
},
{
input: "hello @row.value_1.child_property",
output: { row: { value_1: true } },
output: { row: { value_1: "" } },
},
{
input: "@unknown_prefix.value",
output: {},
},
{
input: "@[email protected]_value",
output: { row: { __recursive: true, recursive_value: true } },
output: { row: { "*": "", recursive_value: "" } },
},
{
input: "@row.row_value @field.field_value",
output: { row: { row_value: true }, field: { field_value: true } },
output: { row: { row_value: "" }, field: { field_value: "" } },
},
{
input: {
string: "hello @row.value_1",
array: ["@row.value_2", "@row.value_3"],
nested: { string: ["@row.value_4"] },
},
output: { row: { value_1: true, value_2: true, value_3: true, value_4: true } },
output: { row: { value_1: "", value_2: "", value_3: "", value_4: "" } },
},
];
// Test individual string parsing
Expand All @@ -170,8 +171,8 @@ describe("Templated Data Extraction", () => {
const { input, output } = testData;
it(JSON.stringify(input), () => {
const parser = new TemplatedData();
const parsedValue = parser.listContextVariables(input, ["row", "field"]);
expect(parsedValue).toEqual(output);
const contextVariables = parser.listContextVariables(input, ["row", "field"]);
expect(contextVariables).toEqual(output);
// process.nextTick(() => console.log(` ${JSON.stringify(parsedValue)}\n`));
});
}
Expand Down
64 changes: 29 additions & 35 deletions packages/shared/src/models/templatedData/templatedData.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,12 @@
import { ITemplatedStringVariable } from "../../types";
import { addStringDelimiters, extractDelimitedTemplateString } from "../../utils/delimiters";
import { isObjectLiteral } from "../../utils/object-utils";

type ITemplatedDataContext = { [prefix: string]: any };
import type { FlowTypes } from "data-models";

/** Hashmap of all context-based variable names used in expression, organised by prefix, e.g.
* `{ field: {some_field_name: true}, row: {some_row_name:true, another_name: true}}`
* `{ field: {some_field_name: ""}, row: {some_row_name:"", another_name: ""}}`
*/

export interface ITemplatedDataContextList {
[contextPrefix: string]: {
[contextVariableName: string]: boolean;
/**
* Track whether variable list known to contain recursive variables that will
* require runtime evaluation, e.g. `{ field: {some_field_name: true, __recursive: true}`
*/
__recursive?: boolean;
};
}
export type ITemplatedDataContext = { [prefix in FlowTypes.IDynamicPrefix]?: Record<string, any> };

/**
* Templated data class contains methods to to convert data containing dynamic context variables
Expand All @@ -31,12 +20,15 @@ export class TemplatedData {
/** Value returned after parsing templated data, e.g. `"Hello example_1"` */
public parsedValue: any;

/** json object containing namespaced values for context replacements
/** json object containing flattened values for context replacements
* ```
* {row:{id:"example_1"}}
* {
* "@row":{id:"example_1"}
* "@row.id": "example_1"
* }
* ```
*/
public parsedContext: ITemplatedDataContext;
public parsedContext: Record<string, any>;

/** List of all prefixes used in context, e.g `["row"]` */
private contextPrefixes: string[] = [];
Expand Down Expand Up @@ -74,19 +66,20 @@ export class TemplatedData {
* Iterate over data, parse string values and nested objects and arrays recursively
*/
public parse<T>(value: T) {
if (value) {
if (typeof value === "string") {
value = this.parseTemplatedString(value);
}
// recursively convert array and json-like objects
if (Array.isArray(value)) {
value = value.map((v) => this.parse(v)) as any;
}
if (isObjectLiteral(value)) {
for (const [key, nestedValue] of Object.entries(value)) {
value[key] = this.parse(nestedValue);
}
if (typeof value === "string") {
return this.parseTemplatedString(value);
}
// recursively convert array and json-like objects
if (Array.isArray(value)) {
return value.map((v) => this.parse(v)) as any;
}
if (isObjectLiteral(value)) {
// create a new object to avoid changes to input
const parsed = {};
for (const [key, nestedValue] of Object.entries(value)) {
parsed[key] = this.parse(nestedValue);
}
return parsed;
}
return value;
}
Expand All @@ -96,12 +89,12 @@ export class TemplatedData {
* detected within data value
**/
public listContextVariables(value: any, prefixes: string[] = []) {
let contextVariables: ITemplatedDataContextList = {};
let contextVariables: ITemplatedDataContext = {};

// Recursively extract any nested context strings
function extractContext(contextValue: any) {
if (contextValue) {
if ({}.constructor === contextValue.constructor) {
if (isObjectLiteral(contextValue)) {
extractContext(Object.values(contextValue));
}
if (Array.isArray(contextValue)) {
Expand All @@ -126,17 +119,18 @@ export class TemplatedData {
}

// Populate any variables identified from processed strings to context variable list
// Include recursive handling when detected nested, e.g. @[email protected]_lookup
// Include handling when detected nested, e.g. @[email protected]_lookup
function populateContextVariables(entries: ITemplatedStringVariable[]) {
for (const entry of entries) {
let [prefix, name] = entry.value.split(".");
prefix = prefix.replace("@", "");
contextVariables[prefix] ??= {};
// recursive variables - keep wildcard reference and process inner
if (entry.variables) {
contextVariables[prefix].__recursive = true;
contextVariables[prefix]["*"] = "";
populateContextVariables(Object.values(entry.variables));
} else {
contextVariables[prefix][name] = true;
contextVariables[prefix][name] = "";
}
}
}
Expand All @@ -147,7 +141,7 @@ export class TemplatedData {

/**
* Take a string and replace instances of context variables, such as `"hello {@row.name}"`
* Will convert non-delimited strings to delimted, extract list of variables and parse
* Will convert non-delimited strings to delimited, extract list of variables and parse
*/
private parseTemplatedString(value: string) {
const delimited = addStringDelimiters(value, this.contextPrefixes);
Expand Down
3 changes: 1 addition & 2 deletions packages/shared/src/utils/object-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,7 @@ export function isEqual(a: any, b: any) {
if (!isEqual(Object.keys(aSorted), Object.keys(bSorted))) return false;
return isEqual(Object.values(aSorted), Object.values(bSorted));
}
// could not compare (e.g. symbols, date objects, functions, buffers etc)
console.warn(`[isEqual] could not compare`, a, b);
// NOTE - does not compare symbols, date objects, functions, buffers etc.
return false;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -217,4 +217,4 @@ ion-button[data-variant~="card"] {
@media (max-width: 320px) {
max-width: 10rem;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import type { FlowTypes } from "packages/data-models";
import { DataItemsActionService } from "./data-items.actions";
import { generateItemMeta } from "./data-items.utils";

/***********************************************************************************************
* Mock Data
**********************************************************************************************/

const MOCK_ITEMS_LIST: FlowTypes.Data_listRow[] = [
{ id: "id_1", text: "item 1", number: 1, boolean: true },
{ id: "id_2", text: "item 2", number: 2, boolean: false },
];

const MOCK_TEMPLATE_ROW: FlowTypes.TemplateRow = {
_nested_name: "",
name: "",
type: "button",
value: "@item.text",
};

/**
* Mock structure for `begin_data_items .... end_data_items` syntax
* The list provided in `value` will be used to source data_list items, and the `rows`
* nested will be templated from the items
*/
const MOCK_DATA_ITEMS_ROW: FlowTypes.TemplateRow = {
_nested_name: "",
name: "",
type: "data_items",
value: "@data.mock_item_list",
rows: [MOCK_TEMPLATE_ROW],
};

/**
* Call standalone tests via:
* yarn ng test --include src/app/shared/components/template/components/data-items/data-items.utils.spec.ts
*/
describe("DataItems Utils", () => {
service: DataItemsActionService;

fit("convertItemActionToSetDataAction", () => {

Check failure on line 41 in src/app/shared/components/template/components/data-items/data-items.actions.spec.ts

View workflow job for this annotation

GitHub Actions / test / build

Unexpected fit
const itemListRows = generateItemMeta(MOCK_ITEMS_LIST);
// const res = convertItemActionToSetDataAction({
// action: {
// action_id: "set_item",
// args: [],
// trigger: "click",
// // advanced example
// // target the next item and update relative text to that item
// params: { _index: "@item._index+1", text: "{@item.text} updated" },
// },
// dataListName: "mock_list",
// itemContext: itemListRows[0],
// itemListRows,
// });
// console.log("res", res);
});
});
Loading
Loading