Skip to content

Commit 17397be

Browse files
rayliverifiedclaude
andcommitted
A Choice variable type with named options
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
1 parent 55ca350 commit 17397be

5 files changed

Lines changed: 74 additions & 2 deletions

File tree

‎lib/src/api/models/action/set_cloud_storage_action.g.dart‎

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎lib/src/api/models/action/set_storage_action.g.dart‎

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎lib/src/api/models/variables_model.dart‎

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,12 @@ enum VariableType {
2929
map,
3030

3131
/// Image type. Represents an image URL.
32-
image;
32+
image,
33+
34+
/// One of a set of named options ([VariableData.choiceOptions]), stored as
35+
/// the option's value; e.g. the state a variance node shows, by its id, so
36+
/// renaming the state keeps it.
37+
choice;
3338

3439
/// Returns a string representation of the variable type.
3540
String get label => switch (this) {
@@ -41,6 +46,7 @@ enum VariableType {
4146
VariableType.list => 'List',
4247
VariableType.map => 'Map',
4348
VariableType.image => 'Image',
49+
VariableType.choice => 'Choice',
4450
};
4551

4652
factory VariableType.fromObjectType(Object obj) {
@@ -61,6 +67,9 @@ enum VariableType {
6167
};
6268
}
6369

70+
/// Whether the variable type is [VariableType.choice].
71+
bool get isChoice => this == VariableType.choice;
72+
6473
/// Whether the variable type is [VariableType.map].
6574
bool get isMap => this == VariableType.map;
6675

@@ -106,6 +115,30 @@ class VariableData
106115
/// Whether the variable has a value or not.
107116
bool get hasValue => value.isNotEmpty;
108117

118+
/// The `extra` key of a [VariableType.choice] variable's options.
119+
static const String optionsKey = 'options';
120+
121+
/// The options of a [VariableType.choice] variable: each a value and the
122+
/// label shown for it. Options stored as plain text are their own label.
123+
List<({String value, String label})> get choiceOptions => [
124+
for (final Object? option in (extra[optionsKey] as List?) ?? const [])
125+
switch (option) {
126+
Map() when option['value'] != null => (
127+
value: '${option['value']}',
128+
label: '${option['label'] ?? option['value']}',
129+
),
130+
_ => (value: '$option', label: '$option'),
131+
},
132+
];
133+
134+
/// The label of the option this variable's [value] picks, or the value.
135+
String get choiceLabel =>
136+
choiceOptions
137+
.where((option) => option.value == value)
138+
.map((option) => option.label)
139+
.firstOrNull ??
140+
value;
141+
109142
/// Type of the variable. This is used to determine how to parse the value.
110143
@JsonKey(unknownEnumValue: VariableType.text)
111144
final VariableType type;
@@ -175,7 +208,7 @@ class VariableData
175208
/// A text variable returns its value as is, so one holding an empty string
176209
/// stays an empty string and compares equal to `''` in conditions.
177210
Object? getValue() => switch (type) {
178-
VariableType.text => value,
211+
VariableType.text || VariableType.choice => value,
179212
VariableType.image => value.isEmpty ? null : value,
180213
VariableType.integer => num.tryParse(value).toInt(),
181214
VariableType.decimal => num.tryParse(value).toDouble(),
@@ -200,6 +233,7 @@ String? sanitizeValueForVariableType(Object? value, VariableType type) {
200233
switch (type) {
201234
case VariableType.text:
202235
case VariableType.image:
236+
case VariableType.choice:
203237
return value.toString();
204238
case VariableType.integer:
205239
return num.tryParse(value.toString()).toInt()?.toString();

‎lib/src/api/models/variables_model.g.dart‎

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎test/choice_variable_test.dart‎

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import 'package:codelessly_api/codelessly_api.dart';
2+
import 'package:test/test.dart';
3+
4+
void main() {
5+
test('a choice variable holds an option value and labels it', () {
6+
final VariableData state = VariableData(
7+
id: 's',
8+
name: 'cardState',
9+
type: VariableType.choice,
10+
value: 'v2',
11+
extra: {
12+
VariableData.optionsKey: [
13+
{'value': 'default', 'label': 'Default'},
14+
{'value': 'v2', 'label': 'Selected'},
15+
'Plain',
16+
],
17+
},
18+
);
19+
expect(state.getValue(), 'v2');
20+
expect(state.choiceLabel, 'Selected');
21+
expect(state.choiceOptions.last, (value: 'Plain', label: 'Plain'));
22+
expect(VariableData.fromJson(state.toJson()), state);
23+
expect(VariableType.choice.label, 'Choice');
24+
});
25+
26+
test('an SDK that predates choice reads it as text', () {
27+
final VariableData read = VariableData.fromJson({
28+
'id': 'x',
29+
'name': 'x',
30+
'type': 'somethingNew',
31+
'value': 'a',
32+
});
33+
expect(read.type, VariableType.text);
34+
});
35+
}

0 commit comments

Comments
 (0)