Skip to content

Commit

Permalink
Merge pull request #114 from getodk/fixes/83-reactive-SelectItem-labels
Browse files Browse the repository at this point in the history
Fix: client reactivity of translated select item labels
  • Loading branch information
eyelidlessness authored May 15, 2024
2 parents fc6b142 + 93217c0 commit 24277c2
Show file tree
Hide file tree
Showing 3 changed files with 343 additions and 101 deletions.
74 changes: 8 additions & 66 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,57 +23,6 @@ env:
TZ: 'America/Phoenix'

jobs:
changes:
name: 'Determine package changes'
runs-on: 'ubuntu-latest'

outputs:
root: ${{ steps.changes.outputs.root }}
odk-common: ${{ steps.changes.outputs.odk-common }}
tree-sitter-xpath: ${{ steps.changes.outputs.tree-sitter-xpath }}
xforms-engine: ${{ steps.changes.outputs.xforms-engine }}
xpath: ${{ steps.changes.outputs.xpath }}
scenario: ${{ steps.changes.outputs.scenario }}
ui-solid: ${{ steps.changes.outputs.ui-solid }}
ui-vue: ${{ steps.changes.outputs.ui-vue }}

steps:
- uses: 'actions/checkout@v3'
- uses: dorny/paths-filter@v2
id: changes
with:
filters: |
root:
- '*'
- '.github/workflows/*'
odk-common:
- 'packages/common/**'
tree-sitter-xpath:
- 'packages/tree-sitter-xpath/grammar.ts'
- 'packages/tree-sitter-xpath/scripts/**'
- 'packages/tree-sitter-xpath/test/**'
xforms-engine:
- 'packages/xforms-engine/**'
scenario:
- 'packages/scenario/**'
xpath:
- 'packages/xpath/**'
ui-solid:
- 'packages/ui-solid/**'
ui-vue:
- 'packages/ui-vue/**'
# So the `paths-filter` action doesn't attempt to use the GitHub API
# when run on pull requests
token: ''

install-and-build:
name: 'Install dependencies and build packages'
runs-on: 'ubuntu-latest'
Expand Down Expand Up @@ -128,7 +77,7 @@ jobs:

lint:
name: 'Lint (global)'
needs: ['install-and-build', 'changes']
needs: ['install-and-build']
runs-on: 'ubuntu-latest'

strategy:
Expand Down Expand Up @@ -171,8 +120,7 @@ jobs:

odk-common:
name: '@odk-web-forms/common'
needs: ['install-and-build', 'changes']
if: needs.changes.outputs.root == 'true' || needs.changes.outputs.odk-common == 'true'
needs: ['install-and-build']
runs-on: 'ubuntu-latest'

strategy:
Expand Down Expand Up @@ -236,8 +184,7 @@ jobs:

xforms-engine:
name: '@odk-web-forms/xforms-engine'
needs: ['install-and-build', 'changes']
if: needs.changes.outputs.root == 'true' || needs.changes.outputs.xforms-engine == 'true'
needs: ['install-and-build']
runs-on: 'ubuntu-latest'

strategy:
Expand Down Expand Up @@ -301,8 +248,7 @@ jobs:

scenario:
name: 'scenario'
needs: ['install-and-build', 'changes']
if: needs.changes.outputs.root == 'true' || needs.changes.outputs.scenario == 'true'
needs: ['install-and-build']
runs-on: 'ubuntu-latest'

strategy:
Expand Down Expand Up @@ -366,8 +312,7 @@ jobs:

xpath:
name: '@odk-web-forms/xpath'
needs: ['install-and-build', 'changes']
if: needs.changes.outputs.root == 'true' || needs.changes.outputs.tree-sitter-xpath == 'true' || needs.changes.outputs.xpath == 'true'
needs: ['install-and-build']
runs-on: 'ubuntu-latest'

strategy:
Expand Down Expand Up @@ -437,8 +382,7 @@ jobs:

tree-sitter-xpath:
name: '@odk-web-forms/tree-sitter-xpath'
needs: ['install-and-build', 'changes']
if: needs.changes.outputs.root == 'true' || needs.changes.outputs.tree-sitter-xpath == 'true'
needs: ['install-and-build']
runs-on: 'ubuntu-latest'

strategy:
Expand Down Expand Up @@ -481,8 +425,7 @@ jobs:

ui-solid:
name: 'ui-solid'
needs: ['install-and-build', 'changes']
if: needs.changes.outputs.root == 'true' || needs.changes.outputs.ui-solid == 'true'
needs: ['install-and-build']
runs-on: 'ubuntu-latest'

strategy:
Expand Down Expand Up @@ -546,8 +489,7 @@ jobs:

ui-vue:
name: 'ui-vue'
needs: ['install-and-build', 'changes']
if: needs.changes.outputs.root == 'true' || needs.changes.outputs.ui-vue == 'true'
needs: ['install-and-build']
runs-on: 'ubuntu-latest'

strategy:
Expand Down
91 changes: 56 additions & 35 deletions packages/xforms-engine/src/lib/reactivity/createSelectItems.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { UpsertableMap } from '@odk-web-forms/common/lib/collections/UpsertableMap.ts';
import type { XFormsXPathEvaluator } from '@odk-web-forms/xpath';
import type { Accessor } from 'solid-js';
import { createMemo } from 'solid-js';
Expand Down Expand Up @@ -26,21 +27,23 @@ const createSelectItemLabel = (
});
};

const buildStaticSelectItems = (
const createTranslatedStaticSelectItems = (
selectField: SelectField,
items: readonly ItemDefinition[]
): readonly SelectItem[] => {
): Accessor<readonly SelectItem[]> => {
return selectField.scope.runTask(() => {
return items.map((item) => {
const labeledItems = items.map((item) => {
const { value } = item;
const label = createSelectItemLabel(selectField, item);

return {
return () => ({
value,
get label() {
return label();
},
};
label: label(),
});
});

return createMemo(() => {
return labeledItems.map((item) => item());
});
});
};
Expand Down Expand Up @@ -89,28 +92,50 @@ const createSelectItemsetItemLabel = (
return createTextRange(context, 'label', label);
};

// TODO: this is begging for caching.
interface ItemsetItem {
label(): TextRange<'label'>;
value(): string;
}

const createItemsetItems = (
selectField: SelectField,
itemset: ItemsetDefinition
): Accessor<readonly ItemsetItem[]> => {
return selectField.scope.runTask(() => {
const itemNodes = createComputedExpression(selectField, itemset.nodes);
const itemsCache = new UpsertableMap<Node, ItemsetItem>();

return createMemo(() => {
return itemNodes().map((itemNode) => {
return itemsCache.upsert(itemNode, () => {
const context = new ItemsetItemEvaluationContext(selectField, itemNode);
const value = createComputedExpression(context, itemset.value);
const label = createSelectItemsetItemLabel(context, itemset, value);

return {
label,
value,
};
});
});
});
});
};

const createItemset = (
selectField: SelectField,
itemset: ItemsetDefinition
): Accessor<readonly SelectItem[]> => {
const { nodes: itemNodesExpression } = itemset;
const itemNodes = createComputedExpression(selectField, itemNodesExpression);

return createMemo(() => {
return itemNodes().map((itemNode) => {
const context = new ItemsetItemEvaluationContext(selectField, itemNode);
const value = createComputedExpression(context, itemset.value);
const label = createSelectItemsetItemLabel(context, itemset, value);

return {
get label() {
return label();
},
get value() {
return value();
},
};
return selectField.scope.runTask(() => {
const itemsetItems = createItemsetItems(selectField, itemset);

return createMemo(() => {
return itemsetItems().map((item) => {
return {
label: item.label(),
value: item.value(),
};
});
});
});
};
Expand All @@ -128,15 +153,11 @@ const createItemset = (
* referencing a form's `itext` translations, etc).
*/
export const createSelectItems = (selectField: SelectField): Accessor<readonly SelectItem[]> => {
return selectField.scope.runTask(() => {
const { items, itemset } = selectField.definition.bodyElement;
const { items, itemset } = selectField.definition.bodyElement;

if (itemset == null) {
const staticItems = buildStaticSelectItems(selectField, items);

return () => staticItems;
}
if (itemset == null) {
return createTranslatedStaticSelectItems(selectField, items);
}

return createItemset(selectField, itemset);
});
return createItemset(selectField, itemset);
};
Loading

0 comments on commit 24277c2

Please sign in to comment.