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

feat(cat-voices): parse missing document properties, add validation #1503

Merged
merged 56 commits into from
Jan 20, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
2ea3408
feat: parse multi select definition as a list of strings
dtscalac Jan 9, 2025
ad74b4b
chore: improve type safety for segments/section parsing
dtscalac Jan 9, 2025
827e8fb
Merge branch 'main' into feat/parse-missing-document-properties
dtscalac Jan 10, 2025
1d58c51
fix: correct definitions for segments/sections
dtscalac Jan 10, 2025
d372f02
docs: todo
dtscalac Jan 10, 2025
e018ffa
feat: update document change to support list changes
dtscalac Jan 10, 2025
8d96f94
feat: update document builder to work with a list of properties and a…
dtscalac Jan 10, 2025
2c8323b
chore: rename DocumentProperty to DocumentPropertyValue
dtscalac Jan 10, 2025
b205f1d
docs: todo
dtscalac Jan 10, 2025
ee6bd3b
Merge branch 'main' into feat/parse-missing-document-properties
dtscalac Jan 10, 2025
9e4ae49
chore: rename document schema, parse object properties and array item…
dtscalac Jan 10, 2025
0068fcb
chore: revert json schema
dtscalac Jan 10, 2025
14bc472
Merge branch 'main' into feat/parse-missing-document-properties
dtscalac Jan 13, 2025
824f75f
Merge branch 'main' into feat/parse-missing-document-properties
dtscalac Jan 13, 2025
8e09089
fix: parsing document schema property
dtscalac Jan 13, 2025
9754e84
style: docs
dtscalac Jan 13, 2025
3e0dd69
chore: extract common enums
dtscalac Jan 14, 2025
465df5e
feat: wip
dtscalac Jan 15, 2025
36318d0
Merge branch 'main' into feat/parse-missing-document-properties
dtscalac Jan 15, 2025
0346abd
fix: merge conflicts & compilation issues
dtscalac Jan 15, 2025
faee144
fix: conflicts
dtscalac Jan 15, 2025
834f3c3
fix: missing property
dtscalac Jan 15, 2025
680c849
fix: merge items correctly
dtscalac Jan 15, 2025
791b7b4
Merge branch 'main' into feat/parse-missing-document-properties
dtscalac Jan 16, 2025
10a62cb
chore: tests & document property parsing
dtscalac Jan 16, 2025
39c73a9
chore: split schemas
dtscalac Jan 16, 2025
047944b
Merge branch 'main' into feat/parse-missing-document-properties
dtscalac Jan 16, 2025
6b0ad69
chore: restructure code
dtscalac Jan 16, 2025
4e13f51
Merge branch 'main' into feat/parse-missing-document-properties
dtscalac Jan 16, 2025
dfa8011
chore: cleanup
dtscalac Jan 16, 2025
2feab11
chore: drop unnecessary tests
dtscalac Jan 16, 2025
68b464b
chore: reformat files
dtscalac Jan 16, 2025
d3e2940
chore: DocumentPropertiesDto tests
dtscalac Jan 16, 2025
63979b8
chore: DocumentSchemaDto tests
dtscalac Jan 16, 2025
c918478
chore: more tests
dtscalac Jan 16, 2025
5802f8d
chore: DocumentChange tests
dtscalac Jan 16, 2025
5ba655c
Merge branch 'main' into feat/parse-missing-document-properties
dtscalac Jan 17, 2025
fae849f
style: spelling
dtscalac Jan 17, 2025
9b8992d
Merge branch 'main' into feat/parse-missing-document-properties
dtscalac Jan 17, 2025
f733a67
chore: fix typo
dtscalac Jan 17, 2025
2a56ff4
chore: cleanup todos
dtscalac Jan 17, 2025
2592e18
fix: tests
dtscalac Jan 17, 2025
6a9b0de
chore: todo
dtscalac Jan 17, 2025
0cbfc3c
chore: extract unimplemented widget
dtscalac Jan 17, 2025
669e520
fix: property casting
dtscalac Jan 17, 2025
ca01740
chore: docs + reformat
dtscalac Jan 17, 2025
7ff24a3
chore: document node id tests
dtscalac Jan 17, 2025
f8085d0
docs: spelling
dtscalac Jan 17, 2025
031250c
chore: cleanup & tests
dtscalac Jan 17, 2025
cbdf575
Merge branch 'main' into feat/parse-missing-document-properties
dtscalac Jan 17, 2025
d40f7de
Merge branch 'main' into feat/parse-missing-document-properties
dtscalac Jan 17, 2025
67d8565
Merge branch 'main' into feat/parse-missing-document-properties
dtscalac Jan 20, 2025
dfee949
chore: make description MarkdownData, optimize properties that are pa…
dtscalac Jan 20, 2025
1c8e8fb
chore: document builder doesn't need to implement DocumentNode
dtscalac Jan 20, 2025
8495845
chore: extract code for finding a target node for document change
dtscalac Jan 20, 2025
8e4dbe1
Merge branch 'main' into feat/parse-missing-document-properties
dtscalac Jan 20, 2025
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

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import 'package:catalyst_voices/common/ext/string_ext.dart';
import 'package:catalyst_voices_models/catalyst_voices_models.dart';

extension DocumentPropertySchemaExt on DocumentPropertySchema {
// TODO(dtscalac): convert to markdown
String get formattedDescription {
final string = description?.data;
return (string ?? '').starred(isEnabled: isRequired);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,15 @@ import 'package:catalyst_voices_models/catalyst_voices_models.dart';
import 'package:flutter/material.dart';

class AgreementConfirmationWidget extends StatefulWidget {
final bool? value;
final AgreementConfirmationDefinition definition;
final DocumentNodeId nodeId;
final String description;
final String title;
final DocumentValueProperty<bool> property;
final DocumentAgreementConfirmationSchema schema;
final bool isEditMode;
final ValueChanged<DocumentChange> onChanged;

const AgreementConfirmationWidget({
super.key,
required this.value,
required this.definition,
required this.nodeId,
required this.description,
required this.title,
required this.property,
required this.schema,
required this.isEditMode,
required this.onChanged,
});
Expand All @@ -34,11 +28,12 @@ class _DocumentCheckboxBuilderWidgetState
late bool _initialValue;
late bool _currentEditValue;

DocumentNodeId get _nodeId => widget.nodeId;
DocumentNodeId get _nodeId => widget.schema.nodeId;

MarkdownData get _description => MarkdownData(widget.description);
MarkdownData get _description =>
widget.schema.description ?? MarkdownData.empty;

bool get _defaultValue => widget.definition.defaultValue;
bool get _defaultValue => widget.schema.defaultValue ?? false;

@override
void initState() {
Expand All @@ -55,7 +50,7 @@ class _DocumentCheckboxBuilderWidgetState
_currentEditValue = _initialValue;
}

if (oldWidget.value != widget.value) {
if (oldWidget.property.value != widget.property.value) {
_setInitialValues();
}
}
Expand Down Expand Up @@ -96,15 +91,15 @@ class _DocumentCheckboxBuilderWidgetState
});

widget.onChanged(
DocumentChange(
DocumentValueChange(
nodeId: _nodeId,
value: _currentEditValue,
),
);
}

void _setInitialValues() {
_initialValue = widget.value ?? _defaultValue;
_initialValue = widget.property.value ?? _defaultValue;
_currentEditValue = _initialValue;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,18 @@ import 'package:catalyst_voices_view_models/catalyst_voices_view_models.dart';
import 'package:flutter/material.dart';

class DocumentTokenValueWidget extends StatefulWidget {
final DocumentProperty<int> property;
final DocumentValueProperty<int> property;
final DocumentIntegerSchema schema;
final Currency currency;
final bool isEditMode;
final ValueChanged<DocumentChange> onChanged;

const DocumentTokenValueWidget({
super.key,
required this.property,
required this.schema,
required this.currency,
this.isEditMode = false,
required this.isEditMode,
required this.onChanged,
});

Expand Down Expand Up @@ -61,8 +63,8 @@ class _DocumentTokenValueWidgetState extends State<DocumentTokenValueWidget> {

@override
Widget build(BuildContext context) {
final schema = widget.property.schema;
final label = schema.title ?? '';
final schema = widget.schema;
final label = schema.title;

return TokenField(
controller: _controller,
Expand Down Expand Up @@ -94,17 +96,16 @@ class _DocumentTokenValueWidgetState extends State<DocumentTokenValueWidget> {
}

void _notifyChangeListener(int? value) {
final change = DocumentChange(
nodeId: widget.property.schema.nodeId,
final change = DocumentValueChange(
nodeId: widget.schema.nodeId,
value: value,
);

widget.onChanged(change);
}

VoicesTextFieldValidationResult _validate(int? value, String text) {
final schema = widget.property.schema;
final result = schema.validatePropertyValue(value);
final result = widget.schema.validate(value);
if (result.isValid) {
return const VoicesTextFieldValidationResult.none();
} else {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
import 'dart:async';

import 'package:catalyst_voices/common/codecs/markdown_codec.dart';
import 'package:catalyst_voices/common/ext/document_property_ext.dart';
import 'package:catalyst_voices/common/ext/document_property_schema_ext.dart';
import 'package:catalyst_voices/widgets/rich_text/voices_rich_text.dart';
import 'package:catalyst_voices_models/catalyst_voices_models.dart';
import 'package:flutter/material.dart';
import 'package:flutter_quill/flutter_quill.dart' as quill;

class MultilineTextEntryMarkdownWidget extends StatefulWidget {
final DocumentProperty<String> property;
final DocumentValueProperty<String> property;
final DocumentMultiLineTextEntryMarkdownSchema schema;
final ValueChanged<DocumentChange> onChanged;
final bool isEditMode;
final bool isRequired;

const MultilineTextEntryMarkdownWidget({
super.key,
required this.property,
required this.schema,
required this.onChanged,
required this.isEditMode,
required this.isRequired,
});

@override
Expand All @@ -36,15 +36,14 @@ class _MultilineTextEntryMarkdownWidgetState
StreamSubscription<quill.DocChange>? _documentChangeSub;
quill.Document? _preEditDocument;

String get _description => widget.property.formattedDescription;
int? get _maxLength => widget.property.schema.strLengthRange?.max;
String? get _value => widget.property.value;
String get _description => widget.schema.formattedDescription;
int? get _maxLength => widget.schema.strLengthRange?.max;

@override
void initState() {
super.initState();

_controller = _buildController(value: _value);
_controller = _buildController(value: widget.property.value);
_controller.addListener(_onControllerChanged);

_focus = VoicesRichTextFocusNode();
Expand All @@ -63,7 +62,7 @@ class _MultilineTextEntryMarkdownWidgetState

if (widget.property.value != oldWidget.property.value) {
_controller.dispose();
_controller = _buildController(value: _value);
_controller = _buildController(value: widget.property.value);
_controller.addListener(_onControllerChanged);
}
}
Expand Down Expand Up @@ -134,8 +133,8 @@ class _MultilineTextEntryMarkdownWidgetState
final delta = _controller.document.toDelta();
final markdownData = markdown.decoder.convert(delta);
widget.onChanged(
DocumentChange(
nodeId: widget.property.schema.nodeId,
DocumentValueChange(
nodeId: widget.schema.nodeId,
value: markdownData.data,
),
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
import 'package:catalyst_voices/common/ext/document_property_ext.dart';
import 'package:catalyst_voices/common/ext/document_property_schema_ext.dart';
import 'package:catalyst_voices/widgets/widgets.dart';
import 'package:catalyst_voices_models/catalyst_voices_models.dart';
import 'package:catalyst_voices_view_models/catalyst_voices_view_models.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

class SimpleTextEntryWidget extends StatefulWidget {
final DocumentProperty<String> property;
final DocumentValueProperty<String> property;
final DocumentStringSchema schema;
final bool isEditMode;
final ValueChanged<DocumentChange> onChanged;

const SimpleTextEntryWidget({
super.key,
required this.property,
required this.schema,
required this.isEditMode,
required this.onChanged,
});
Expand All @@ -25,10 +27,9 @@ class _SimpleTextEntryWidgetState extends State<SimpleTextEntryWidget> {
late final TextEditingController _controller;
late final FocusNode _focusNode;

String get _description => widget.property.formattedDescription;
int? get _maxLength => widget.property.schema.strLengthRange?.max;
bool get _resizable =>
widget.property.schema.definition is MultiLineTextEntryDefinition;
String get _description => widget.schema.formattedDescription;
int? get _maxLength => widget.schema.strLengthRange?.max;
bool get _resizable => widget.schema is DocumentMultiLineTextEntrySchema;

@override
void initState() {
Expand Down Expand Up @@ -81,7 +82,7 @@ class _SimpleTextEntryWidgetState extends State<SimpleTextEntryWidget> {
validator: _validate,
enabled: widget.isEditMode,
// TODO(LynxLynxx): check if this is right after schema is finalized
hintText: widget.property.schema.defaultValue,
hintText: widget.schema.defaultValue,
resizable: _resizable,
maxLength: _maxLength,
),
Expand All @@ -108,8 +109,8 @@ class _SimpleTextEntryWidgetState extends State<SimpleTextEntryWidget> {
}

void _notifyChangeListener(String? value) {
final change = DocumentChange(
nodeId: widget.property.schema.nodeId,
final change = DocumentValueChange(
nodeId: widget.schema.nodeId,
value: value,
);

Expand All @@ -120,8 +121,8 @@ class _SimpleTextEntryWidgetState extends State<SimpleTextEntryWidget> {
if (!widget.isEditMode) {
return const VoicesTextFieldValidationResult.none();
}
final schema = widget.property.schema;
final result = schema.validatePropertyValue(value);
final schema = widget.schema;
final result = schema.validate(value);
if (result.isValid) {
return const VoicesTextFieldValidationResult.none();
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,16 @@ import 'package:flutter/material.dart';
class SingleDropdownSelectionWidget extends StatefulWidget {
final String value;
final List<String> items;
final DropDownSingleSelectDefinition definition;
final DocumentNodeId nodeId;
final String title;
final DocumentDropDownSingleSelectSchema schema;
final bool isEditMode;
final bool isRequired;
final ValueChanged<DocumentChange> onChanged;

const SingleDropdownSelectionWidget({
super.key,
required this.value,
required this.items,
required this.definition,
required this.nodeId,
required this.title,
required this.schema,
required this.isEditMode,
required this.isRequired,
required this.onChanged,
});

Expand Down Expand Up @@ -76,7 +70,7 @@ class _SingleDropdownSelectionWidgetState
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(
widget.title,
widget.schema.title,
style: Theme.of(context).textTheme.titleSmall,
),
const SizedBox(height: 8),
Expand All @@ -85,7 +79,11 @@ class _SingleDropdownSelectionWidgetState
items: _dropdownMenuEntries,
enabled: widget.isEditMode,
onSelected: (val) {
widget.onChanged(DocumentChange(nodeId: widget.nodeId, value: val));
final change = DocumentValueChange(
nodeId: widget.schema.nodeId,
value: val,
);
widget.onChanged(change);
},
initialValue: widget.value,
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,8 @@ class _SingleGroupedTagSelectorWidgetState
setState(() {
_selection = value;

final change = DocumentChange(nodeId: widget.id, value: value);
// TODO(dtscalac): this should update children properties, not the parent
final change = DocumentValueChange(nodeId: widget.id, value: value);
widget.onChanged(change);
});
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
import 'package:catalyst_voices/common/ext/document_property_ext.dart';
import 'package:catalyst_voices/common/ext/document_property_schema_ext.dart';
import 'package:catalyst_voices/widgets/text_field/voices_https_text_field.dart';
import 'package:catalyst_voices/widgets/widgets.dart';
import 'package:catalyst_voices_models/catalyst_voices_models.dart';
import 'package:catalyst_voices_view_models/catalyst_voices_view_models.dart';
import 'package:flutter/material.dart';

class SingleLineHttpsUrlWidget extends StatefulWidget {
final DocumentProperty<String> property;
final DocumentValueProperty<String> property;
final DocumentStringSchema schema;
final bool isEditMode;
final ValueChanged<DocumentChange> onChanged;

const SingleLineHttpsUrlWidget({
super.key,
required this.property,
required this.schema,
required this.isEditMode,
required this.onChanged,
});
Expand All @@ -26,7 +28,7 @@ class _SingleLineHttpsUrlWidgetState extends State<SingleLineHttpsUrlWidget> {
late final TextEditingController _textEditingController;
late final FocusNode _focusNode;

String get _description => widget.property.formattedDescription;
String get _description => widget.schema.formattedDescription;

@override
void initState() {
Expand Down Expand Up @@ -89,8 +91,8 @@ class _SingleLineHttpsUrlWidgetState extends State<SingleLineHttpsUrlWidget> {
}

void _notifyChangeListener(String? value) {
final change = DocumentChange(
nodeId: widget.property.schema.nodeId,
final change = DocumentValueChange(
nodeId: widget.schema.nodeId,
value: value,
);

Expand All @@ -101,8 +103,8 @@ class _SingleLineHttpsUrlWidgetState extends State<SingleLineHttpsUrlWidget> {
if (value == null || value.isEmpty) {
return const VoicesTextFieldValidationResult.none();
}
final schema = widget.property.schema;
final result = schema.validatePropertyValue(value);
final schema = widget.schema;
final result = schema.validate(value);
if (result.isValid) {
return const VoicesTextFieldValidationResult.success();
} else {
Expand Down
Loading
Loading