From 093487ca56b15e8c0ea4d66c0c9f923d39b371bd Mon Sep 17 00:00:00 2001 From: Ryszard Schossler Date: Mon, 9 Dec 2024 14:02:23 +0100 Subject: [PATCH 01/18] draft for setup segment --- .../base_proposal_template.dart | 32 + .../definitions_proposal_template.dart | 93 ++ .../proposal_template/proposal_template.dart | 47 + .../sections/proposer_section.dart | 39 + .../sections/title_section.dart | 35 + .../segments/proposal_template_segments.dart | 46 + .../proposal_template_setup_segment.dart | 44 + .../topics/applicant_topic.dart | 26 + .../topics/coproposers_topic.dart | 26 + .../proposal_template/topics/title_topic.dart | 26 + .../proposal_template/topics/type_topic.dart | 26 + .../catalyst_voices_models/pubspec.yaml | 6 +- .../proposal/helpers/generic_proposal.json | 236 +++++ .../helpers/generic_proposal_template.json | 916 ++++++++++++++++++ .../test/proposal/helpers/read_json.dart | 10 + .../test/proposal/proposal_test.dart | 19 + 16 files changed, 1626 insertions(+), 1 deletion(-) create mode 100644 catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/base_proposal_template.dart create mode 100644 catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/definitions/definitions_proposal_template.dart create mode 100644 catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/proposal_template.dart create mode 100644 catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/sections/proposer_section.dart create mode 100644 catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/sections/title_section.dart create mode 100644 catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/segments/proposal_template_segments.dart create mode 100644 catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/segments/proposal_template_setup_segment.dart create mode 100644 catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/topics/applicant_topic.dart create mode 100644 catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/topics/coproposers_topic.dart create mode 100644 catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/topics/title_topic.dart create mode 100644 catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/topics/type_topic.dart create mode 100644 catalyst_voices/packages/internal/catalyst_voices_models/test/proposal/helpers/generic_proposal.json create mode 100644 catalyst_voices/packages/internal/catalyst_voices_models/test/proposal/helpers/generic_proposal_template.json create mode 100644 catalyst_voices/packages/internal/catalyst_voices_models/test/proposal/helpers/read_json.dart create mode 100644 catalyst_voices/packages/internal/catalyst_voices_models/test/proposal/proposal_test.dart diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/base_proposal_template.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/base_proposal_template.dart new file mode 100644 index 00000000000..4a29c3c3fec --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/base_proposal_template.dart @@ -0,0 +1,32 @@ +abstract class PropTemplateBase { + final String ref; + final String title; + final String description; + + const PropTemplateBase({ + required this.ref, + required this.title, + required this.description, + }); +} + +abstract class PropTemplateProperty extends PropTemplateBase { + final List properties; + + const PropTemplateProperty({ + required super.ref, + required super.title, + required super.description, + required this.properties, + }); +} + +abstract class PropTemplateTopic { + final String ref; + final String title; + + const PropTemplateTopic({ + required this.ref, + required this.title, + }); +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/definitions/definitions_proposal_template.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/definitions/definitions_proposal_template.dart new file mode 100644 index 00000000000..334993caf6a --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/definitions/definitions_proposal_template.dart @@ -0,0 +1,93 @@ +sealed class Definitions { + const Definitions(); + + static Definitions select(Map json) { + final ref = json[r'$ref'] as String; + final definition = ref.split('/').last; + return switch (definition) { + 'segment' => SegmentDefinition.fromJson(json), + 'section' => SectionDefiniton.fromJson(json), + 'singleLineTextEntry' => SingleLineTextEntry.fromJson(json), + 'singleLineHttpsURLEntry' => SingleLineHttpsURLEntry.fromJson(json), + 'multiLineTextEntry' => MultiLineTextEntry.fromJson(json), + _ => throw Exception('Unknown link: $definition'), + }; + } +} + +class SegmentDefinition extends Definitions { + final bool additionalProperties; + + const SegmentDefinition({ + required this.additionalProperties, + }); + + factory SegmentDefinition.fromJson(Map json) => + SegmentDefinition( + additionalProperties: json['additionalProperties'] as bool, + ); +} + +class SectionDefiniton extends Definitions { + final bool additionalProperties; + + const SectionDefiniton({ + required this.additionalProperties, + }); + + factory SectionDefiniton.fromJson(Map json) => + SectionDefiniton( + additionalProperties: json['additionalProperties'] as bool, + ); +} + +class SingleLineTextEntry extends Definitions { + final String contentMediaType; + final String pattern; + + const SingleLineTextEntry({ + required this.contentMediaType, + required this.pattern, + }); + + factory SingleLineTextEntry.fromJson(Map json) => + SingleLineTextEntry( + contentMediaType: json['contentMediaType'] as String, + pattern: json['pattern'] as String, + ); +} + +class SingleLineHttpsURLEntry extends Definitions { + final String type; + final String format; + final String pattern; + + const SingleLineHttpsURLEntry({ + required this.type, + required this.format, + required this.pattern, + }); + + factory SingleLineHttpsURLEntry.fromJson(Map json) => + SingleLineHttpsURLEntry( + type: json['type'] as String, + format: json['format'] as String, + pattern: json['pattern'] as String, + ); +} + +class MultiLineTextEntry extends Definitions { + final String contentMediaType; + final String pattern; + + const MultiLineTextEntry({ + required this.contentMediaType, + required this.pattern, + }); + + factory MultiLineTextEntry.fromJson(Map json) => + MultiLineTextEntry( + contentMediaType: json['contentMediaType'] as String, + pattern: json['pattern'] as String, + ); +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/proposal_template.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/proposal_template.dart new file mode 100644 index 00000000000..2d8e9938c26 --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/proposal_template.dart @@ -0,0 +1,47 @@ +import 'package:catalyst_voices_models/src/proposal/proposal_template/segments/proposal_template_segments.dart'; +import 'package:equatable/equatable.dart'; +import 'package:json_annotation/json_annotation.dart'; + +part 'proposal_template.g.dart'; + +@JsonSerializable() +class PropTemplate extends Equatable { + final String schema; + final String id; + final String title; + final String description; + final Object definitions; + final String type; + final bool additionalProperties; + final PropTemplateSegments properties; + @JsonKey(name: 'x-order') + final List xorder; + + const PropTemplate({ + required this.schema, + required this.id, + required this.title, + required this.description, + required this.definitions, + required this.type, + required this.additionalProperties, + required this.properties, + required this.xorder, + }); + + factory PropTemplate.fromJson(Map json) => + _$PropTemplateFromJson(json); + + @override + List get props => [ + schema, + id, + title, + description, + definitions, + type, + additionalProperties, + properties, + xorder, + ]; +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/sections/proposer_section.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/sections/proposer_section.dart new file mode 100644 index 00000000000..633570801e5 --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/sections/proposer_section.dart @@ -0,0 +1,39 @@ +import 'package:catalyst_voices_models/src/proposal/proposal_template/topics/applicant_topic.dart'; +import 'package:catalyst_voices_models/src/proposal/proposal_template/topics/coproposers_topic.dart'; +import 'package:catalyst_voices_models/src/proposal/proposal_template/topics/type_topic.dart'; +import 'package:json_annotation/json_annotation.dart'; + +part 'proposer_section.g.dart'; + +@JsonSerializable() +class ProposerSection { + @JsonKey(name: r'$ref') + final String ref; + final ProposerProperties properties; + final List required; + + const ProposerSection({ + required this.ref, + required this.properties, + required this.required, + }); + + factory ProposerSection.fromJson(Map json) => + _$ProposerSectionFromJson(json); +} + +@JsonSerializable() +class ProposerProperties { + final ApplicantTopic applicant; + final TypeTopic type; + final CoproposersTopic coproposers; + + const ProposerProperties({ + required this.applicant, + required this.type, + required this.coproposers, + }); + + factory ProposerProperties.fromJson(Map json) => + _$ProposerPropertiesFromJson(json); +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/sections/title_section.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/sections/title_section.dart new file mode 100644 index 00000000000..e4ae05a0bee --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/sections/title_section.dart @@ -0,0 +1,35 @@ +import 'package:catalyst_voices_models/src/proposal/proposal_template/topics/title_topic.dart'; +import 'package:json_annotation/json_annotation.dart'; + +part 'title_section.g.dart'; + +@JsonSerializable() +class TitleSection { + @JsonKey(name: r'$ref') + final String ref; + final String title; + final String description; + final TitleProperties properties; + + const TitleSection({ + required this.title, + required this.ref, + required this.description, + required this.properties, + }); + + factory TitleSection.fromJson(Map json) => + _$TitleSectionFromJson(json); +} + +@JsonSerializable() +class TitleProperties { + final TitleTopic title; + + const TitleProperties({ + required this.title, + }); + + factory TitleProperties.fromJson(Map json) => + _$TitlePropertiesFromJson(json); +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/segments/proposal_template_segments.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/segments/proposal_template_segments.dart new file mode 100644 index 00000000000..99cd2071dda --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/segments/proposal_template_segments.dart @@ -0,0 +1,46 @@ +import 'package:catalyst_voices_models/src/proposal/proposal_template/segments/proposal_template_setup_segment.dart'; +import 'package:equatable/equatable.dart'; +import 'package:json_annotation/json_annotation.dart'; + +part 'proposal_template_segments.g.dart'; + +@JsonSerializable() +class PropTemplateSegments extends Equatable { + @JsonKey(name: r'$schema') + final SchemaProperty schema; + final PropTemplateSetup setup; + + const PropTemplateSegments({ + required this.schema, + required this.setup, + }); + + factory PropTemplateSegments.fromJson(Map json) => + _$PropTemplateSegmentsFromJson(json); + + @override + List get props => []; +} + +@JsonSerializable() +class SchemaProperty extends Equatable { + @JsonKey(name: r'$schema') + final String schema; + @JsonKey(name: r'$id') + final String id; + final String title; + final String description; + + const SchemaProperty({ + required this.schema, + required this.id, + required this.title, + required this.description, + }); + + factory SchemaProperty.fromJson(Map json) => + _$SchemaPropertyFromJson(json); + + @override + List get props => [schema, id, title, description]; +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/segments/proposal_template_setup_segment.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/segments/proposal_template_setup_segment.dart new file mode 100644 index 00000000000..ab94ec4ff03 --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/segments/proposal_template_setup_segment.dart @@ -0,0 +1,44 @@ +import 'package:catalyst_voices_models/src/proposal/proposal_template/sections/proposer_section.dart'; +import 'package:catalyst_voices_models/src/proposal/proposal_template/sections/title_section.dart'; +import 'package:equatable/equatable.dart'; +import 'package:json_annotation/json_annotation.dart'; + +part 'proposal_template_setup_segment.g.dart'; + +@JsonSerializable() +class PropTemplateSetup extends Equatable { + @JsonKey(name: r'$ref') + final String ref; + final String title; + final String description; + final PropTemplateSetupProperties properties; + final List required; + + const PropTemplateSetup({ + required this.ref, + required this.title, + required this.description, + required this.properties, + required this.required, + }); + + factory PropTemplateSetup.fromJson(Map json) => + _$PropTemplateSetupFromJson(json); + + @override + List get props => [title, description, properties, required]; +} + +@JsonSerializable() +class PropTemplateSetupProperties { + final TitleSection title; + final ProposerSection proposer; + + const PropTemplateSetupProperties({ + required this.title, + required this.proposer, + }); + + factory PropTemplateSetupProperties.fromJson(Map json) => + _$PropTemplateSetupPropertiesFromJson(json); +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/topics/applicant_topic.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/topics/applicant_topic.dart new file mode 100644 index 00000000000..b092c4df5bd --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/topics/applicant_topic.dart @@ -0,0 +1,26 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'applicant_topic.g.dart'; + +@JsonSerializable() +class ApplicantTopic { + @JsonKey(name: r'$ref') + final String ref; + final String title; + final String description; + final String guidance; + final int minLength; + final int maxLength; + + ApplicantTopic({ + required this.ref, + required this.title, + required this.description, + required this.guidance, + required this.minLength, + required this.maxLength, + }); + + factory ApplicantTopic.fromJson(Map json) => + _$ApplicantTopicFromJson(json); +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/topics/coproposers_topic.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/topics/coproposers_topic.dart new file mode 100644 index 00000000000..53b7cd30789 --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/topics/coproposers_topic.dart @@ -0,0 +1,26 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'coproposers_topic.g.dart'; + +@JsonSerializable() +class CoproposersTopic { + @JsonKey(name: r'$ref') + final String ref; + final String title; + final String description; + final String guidance; + final int minItems; + final int maxItems; + + const CoproposersTopic({ + required this.ref, + required this.title, + required this.description, + required this.guidance, + required this.minItems, + required this.maxItems, + }); + + factory CoproposersTopic.fromJson(Map json) => + _$CoproposersTopicFromJson(json); +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/topics/title_topic.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/topics/title_topic.dart new file mode 100644 index 00000000000..488630362d0 --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/topics/title_topic.dart @@ -0,0 +1,26 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'title_topic.g.dart'; + +@JsonSerializable() +class TitleTopic { + @JsonKey(name: r'$ref') + final String ref; + final String title; + final String description; + final int minLength; + final int maxLength; + final String guidance; + + const TitleTopic({ + required this.ref, + required this.title, + required this.description, + required this.minLength, + required this.maxLength, + required this.guidance, + }); + + factory TitleTopic.fromJson(Map json) => + _$TitleTopicFromJson(json); +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/topics/type_topic.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/topics/type_topic.dart new file mode 100644 index 00000000000..ad279377972 --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/topics/type_topic.dart @@ -0,0 +1,26 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'type_topic.g.dart'; + +@JsonSerializable() +class TypeTopic { + @JsonKey(name: r'$ref') + final String ref; + final String title; + final String description; + final String guidance; + final List enumValues; + final String defaultValue; + + const TypeTopic({ + required this.ref, + required this.title, + required this.description, + required this.guidance, + required this.enumValues, + required this.defaultValue, + }); + + factory TypeTopic.fromJson(Map json) => + _$TypeTopicFromJson(json); +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/pubspec.yaml b/catalyst_voices/packages/internal/catalyst_voices_models/pubspec.yaml index e83c92fefdd..2816e42f049 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_models/pubspec.yaml +++ b/catalyst_voices/packages/internal/catalyst_voices_models/pubspec.yaml @@ -14,9 +14,13 @@ dependencies: collection: ^1.18.0 convert: ^3.1.1 equatable: ^2.0.7 + json_annotation: ^4.9.0 meta: ^1.10.0 password_strength: ^0.2.0 dev_dependencies: + build_runner: ^2.4.13 catalyst_analysis: ^2.0.0 - test: ^1.24.9 \ No newline at end of file + + json_serializable: ^6.9.0 + test: ^1.24.9 diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/test/proposal/helpers/generic_proposal.json b/catalyst_voices/packages/internal/catalyst_voices_models/test/proposal/helpers/generic_proposal.json new file mode 100644 index 00000000000..4b2d77cdbc3 --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_models/test/proposal/helpers/generic_proposal.json @@ -0,0 +1,236 @@ +{ + "$schema": "./0ce8ab38-9258-4fbc-a62e-7faa6e58318f.schema.json", + "setup": { + "title": { + "title": "Example Catalyst Proposal" + }, + "proposer": { + "applicant": "John Doe", + "type": "Individual", + "coproposers": [] + } + }, + "summary": { + "budget": { + "requestedFunds": 150000 + }, + "time": { + "duration": 6 + }, + "translation": { + "translated": false, + "original": "English", + "notes": "Original proposal in English" + }, + "problem": { + "statement": "Current challenge in the Cardano ecosystem...", + "impact": [ + "Technical Infrastructure", + "Developer Tooling", + "Adoption" + ] + }, + "solution": { + "summary": "Our solution provides a comprehensive toolkit...", + "approach": "We will implement this solution using...", + "innovationAspects": [ + "Novel testing framework", + "Automated integration tools" + ] + }, + "SupportingLinks": { + "links": [ + { + "url": "https://github.com/example/project", + "type": "GitHub Repository", + "description": "Project's main repository" + } + ], + "mainRepository": "https://github.com/example/project", + "documentation": "https://docs.example.com" + } + }, + "horizons": { + "category": { + "primaryCategory": "Development & Tools", + "subCategory": "Developer Tools" + }, + "tags": [ + "defi", + "developer-tools", + "infrastructure" + ], + "impact": { + "timeframe": "Medium-term (6-18 months)", + "scale": "Global", + "metrics": [ + { + "metric": "Developer Adoption", + "target": "500 active developers", + "measurement": "GitHub analytics" + } + ] + } + }, + "proposalDetails": { + "solution": { + "description": "Our solution provides a comprehensive toolkit...", + "uniqueValue": "First integrated testing framework for Cardano", + "targetAudience": [ + "Cardano Developers", + "DApp Teams" + ], + "implementation": "We will use an agile development approach..." + }, + "impact": { + "communityBenefit": "Significantly reduces development time and improves code quality", + "metrics": [ + { + "name": "Developer Adoption", + "description": "Number of active developers using the toolkit", + "target": "500 developers", + "measurement": "GitHub analytics and usage statistics" + } + ], + "outputs": [ + "Testing Framework", + "Documentation", + "Training Materials" + ] + }, + "capability": { + "teamExperience": "Our team has extensive experience in blockchain development...", + "feasibilityApproach": "We have already developed a proof of concept...", + "fundManagement": "Funds will be managed through a transparent process..." + } + }, + "milestones": { + "milestones": { + "declared": [ + "a", + "bb", + "cccccccccccccccccccccccc", + "dd", + "eee", + "fff" + ] + } + }, + "milestonez": { + "milestonesConfig": { + "grantAmount": 150000, + "numberOfMilestones": 4 + }, + "milestonesList": [ + { + "title": "Initial Setup and Planning", + "description": "Project setup and detailed planning phase", + "deliverables": [ + { + "name": "Project Plan", + "description": "Detailed project planning documentation", + "type": "Documentation" + } + ], + "acceptanceCriteria": [ + "Completed project plan", + "Technical specifications approved" + ], + "evidenceOfCompletion": [ + { + "type": "Documentation", + "description": "Project planning documents and specifications" + } + ], + "timeline": { + "startDate": "2024-03-01", + "endDate": "2024-04-01", + "durationInWeeks": 4 + }, + "budget": { + "amount": 37500, + "breakdown": [ + { + "category": "Development", + "amount": 30000, + "description": "Initial development work" + } + ] + } + } + ] + }, + "finalPitch": { + "team": { + "members": [ + { + "name": "John Doe", + "role": "Project Lead", + "expertise": [ + "Blockchain Development", + "Smart Contracts" + ], + "experience": "10 years in software development", + "links": [ + { + "type": "GitHub", + "url": "https://github.com/johndoe", + "description": "GitHub Profile" + } + ] + } + ] + }, + "budget": { + "totalBudget": 150000, + "categories": [ + { + "category": "Development", + "amount": 100000, + "description": "Core development team costs" + } + ] + }, + "valueProposition": { + "costBenefitAnalysis": "The project provides significant value...", + "longTermValue": "The solution will continue to benefit the ecosystem...", + "communityBenefits": [ + "Increased developer productivity", + "Better code quality" + ] + } + }, + "mandatoryAcknowledgments": { + "fundRules": { + "acknowledgment": true, + "version": "F14", + "timestamp": "2024-01-20T15:30:00Z" + }, + "termsAndConditions": { + "acknowledgment": true, + "version": "1.0.0", + "documentUrl": "https://cardano.org/terms", + "timestamp": "2024-01-20T15:30:00Z" + }, + "privacyPolicy": { + "acknowledgment": true, + "version": "1.0.0", + "documentUrl": "https://cardano.org/privacy", + "timestamp": "2024-01-20T15:30:00Z" + }, + "intellectualProperty": { + "acknowledgment": true, + "timestamp": "2024-01-20T15:30:00Z" + }, + "compliance": { + "legalCompliance": true, + "noConflictOfInterest": true, + "accurateInformation": true, + "jurisdictions": [ + "US", + "GB" + ], + "timestamp": "2024-01-20T15:30:00Z" + } + } +} \ No newline at end of file diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/test/proposal/helpers/generic_proposal_template.json b/catalyst_voices/packages/internal/catalyst_voices_models/test/proposal/helpers/generic_proposal_template.json new file mode 100644 index 00000000000..dc5812c5be1 --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_models/test/proposal/helpers/generic_proposal_template.json @@ -0,0 +1,916 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://cardano.org/schemas/catalyst/f14/proposal", + "title": "F14 Submission Form", + "description": "Schema for the F14 Catalyst Proposal Submission Form", + "definitions": { + "schemaReferenceNonUI": { + "$comment": "NOT UI: used to identify the kind of template document used.", + "type": "string", + "format": "path", + "readOnly": true + }, + "segment": { + "$comment": "UI - Logical Document Section Break.", + "type": "object", + "additionalProperties": false + }, + "section": { + "$comment": "UI - Logical Document Sub-Section Break.", + "type": "object", + "additionalProperties": false + }, + "singleLineTextEntry": { + "$comment": "UI - Single Line text entry without any markup or rich text capability.", + "type": "string", + "contentMediaType": "text/plain", + "pattern": "^.*$" + }, + "singleLineHttpsURLEntry": { + "$comment": "UI - Single Line text entry for HTTPS Urls.", + "type": "string", + "format": "uri", + "pattern": "^https:.*" + }, + "multiLineTextEntry": { + "$comment": "UI - Multiline text entry without any markup or rich text capability.", + "type": "string", + "contentMediaType": "text/plain", + "pattern": "^[\\S\\s]*$" + }, + "multiLineTextEntryMarkdown": { + "$comment": "UI - Multiline text entry with Markdown content.", + "type": "string", + "contentMediaType": "text/markdown", + "pattern": "^[\\S\\s]*$" + }, + "dropDownSingleSelect": { + "$comment": "UI - Drop Down Selection of a single entry from the defined enum.", + "type": "string", + "contentMediaType": "text/plain", + "pattern": "^.*$", + "format": "dropDownSingleSelect" + }, + "multiSelect": { + "$comment": "UI - Multiselect from the given items.", + "type": "array", + "uniqueItems": true, + "format": "multiSelect" + }, + "singleLineTextEntryList": { + "$comment": "UI - A Growable List of single line text (no markup or richtext).", + "type": "array", + "format": "singleLineTextEntryList", + "uniqueItems": true, + "default": [], + "items": { + "$ref": "#/definitions/singleLineTextEntry", + "maxLength": 1024 + } + }, + "multiLineTextEntryListMarkdown": { + "$comment": "UI - A Growable List of markdown formatted text fields.", + "type": "array", + "format": "multiLineTextEntryListMarkdown", + "uniqueItems": true, + "default": [], + "items": { + "$ref": "#/definitions/multiLineTextEntryMarkdown", + "maxLength": 10240 + } + }, + "singleLineHttpsURLEntryList": { + "$comment": "UI - A Growable List of HTTPS URLs.", + "type": "array", + "format": "singleLineHttpsURLEntryList", + "uniqueItems": true, + "default": [], + "items": { + "$ref": "#/definitions/singleLineHttpsURLEntry", + "maxLength": 1024 + } + }, + "nestedQuestionsList": { + "$comment": "UI - A Growable List of Questions. The contents are an object, that can have any UI elements within.", + "type": "array", + "format": "nestedQuestionsList", + "uniqueItems": true, + "default": [] + }, + "nestedQuestions": { + "$comment": "UI - The container for a nested question set.", + "type": "object", + "format": "nestedQuestions", + "additionalProperties": false + }, + "singleGroupedTagSelector": { + "$comment": "UI - A selector where a top level selection, gives a single choice from a list of tags.", + "type": "object", + "format": "singleGroupedTagSelector", + "additionalProperties": false + }, + "tagGroup": { + "$comment": "UI - An individual group within a singleGroupedTagSelector.", + "type": "string", + "format": "tagGroup", + "pattern": "^.*$" + }, + "tagSelection": { + "$comment": "UI - An individual tag within the group of a singleGroupedTagSelector.", + "type": "string", + "format": "tagSelection", + "pattern": "^.*$" + }, + "tokenValueCardanoADA": { + "$comment": "UI - A Token Value denominated in Cardano ADA.", + "type": "integer", + "format": "token:cardano:ada" + }, + "durationInMonths": { + "$comment": "UI - A Duration represented in total months.", + "type": "integer", + "format": "datetime:duration:months" + }, + "yesNoChoice": { + "$comment": "UI - A Boolean choice, represented as a Yes/No selection. Yes = true.", + "type": "boolean", + "format": "yesNoChoice", + "default": false + }, + "agreementConfirmation": { + "$comment": "UI - A Boolean choice, defaults to `false` but its invalid if its not set to `true`.", + "type": "boolean", + "format": "agreementConfirmation", + "default": false, + "const": true + }, + "spdxLicenseOrURL": { + "$comment": "UI - Drop Down Selection of any valid SPDX Identifier. This is a complex type, it should let the user select one of the valid SPDX licenses, or enter a URL of the license if its proprietary. In the form its just a string.", + "type": "string", + "contentMediaType": "text/plain", + "pattern": "^.*$", + "format": "spdxLicenseOrURL" + } + }, + "type": "object", + "additionalProperties": false, + "properties": { + "$schema": { + "$ref": "#/definitions/schemaReferenceNonUI", + "default": "./0ce8ab38-9258-4fbc-a62e-7faa6e58318f.schema.json", + "const": "./0ce8ab38-9258-4fbc-a62e-7faa6e58318f.schema.json" + }, + "setup": { + "$ref": "#/definitions/segment", + "title": "proposal setup", + "description": "Proposal title", + "properties": { + "title": { + "$ref": "#/definitions/section", + "title": "proposal setup", + "description": "Proposal title", + "properties": { + "title": { + "$ref": "#/definitions/singleLineTextEntry", + "title": "Proposal Title", + "description": "

Proposal title

Please note we suggest you use no more than 60 characters for your proposal title so that it can be easily viewed in the voting app.

", + "minLength": 1, + "maxLength": 60, + "x-guidance": "

The title should clearly express what the proposal is about. Voters can see the title in the voting app, even without opening the proposal, so a clear, unambiguous, and concise title is very important.

" + } + }, + "required": [ + "title" + ] + }, + "proposer": { + "$ref": "#/definitions/section", + "properties": { + "applicant": { + "$ref": "#/definitions/singleLineTextEntry", + "title": "Name and surname of main applicant", + "description": "Name and surname of main applicant", + "x-guidance": "

Please provide the name and surname of the main applicant. The main applicant is considered as the individual responsible for the project and the person authorized to act on behalf of other applicants (where applicable).

", + "minLength": 2, + "maxLength": 100 + }, + "type": { + "$ref": "#/definitions/dropDownSingleSelect", + "title": "Are you delivering this project as an individual or as an entity (whether formally incorporated or not)", + "description": "Are you delivering this project as an individual or as an entity (whether formally incorporated or not)", + "x-mad-guidance": "

Please select from one of the following:

  1. Individual
  2. Entity (Incorporated)
  3. Entity (Not Incorporated)
", + "enum": [ + "Individual", + "Entity (Incorporated)", + "Entity (Not Incorporated)" + ], + "default": "Individual" + }, + "coproposers": { + "$ref": "#/definitions/singleLineTextEntryList", + "title": "Co-proposers and additional applicants", + "description": "Co-proposers and additional applicants", + "x-guidance": "

List any persons who are submitting the proposal jointly with the main applicant. Make sure you have confirmed approval/awareness with these individuals/accounts before adding them. If there is more than one proposer, identify the lead person who is authorized to act on behalf of other co-proposers. IMPORTANT A maximum of 6 (six) proposals can be led or co-proposed by the same applicant or enterprise. Please, reference Fund 14 rules for added detail.

", + "maxItems": 5, + "minItems": 0 + } + }, + "required": [ + "applicant", + "type" + ] + } + }, + "required": [ + "title", + "proposer" + ] + }, + "summary": { + "$ref": "#/definitions/segment", + "title": "Proposal Summary", + "description": "Key information about your proposal", + "properties": { + "budget": { + "$ref": "#/definitions/section", + "title": "Budget Information", + "properties": { + "requestedFunds": { + "$ref": "#/definitions/tokenValueCardanoADA", + "title": "Requested funds in ADA", + "description": "The amount of funding requested for your proposal", + "x-guidance": "

There is a minimum and a maximum amount of funding that can be requested in a single Catalyst proposal. These are outlined below per each category:

Minimum Funding Amount per proposal:

Cardano Open: A15,000

Cardano Uses Cases: A15,000

Cardano Partners: A500,000

Maximum Funding Amount per proposal:

Cardano Open:

  • Developers (technical): A200,000
  • Ecosystem (non-technical): A100,000

Cardano Uses Cases:

  • Concept A150,000
  • Product: A500,000

Cardano Partners:

  • Enterprise R&D A2,000,000
  • Growth & Acceleration: A2,000,000
", + "minimum": 15000, + "maximum": 2000000 + } + }, + "required": [ + "requestedFunds" + ] + }, + "time": { + "$ref": "#/definitions/section", + "properties": { + "duration": { + "$ref": "#/definitions/durationInMonths", + "title": "Project Duration in Months", + "description": "Specify the expected duration of your project. Projects must be completable within 2-12 months.", + "x-guidance": "

Minimum 2 months-Maximum 12 months. The scope of your funding request and this project is expected to produce the deliverables you specify in the proposal within 2-12 months If you believe your project will take longer than 12 months, consider reducing the project's scope so that it becomes achievable within 12 months If your project completes earlier than scheduled so long as you have submitted your PoAs and Project Close-out report and video then your project can be closed out.

", + "minimum": 2, + "maximum": 12 + } + }, + "required": [ + "duration" + ] + }, + "translation": { + "$ref": "#/definitions/section", + "title": "Translation Information", + "description": "Information about the proposal's language and translation status", + "properties": { + "translated": { + "$ref": "#/definitions/yesNoChoice", + "title": "Auto-translated Status", + "description": "Indicate if your proposal has been auto-translated into English from another language", + "x-guidance": "

Tick YES if your proposal has been auto-translated into English from another language so readers are reminded that your proposal has been translated, and that they should be tolerant of any language imperfections. Tick NO if your proposal has not been auto-translated into English from another language

" + }, + "original": { + "$ref": "#/definitions/singleLineTextEntry", + "title": "Original Language", + "description": "If auto-translated, specify the original language of your proposal", + "minLength": 2, + "maxLength": 50, + "examples": [ + "Spanish", + "Japanese", + "French" + ] + }, + "notes": { + "$ref": "#/definitions/multiLineTextEntry", + "title": "Translation Notes", + "description": "Additional notes about the translation or original language content", + "maxLength": 500 + } + }, + "required": [ + "isTranslated" + ], + "dependencies": { + "originalLanguage": [ + "isTranslated" + ], + "translationNotes": [ + "isTranslated" + ] + }, + "if": { + "properties": { + "isTranslated": { + "const": true + } + } + }, + "then": { + "required": [ + "originalLanguage" + ] + } + }, + "problem": { + "$ref": "#/definitions/section", + "title": "Problem Statement", + "description": "Define the problem your proposal aims to solve", + "properties": { + "statement": { + "$ref": "#/definitions/multiLineTextEntry", + "title": "Problem Description", + "description": "Clearly define the problem you aim to solve. This will be visible in the Catalyst voting app.", + "minLength": 10, + "maxLength": 200, + "x-guidance": "

Ensure you present a well-defined problem. What is the core issue that you hope to fix? Remember: the reader might not recognize the problem unless you state it clearly. This answer will be displayed on the Catalyst voting app, so voters will see it even if they don't open your proposal to read it in detail.

" + }, + "impact": { + "$ref": "#/definitions/multiSelect", + "title": "Impact Areas", + "description": "Select the areas that will be most impacted by solving this problem", + "items": { + "$ref": "#/definitions/singleLineTextEntry", + "enum": [ + "Technical Infrastructure", + "User Experience", + "Developer Tooling", + "Community Growth", + "Economic Sustainability", + "Interoperability", + "Security", + "Scalability", + "Education", + "Adoption" + ] + }, + "minItems": 1, + "maxItems": 3 + } + }, + "required": [ + "statement", + "impact" + ] + }, + "solution": { + "$ref": "#/definitions/section", + "title": "Solution Overview", + "description": "Describe your proposed solution to the problem", + "properties": { + "summary": { + "$ref": "#/definitions/multiLineTextEntry", + "title": "Solution Summary", + "description": "Briefly describe your solution. Focus on what you will do or create to solve the problem.", + "minLength": 10, + "maxLength": 200, + "x-guidance": "

Focus on what you are going to do, or make, or change, to solve the problem. So not 'There should be a way to....' but 'We will make a Clearly state how the solution addresses the specific problem you have identified - connect the 'why' and the 'how' This answer will be displayed on the Catalyst voting app, so voters will see it even if they do not open your proposal and read it in detail.

" + }, + "approach": { + "$ref": "#/definitions/multiLineTextEntry", + "title": "Technical Approach", + "description": "Outline the technical approach or methodology you will use", + "maxLength": 500 + }, + "innovationAspects": { + "$ref": "#/definitions/singleLineTextEntryList", + "title": "Innovation Aspects", + "description": "Key innovative aspects of your solution", + "minItems": 1, + "maxItems": 5 + } + }, + "required": [ + "summary", + "approach" + ] + }, + "SupportingLinks": { + "$ref": "#/definitions/section", + "title": "Supporting Documentation", + "description": "Additional resources and documentation for your proposal", + "x-guidance": "

Here, provide links to yours or your partner organization's website, repository, or marketing. Alternatively, provide links to any whitepaper or other publication relevant to your proposal. Note however that this is extra information that voters and Community Reviewers might choose not to read. You should not fail to include any of the questions in this form because you feel the answers can be found elsewhere. If any links are specified make sure these are added in good order (first link must be present before specifying second). Also ensure all links include https. Without these steps, the form will not be submittable and show errors

", + "properties": { + "mainRepository": { + "$ref": "#/definitions/singleLineHttpsURLEntry", + "title": "Main Code Repository", + "description": "Primary repository where the project's code will be hosted" + }, + "documentation": { + "$ref": "#/definitions/singleLineHttpsURLEntry", + "title": "Documentation URL", + "description": "Main documentation site or resource for the project" + }, + "other": { + "$ref": "#/definitions/singleLineHttpsURLEntryList", + "title": "Resource Links", + "description": "Links to any other relevant documentation, code repositories, or marketing materials. All links must use HTTPS.", + "minItems": 0, + "maxItems": 5 + } + } + }, + "dependencies": { + "$ref": "#/definitions/section", + "title": "Project Dependencies", + "description": "External dependencies and requirements for project success", + "x-guidance": "

If your project has any dependencies and prerequisites for your project's success, list them here. These are usually external factors (such as third-party suppliers, external resources, third-party software, etc.) that may cause a delay, since a project has less control over them. In case of third party software, indicate whether you have the necessary licenses and permission to use such software.

", + "properties": { + "details": { + "$ref": "#/definitions/nestedQuestionsList", + "title": "Dependency Details", + "description": "List and describe each dependency", + "items": { + "$ref": "#/definitions/nestedQuestions", + "properties": { + "name": { + "$ref": "#/definitions/singleLineTextEntry", + "title": "Dependency Name", + "description": "Name of the organization, technology, or resource", + "maxLength": 100 + }, + "type": { + "$ref": "#/definitions/dropDownSingleSelect", + "title": "Dependency Type", + "description": "Type of dependency", + "enum": [ + "Technical", + "Organizational", + "Legal", + "Financial", + "Other" + ] + }, + "description": { + "$ref": "#/definitions/multiLineTextEntry", + "title": "Description", + "description": "Explain why this dependency is essential and how it affects your project", + "maxLength": 500 + }, + "mitigationPlan": { + "$ref": "#/definitions/multiLineTextEntry", + "title": "Mitigation Plan", + "description": "How will you handle potential issues with this dependency", + "maxLength": 300 + } + }, + "required": [ + "name", + "type", + "description" + ] + }, + "minItems": 0, + "maxItems": 10 + } + } + }, + "open_source": { + "$ref": "#/definitions/section", + "title": "Project Open Source", + "description": "Will your project's output/be s fully open source? Open source refers to something people can modify and share because its design is publicly accessible.", + "x-guidance": "

Open source software is software with source code that anyone can inspect, modify, and enhance. Conversely, only the original authors of proprietary software can legally copy, inspect, and alter that software

", + "properties": { + "source_code": { + "$ref": "#/definitions/spdxLicenseOrURL" + }, + "documentation": { + "$ref": "#/definitions/spdxLicenseOrURL" + }, + "note": { + "$ref": "#/definitions/multiLineTextEntry", + "title": "More Information", + "description": "Please provide here more information on the open source status of your project outputs", + "maxLength": 500, + "x-guidance": "

If you did not answer PROPRIETARY to the above questions, the project should be open source-available throughout the entire lifecycle of the project with a declared open-source repository. Please indicate here the type of license you intend to use for open source and provide any further information you feel is relevant to the open source status of your project outputs If only certain elements of your code will be open source please clarify which elements will be open source here. If you answered NO to the above question, please give further details as to why your projects outputs will not be open source METADATA

" + } + }, + "required": [ + "source_code", + "documentation" + ] + } + } + }, + "horizons": { + "$ref": "#/definitions/segment", + "title": "Horizons", + "properties": { + "theme": { + "$ref": "#/definitions/section", + "title": "Horizons", + "description": "Long-term vision and categorization of your project", + "properties": { + "grouped_tag": { + "$ref": "#/definitions/singleGroupedTagSelector", + "oneOf": [ + { + "properties": { + "group": { + "$ref": "#/definitions/tagGroup", + "const": "Governance" + }, + "tag": { + "$ref": "#/definitions/tagSelection", + "enum": [ + "Governance", + "DAO" + ] + } + } + }, + { + "properties": { + "group": { + "$ref": "#/definitions/tagGroup", + "const": "Education" + }, + "tag": { + "$ref": "#/definitions/tagSelection", + "enum": [ + "Education", + "Learn to Earn", + "Training", + "Translation" + ] + } + } + }, + { + "properties": { + "group": { + "$ref": "#/definitions/tagGroup", + "const": "Community & Outreach" + }, + "tag": { + "$ref": "#/definitions/tagSelection", + "enum": [ + "Connected Community", + "Community", + "Community Outreach", + "Social Media" + ] + } + } + }, + { + "properties": { + "group": { + "$ref": "#/definitions/tagGroup", + "const": "Development & Tools" + }, + "tag": { + "$ref": "#/definitions/tagSelection", + "enum": [ + "Developer Tools", + "L2", + "Infrastructure", + "Analytics", + "AI", + "Research", + "UTXO", + "P2P" + ] + } + } + }, + { + "properties": { + "group": { + "$ref": "#/definitions/tagGroup", + "const": "Identity & Security" + }, + "tag": { + "$ref": "#/definitions/tagSelection", + "enum": [ + "Identity & Verification", + "Cybersecurity", + "Security", + "Authentication", + "Privacy" + ] + } + } + }, + { + "properties": { + "group": { + "$ref": "#/definitions/tagGroup", + "const": "DeFi" + }, + "tag": { + "$ref": "#/definitions/tagSelection", + "enum": [ + "DeFi", + "Payments", + "Stablecoin", + "Risk Management", + "Yield", + "Staking", + "Lending" + ] + } + } + }, + { + "properties": { + "group": { + "$ref": "#/definitions/tagGroup", + "const": "Real World Applications" + }, + "tag": { + "$ref": "#/definitions/tagSelection", + "enum": [ + "Wallet", + "Marketplace", + "Manufacturing", + "IoT", + "Financial Services", + "E-commerce", + "Business Services", + "Supply Chain", + "Real Estate", + "Healthcare", + "Tourism", + "Entertainments", + "RWA", + "Music", + "Tokenization" + ] + } + } + }, + { + "properties": { + "group": { + "$ref": "#/definitions/tagGroup", + "const": "Events & Marketing" + }, + "tag": { + "$ref": "#/definitions/tagSelection", + "enum": [ + "Events", + "Marketing", + "Hackathons", + "Accelerator", + "Incubator" + ] + } + } + }, + { + "properties": { + "group": { + "$ref": "#/definitions/tagGroup", + "const": "Interoperability" + }, + "tag": { + "$ref": "#/definitions/tagSelection", + "enum": [ + "Cross-chain", + "Interoperability", + "Off-chain", + "Legal", + "Policy Advocacy", + "Standards" + ] + } + } + }, + { + "properties": { + "group": { + "$ref": "#/definitions/tagGroup", + "const": "Sustainability" + }, + "tag": { + "$ref": "#/definitions/tagSelection", + "enum": [ + "Sustainability", + "Environment", + "Agriculture" + ] + } + } + }, + { + "properties": { + "group": { + "$ref": "#/definitions/tagGroup", + "const": "Smart Contracts" + }, + "tag": { + "$ref": "#/definitions/tagSelection", + "enum": [ + "Smart Contract", + "Smart Contracts", + "Audit", + "Oracles" + ] + } + } + }, + { + "properties": { + "group": { + "$ref": "#/definitions/tagGroup", + "const": "GameFi" + }, + "tag": { + "$ref": "#/definitions/tagSelection", + "enum": [ + "Gaming", + "Gaming (GameFi)", + "Entertainment", + "Metaverse" + ] + } + } + }, + { + "properties": { + "group": { + "$ref": "#/definitions/tagGroup", + "const": "NFT" + }, + "tag": { + "$ref": "#/definitions/tagSelection", + "enum": [ + "NFT", + "CNFT", + "Collectibles", + "Digital Twin" + ] + } + } + } + ] + } + } + } + } + }, + "details": { + "$ref": "#/definitions/segment", + "title": "Your Project and Solution", + "properties": { + "solution": { + "$ref": "#/definitions/section", + "title": "Solution", + "description": "

How you write this section will depend on what type of proposal you are writing. You might want to include details on:


  • How do you perceive the problem you are solving?
  • What are your reasons for approaching it in the way that you have?
  • Who will your project engage?
  • How will you demonstrate or prove your impact?


Explain what is unique about your solution, who will benefit, and why this is important to Cardano.

", + "properties": { + "solution": { + "$ref": "#/definitions/multiLineTextEntryMarkdown", + "minLength": 1, + "maxLength": 10240, + "examples": [ + "Our solution involves developing a decentralized education platform that will..." + ] + } + } + }, + "impact": { + "$ref": "#/definitions/section", + "title": "Impact", + "description": "

Please include here a description of how you intend to measure impact (whether quantitative or qualitative) and how and with whom you will share your outputs:


  • In what way will the success of your project bring value to the Cardano Community? 
  • How will you measure this impact? 
  • How will you share the outputs and opportunities that result from your project?
", + "properties": { + "impact": { + "$ref": "#/definitions/multiLineTextEntryMarkdown", + "minLength": 1, + "maxLength": 10240 + } + } + }, + "feasibility": { + "$ref": "#/definitions/section", + "title": "Capabilities & Feasibility", + "description": "

Please describe your existing capabilities that demonstrate how and why you believe you’re best suited to deliver this project?

Please include the steps or processes that demonstrate that you can be trusted to manage funds properly.

", + "properties": { + "feasibility": { + "$ref": "#/definitions/multiLineTextEntryMarkdown", + "minLength": 1, + "maxLength": 10240 + } + } + } + } + }, + "milestones": { + "$ref": "#/definitions/segment", + "title": "Milestones", + "properties": { + "milestones": { + "$ref": "#/definitions/section", + "description": "

A clear set of milestones and acceptance criteria will demonstrate your capability to deliver the project as proposed. More guidance on submitting milestones as part of your project proposal can be found here.


Milestones guidance


  • For Grant Amounts of up to 75k ada, at least 2 milestones, plus the final one including Project Close-out Report and Video, must be included (3 milestones in total)
  • For Grant Amounts over 75k ada up to 150k ada, at least 3 milestones, plus the final one including Project Close-out Report and Video, must be included (4 milestones in total)
  • For Grant Amounts over 150k ada up to 300k ada, at least 4 milestones, plus the final one including Project Close-out Report and Video, must be included (5 milestones in total)
  • For Grant Amounts exceeding 300k ada, at least 5 milestones, plus the final one including Project Close-out Report and Video, must be included (6 milestones in total)
", + "properties": { + "declared": { + "$ref": "#/definitions/multiLineTextEntryListMarkdown", + "minItems": 3, + "maxItems": 6 + } + } + } + } + }, + "pitch": { + "$ref": "#/definitions/segment", + "title": "Final Pitch", + "properties": { + "team": { + "$ref": "#/definitions/section", + "title": "Team", + "properties": { + "who": { + "$ref": "#/definitions/multiLineTextEntryMarkdown", + "title": "Who is in the project team and what are their roles?", + "description": "p>List your team, their Linkedin profiles (or similar) and state what aspect of the proposal’s work each team member will undertake.


If you are planning to recruit additional team members, please state what specific skills you will be looking for in the people you recruit, so readers can see that you understand what skills will be needed to complete the project.


You are expected to have already engaged the relevant members of the organizations referenced so you understand if they are willing and/or have capacity to support the project. If you have not taken any steps to engage with your team yet, it is likely that the resources will not be available if you are approved for funding, which can jeopardize the project before it has even begun. The Catalyst team cannot help with this, meaning you are expected to have understood the requirements and engaged the necessary people before submitting a proposal.


Have you engaged anyone on any of the technical group channels (eg Discord or Telegram), or do you have a direct line of communications with the people and resources required?


Important: Catalyst funding is not anonymous, and some level of ‘proof of life’ verifications will take place before initial funding is released. Also remember that your proposal will be publicly available, so make sure to obtain any consent required before including confidential or third party information.


All Project Participants must disclose their role and scope of services across any submitted proposals, even if they are not in the lead or co-proposer role, such as an implementer, vendor, service provider, etc. Failure to disclose this information may lead to disqualification from the current grant round.

", + "minLength": 1, + "maxLength": 10240 + } + } + }, + "budget": { + "$ref": "#/definitions/section", + "title": "Budget & Costs", + "properties": { + "costs": { + "$ref": "#/definitions/multiLineTextEntryMarkdown", + "title": "Please provide a cost breakdown of the proposed work and resources", + "description": "

Make sure every element mentioned in your plan reflects its cost. It may be helpful to refer to your plan and timeline, list all the resources you will need at each stage, and what they cost.


Here, provide a clear description of any third party product or service you will be using. This could be hardware, software licenses, professional services (legal, accounting, code auditing, etc) but does not need to include the use of contracted programmers and developers.


The exact budget elements you include will depend on what type of work you are doing, and you might need to give less detail for a small, low-budget proposal. If the cost of the project will exceed the funding request, please provide information about alternative sources of funding.


Consider including budget elements for publicity / marketing / promotion / community engagement; project management; documentation; and reporting back to the community. Most proposals need these, but many proposers forget to include them.


It is the project team’s responsibility to properly manage the funds provided. Make sure to reference Fund Rules to understand eligibility around costs.

", + "minLength": 1, + "maxLength": 10240 + } + } + }, + "value": { + "$ref": "#/definitions/section", + "title": "Value for Money", + "properties": { + "note": { + "$ref": "#/definitions/multiLineTextEntryMarkdown", + "title": "How does the cost of the project represent value for money for the Cardano ecosystem?", + "description": "

Use the response to provide the context about the costs you listed previously, particularly if they are high.


It may be helpful to include some brief information on how you have decided on the costs of the project. 


For instance, can you justify with supporting evidence that costs are proportional to the average wage in your country, or typical freelance rates in your industry? Is there anything else that helps to support how the project represents value for money?

", + "minLength": 1, + "maxLength": 10240 + } + } + } + } + }, + "agreements": { + "$ref": "#/definitions/segment", + "title": "Acknowledgements", + "properties": { + "mandatory": { + "$ref": "#/definitions/section", + "title": "Mandatory", + "properties": { + "fund_rules": { + "$ref": "#/definitions/agreementConfirmation", + "title": "Fund Rules:", + "description": "

By submitting a proposal to Project Catalyst Fund14, I confirm that I have read and agree to be bound by the Fund Rules.

" + }, + "terms_and_conditions": { + "$ref": "#/definitions/agreementConfirmation", + "title": "Terms and Conditions:", + "description": "

By submitting a proposal to Project Catalyst Fund14, I confirm that I have read and agree to be bound by the Project Catalyst Terms and Conditions.

" + }, + "privacy_policy": { + "$ref": "#/definitions/agreementConfirmation", + "title": "Privacy Policy: ", + "description": "

I acknowledge and agree that any data I share in connection with my participation in Project Catalyst Fund14 will be collected, stored, used and processed in accordance with the Catalyst FC’s Privacy Policy.

" + } + }, + "required": [ + "fund_rules", + "terms_and_conditions", + "privacy_policy" + ], + "x-order": [ + "fund_rules", + "terms_and_conditions", + "privacy_policy" + ] + } + }, + "x-order": [ + "mandatory" + ] + } + }, + "x-order": [ + "setup", + "summary", + "horizons", + "details", + "milestones", + "pitch", + "agreement" + ] +} \ No newline at end of file diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/test/proposal/helpers/read_json.dart b/catalyst_voices/packages/internal/catalyst_voices_models/test/proposal/helpers/read_json.dart new file mode 100644 index 00000000000..982db98a6ba --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_models/test/proposal/helpers/read_json.dart @@ -0,0 +1,10 @@ +import 'dart:io'; + +String readJson(String name) { + var dir = Directory.current.path; + + if (dir.endsWith('/test')) { + dir = dir.replaceAll('/test', ''); + } + return File('$dir/$name').readAsStringSync(); +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/test/proposal/proposal_test.dart b/catalyst_voices/packages/internal/catalyst_voices_models/test/proposal/proposal_test.dart new file mode 100644 index 00000000000..a161aa1c249 --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_models/test/proposal/proposal_test.dart @@ -0,0 +1,19 @@ +import 'dart:convert'; + +import 'package:catalyst_voices_models/src/proposal/proposal_template/proposal_template.dart'; +import 'package:test/test.dart'; + +import 'helpers/read_json.dart'; + +Future main() async { + const filePath = '/test/proposal/helpers/generic_proposal_template.json'; + late Map template; + + setUpAll(() { + template = json.decode(readJson(filePath)) as Map; + }); + + test('Test proposal template', () async { + final proposalTemplate = PropTemplate.fromJson(template); + }); +} From 508cb913538f10e3428e7b4314688957fc03883c Mon Sep 17 00:00:00 2001 From: Ryszard Schossler Date: Mon, 9 Dec 2024 14:05:16 +0100 Subject: [PATCH 02/18] fix: delete unused files --- .../base_proposal_template.dart | 32 ------- .../definitions_proposal_template.dart | 93 ------------------- 2 files changed, 125 deletions(-) delete mode 100644 catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/base_proposal_template.dart delete mode 100644 catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/definitions/definitions_proposal_template.dart diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/base_proposal_template.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/base_proposal_template.dart deleted file mode 100644 index 4a29c3c3fec..00000000000 --- a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/base_proposal_template.dart +++ /dev/null @@ -1,32 +0,0 @@ -abstract class PropTemplateBase { - final String ref; - final String title; - final String description; - - const PropTemplateBase({ - required this.ref, - required this.title, - required this.description, - }); -} - -abstract class PropTemplateProperty extends PropTemplateBase { - final List properties; - - const PropTemplateProperty({ - required super.ref, - required super.title, - required super.description, - required this.properties, - }); -} - -abstract class PropTemplateTopic { - final String ref; - final String title; - - const PropTemplateTopic({ - required this.ref, - required this.title, - }); -} diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/definitions/definitions_proposal_template.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/definitions/definitions_proposal_template.dart deleted file mode 100644 index 334993caf6a..00000000000 --- a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/definitions/definitions_proposal_template.dart +++ /dev/null @@ -1,93 +0,0 @@ -sealed class Definitions { - const Definitions(); - - static Definitions select(Map json) { - final ref = json[r'$ref'] as String; - final definition = ref.split('/').last; - return switch (definition) { - 'segment' => SegmentDefinition.fromJson(json), - 'section' => SectionDefiniton.fromJson(json), - 'singleLineTextEntry' => SingleLineTextEntry.fromJson(json), - 'singleLineHttpsURLEntry' => SingleLineHttpsURLEntry.fromJson(json), - 'multiLineTextEntry' => MultiLineTextEntry.fromJson(json), - _ => throw Exception('Unknown link: $definition'), - }; - } -} - -class SegmentDefinition extends Definitions { - final bool additionalProperties; - - const SegmentDefinition({ - required this.additionalProperties, - }); - - factory SegmentDefinition.fromJson(Map json) => - SegmentDefinition( - additionalProperties: json['additionalProperties'] as bool, - ); -} - -class SectionDefiniton extends Definitions { - final bool additionalProperties; - - const SectionDefiniton({ - required this.additionalProperties, - }); - - factory SectionDefiniton.fromJson(Map json) => - SectionDefiniton( - additionalProperties: json['additionalProperties'] as bool, - ); -} - -class SingleLineTextEntry extends Definitions { - final String contentMediaType; - final String pattern; - - const SingleLineTextEntry({ - required this.contentMediaType, - required this.pattern, - }); - - factory SingleLineTextEntry.fromJson(Map json) => - SingleLineTextEntry( - contentMediaType: json['contentMediaType'] as String, - pattern: json['pattern'] as String, - ); -} - -class SingleLineHttpsURLEntry extends Definitions { - final String type; - final String format; - final String pattern; - - const SingleLineHttpsURLEntry({ - required this.type, - required this.format, - required this.pattern, - }); - - factory SingleLineHttpsURLEntry.fromJson(Map json) => - SingleLineHttpsURLEntry( - type: json['type'] as String, - format: json['format'] as String, - pattern: json['pattern'] as String, - ); -} - -class MultiLineTextEntry extends Definitions { - final String contentMediaType; - final String pattern; - - const MultiLineTextEntry({ - required this.contentMediaType, - required this.pattern, - }); - - factory MultiLineTextEntry.fromJson(Map json) => - MultiLineTextEntry( - contentMediaType: json['contentMediaType'] as String, - pattern: json['pattern'] as String, - ); -} From 3757c4a2657e99651c1f5b3a9906bc35985cbdd6 Mon Sep 17 00:00:00 2001 From: Ryszard Schossler Date: Tue, 10 Dec 2024 13:56:06 +0100 Subject: [PATCH 03/18] feat: dtos for properties --- .../proposal_template/proposal_template.dart | 47 ---- .../sections/proposer_section.dart | 39 ---- .../sections/title_section.dart | 35 --- .../segments/proposal_template_segments.dart | 46 ---- .../proposal_template_setup_segment.dart | 44 ---- .../topics/applicant_topic.dart | 26 --- .../topics/coproposers_topic.dart | 26 --- .../proposal_template/topics/title_topic.dart | 26 --- .../proposal_template/topics/type_topic.dart | 26 --- .../definitions/definition.dart | 13 ++ .../definitions/list_entry_definitions.dart | 57 +++++ .../logical_section_definitions.dart | 17 ++ .../definitions/other_definitions.dart | 84 +++++++ .../definitions/tag_definitions.dart | 38 ++++ .../definitions/text_entry_definitions.dart | 45 ++++ .../dtos/proposal_template_dto.dart | 68 ++++++ .../dtos/proposal_template_element_dto.dart | 58 +++++ .../dtos/proposal_template_segment_dto.dart | 49 ++++ .../dtos/proposal_template_topic_dto.dart | 58 +++++ ...8-9258-4fbc-a62e-7faa6e58318f.schema.json} | 0 .../proposal/helpers/generic_proposal.json | 212 ++++-------------- .../test/proposal/proposal_test.dart | 10 +- 22 files changed, 534 insertions(+), 490 deletions(-) delete mode 100644 catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/proposal_template.dart delete mode 100644 catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/sections/proposer_section.dart delete mode 100644 catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/sections/title_section.dart delete mode 100644 catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/segments/proposal_template_segments.dart delete mode 100644 catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/segments/proposal_template_setup_segment.dart delete mode 100644 catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/topics/applicant_topic.dart delete mode 100644 catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/topics/coproposers_topic.dart delete mode 100644 catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/topics/title_topic.dart delete mode 100644 catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/topics/type_topic.dart create mode 100644 catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/definitions/definition.dart create mode 100644 catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/definitions/list_entry_definitions.dart create mode 100644 catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/definitions/logical_section_definitions.dart create mode 100644 catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/definitions/other_definitions.dart create mode 100644 catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/definitions/tag_definitions.dart create mode 100644 catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/definitions/text_entry_definitions.dart create mode 100644 catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/dtos/proposal_template_dto.dart create mode 100644 catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/dtos/proposal_template_element_dto.dart create mode 100644 catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/dtos/proposal_template_segment_dto.dart create mode 100644 catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/dtos/proposal_template_topic_dto.dart rename catalyst_voices/packages/internal/catalyst_voices_models/test/proposal/helpers/{generic_proposal_template.json => 0ce8ab38-9258-4fbc-a62e-7faa6e58318f.schema.json} (100%) diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/proposal_template.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/proposal_template.dart deleted file mode 100644 index 2d8e9938c26..00000000000 --- a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/proposal_template.dart +++ /dev/null @@ -1,47 +0,0 @@ -import 'package:catalyst_voices_models/src/proposal/proposal_template/segments/proposal_template_segments.dart'; -import 'package:equatable/equatable.dart'; -import 'package:json_annotation/json_annotation.dart'; - -part 'proposal_template.g.dart'; - -@JsonSerializable() -class PropTemplate extends Equatable { - final String schema; - final String id; - final String title; - final String description; - final Object definitions; - final String type; - final bool additionalProperties; - final PropTemplateSegments properties; - @JsonKey(name: 'x-order') - final List xorder; - - const PropTemplate({ - required this.schema, - required this.id, - required this.title, - required this.description, - required this.definitions, - required this.type, - required this.additionalProperties, - required this.properties, - required this.xorder, - }); - - factory PropTemplate.fromJson(Map json) => - _$PropTemplateFromJson(json); - - @override - List get props => [ - schema, - id, - title, - description, - definitions, - type, - additionalProperties, - properties, - xorder, - ]; -} diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/sections/proposer_section.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/sections/proposer_section.dart deleted file mode 100644 index 633570801e5..00000000000 --- a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/sections/proposer_section.dart +++ /dev/null @@ -1,39 +0,0 @@ -import 'package:catalyst_voices_models/src/proposal/proposal_template/topics/applicant_topic.dart'; -import 'package:catalyst_voices_models/src/proposal/proposal_template/topics/coproposers_topic.dart'; -import 'package:catalyst_voices_models/src/proposal/proposal_template/topics/type_topic.dart'; -import 'package:json_annotation/json_annotation.dart'; - -part 'proposer_section.g.dart'; - -@JsonSerializable() -class ProposerSection { - @JsonKey(name: r'$ref') - final String ref; - final ProposerProperties properties; - final List required; - - const ProposerSection({ - required this.ref, - required this.properties, - required this.required, - }); - - factory ProposerSection.fromJson(Map json) => - _$ProposerSectionFromJson(json); -} - -@JsonSerializable() -class ProposerProperties { - final ApplicantTopic applicant; - final TypeTopic type; - final CoproposersTopic coproposers; - - const ProposerProperties({ - required this.applicant, - required this.type, - required this.coproposers, - }); - - factory ProposerProperties.fromJson(Map json) => - _$ProposerPropertiesFromJson(json); -} diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/sections/title_section.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/sections/title_section.dart deleted file mode 100644 index e4ae05a0bee..00000000000 --- a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/sections/title_section.dart +++ /dev/null @@ -1,35 +0,0 @@ -import 'package:catalyst_voices_models/src/proposal/proposal_template/topics/title_topic.dart'; -import 'package:json_annotation/json_annotation.dart'; - -part 'title_section.g.dart'; - -@JsonSerializable() -class TitleSection { - @JsonKey(name: r'$ref') - final String ref; - final String title; - final String description; - final TitleProperties properties; - - const TitleSection({ - required this.title, - required this.ref, - required this.description, - required this.properties, - }); - - factory TitleSection.fromJson(Map json) => - _$TitleSectionFromJson(json); -} - -@JsonSerializable() -class TitleProperties { - final TitleTopic title; - - const TitleProperties({ - required this.title, - }); - - factory TitleProperties.fromJson(Map json) => - _$TitlePropertiesFromJson(json); -} diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/segments/proposal_template_segments.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/segments/proposal_template_segments.dart deleted file mode 100644 index 99cd2071dda..00000000000 --- a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/segments/proposal_template_segments.dart +++ /dev/null @@ -1,46 +0,0 @@ -import 'package:catalyst_voices_models/src/proposal/proposal_template/segments/proposal_template_setup_segment.dart'; -import 'package:equatable/equatable.dart'; -import 'package:json_annotation/json_annotation.dart'; - -part 'proposal_template_segments.g.dart'; - -@JsonSerializable() -class PropTemplateSegments extends Equatable { - @JsonKey(name: r'$schema') - final SchemaProperty schema; - final PropTemplateSetup setup; - - const PropTemplateSegments({ - required this.schema, - required this.setup, - }); - - factory PropTemplateSegments.fromJson(Map json) => - _$PropTemplateSegmentsFromJson(json); - - @override - List get props => []; -} - -@JsonSerializable() -class SchemaProperty extends Equatable { - @JsonKey(name: r'$schema') - final String schema; - @JsonKey(name: r'$id') - final String id; - final String title; - final String description; - - const SchemaProperty({ - required this.schema, - required this.id, - required this.title, - required this.description, - }); - - factory SchemaProperty.fromJson(Map json) => - _$SchemaPropertyFromJson(json); - - @override - List get props => [schema, id, title, description]; -} diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/segments/proposal_template_setup_segment.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/segments/proposal_template_setup_segment.dart deleted file mode 100644 index ab94ec4ff03..00000000000 --- a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/segments/proposal_template_setup_segment.dart +++ /dev/null @@ -1,44 +0,0 @@ -import 'package:catalyst_voices_models/src/proposal/proposal_template/sections/proposer_section.dart'; -import 'package:catalyst_voices_models/src/proposal/proposal_template/sections/title_section.dart'; -import 'package:equatable/equatable.dart'; -import 'package:json_annotation/json_annotation.dart'; - -part 'proposal_template_setup_segment.g.dart'; - -@JsonSerializable() -class PropTemplateSetup extends Equatable { - @JsonKey(name: r'$ref') - final String ref; - final String title; - final String description; - final PropTemplateSetupProperties properties; - final List required; - - const PropTemplateSetup({ - required this.ref, - required this.title, - required this.description, - required this.properties, - required this.required, - }); - - factory PropTemplateSetup.fromJson(Map json) => - _$PropTemplateSetupFromJson(json); - - @override - List get props => [title, description, properties, required]; -} - -@JsonSerializable() -class PropTemplateSetupProperties { - final TitleSection title; - final ProposerSection proposer; - - const PropTemplateSetupProperties({ - required this.title, - required this.proposer, - }); - - factory PropTemplateSetupProperties.fromJson(Map json) => - _$PropTemplateSetupPropertiesFromJson(json); -} diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/topics/applicant_topic.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/topics/applicant_topic.dart deleted file mode 100644 index b092c4df5bd..00000000000 --- a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/topics/applicant_topic.dart +++ /dev/null @@ -1,26 +0,0 @@ -import 'package:json_annotation/json_annotation.dart'; - -part 'applicant_topic.g.dart'; - -@JsonSerializable() -class ApplicantTopic { - @JsonKey(name: r'$ref') - final String ref; - final String title; - final String description; - final String guidance; - final int minLength; - final int maxLength; - - ApplicantTopic({ - required this.ref, - required this.title, - required this.description, - required this.guidance, - required this.minLength, - required this.maxLength, - }); - - factory ApplicantTopic.fromJson(Map json) => - _$ApplicantTopicFromJson(json); -} diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/topics/coproposers_topic.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/topics/coproposers_topic.dart deleted file mode 100644 index 53b7cd30789..00000000000 --- a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/topics/coproposers_topic.dart +++ /dev/null @@ -1,26 +0,0 @@ -import 'package:json_annotation/json_annotation.dart'; - -part 'coproposers_topic.g.dart'; - -@JsonSerializable() -class CoproposersTopic { - @JsonKey(name: r'$ref') - final String ref; - final String title; - final String description; - final String guidance; - final int minItems; - final int maxItems; - - const CoproposersTopic({ - required this.ref, - required this.title, - required this.description, - required this.guidance, - required this.minItems, - required this.maxItems, - }); - - factory CoproposersTopic.fromJson(Map json) => - _$CoproposersTopicFromJson(json); -} diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/topics/title_topic.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/topics/title_topic.dart deleted file mode 100644 index 488630362d0..00000000000 --- a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/topics/title_topic.dart +++ /dev/null @@ -1,26 +0,0 @@ -import 'package:json_annotation/json_annotation.dart'; - -part 'title_topic.g.dart'; - -@JsonSerializable() -class TitleTopic { - @JsonKey(name: r'$ref') - final String ref; - final String title; - final String description; - final int minLength; - final int maxLength; - final String guidance; - - const TitleTopic({ - required this.ref, - required this.title, - required this.description, - required this.minLength, - required this.maxLength, - required this.guidance, - }); - - factory TitleTopic.fromJson(Map json) => - _$TitleTopicFromJson(json); -} diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/topics/type_topic.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/topics/type_topic.dart deleted file mode 100644 index ad279377972..00000000000 --- a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal/proposal_template/topics/type_topic.dart +++ /dev/null @@ -1,26 +0,0 @@ -import 'package:json_annotation/json_annotation.dart'; - -part 'type_topic.g.dart'; - -@JsonSerializable() -class TypeTopic { - @JsonKey(name: r'$ref') - final String ref; - final String title; - final String description; - final String guidance; - final List enumValues; - final String defaultValue; - - const TypeTopic({ - required this.ref, - required this.title, - required this.description, - required this.guidance, - required this.enumValues, - required this.defaultValue, - }); - - factory TypeTopic.fromJson(Map json) => - _$TypeTopicFromJson(json); -} diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/definitions/definition.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/definitions/definition.dart new file mode 100644 index 00000000000..6d473bf92a2 --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/definitions/definition.dart @@ -0,0 +1,13 @@ +abstract class Definition { + final String type; + final String? format; + final String? contentMediaType; + final String? pattern; + + const Definition({ + required this.type, + this.format, + this.contentMediaType, + this.pattern, + }); +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/definitions/list_entry_definitions.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/definitions/list_entry_definitions.dart new file mode 100644 index 00000000000..78ea293cb15 --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/definitions/list_entry_definitions.dart @@ -0,0 +1,57 @@ +import 'package:catalyst_voices_models/src/proposal_template/definitions/definition.dart'; + +sealed class ListEntryDefinition extends Definition { + final bool uniqueItems; + final List defaultValue; + + ListEntryDefinition({ + this.uniqueItems = true, + required this.defaultValue, + super.type = 'array', + super.format, + }); +} + +final class SingleLineTextEntryListDefinition extends ListEntryDefinition { + SingleLineTextEntryListDefinition({ + super.uniqueItems, + required super.defaultValue, + required super.type, + super.format = 'singleLineTextEntryList', + }); +} + +final class MultiLineTextEntryListMarkdownDefinition + extends ListEntryDefinition { + MultiLineTextEntryListMarkdownDefinition({ + super.uniqueItems, + required super.defaultValue, + super.format = 'multiLineTextEntryListMarkdown', + }); +} + +final class SingleLineHttpsURLEntryListDefinition extends ListEntryDefinition { + SingleLineHttpsURLEntryListDefinition({ + super.uniqueItems, + required super.defaultValue, + super.format = 'singleLineHttpsURLEntryList', + }); +} + +final class NestedQuestionsListDefinition extends ListEntryDefinition { + NestedQuestionsListDefinition({ + super.uniqueItems, + required super.defaultValue, + super.format = 'nestedQuestionsList', + }); +} + +final class NestedQuestionsDefinition extends Definition { + final bool additionalProperties; + + NestedQuestionsDefinition({ + this.additionalProperties = false, + super.type = 'object', + super.format = 'nestedQuestions', + }); +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/definitions/logical_section_definitions.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/definitions/logical_section_definitions.dart new file mode 100644 index 00000000000..01ca15e1e3b --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/definitions/logical_section_definitions.dart @@ -0,0 +1,17 @@ +import 'package:catalyst_voices_models/src/proposal_template/definitions/definition.dart'; + +sealed class LogicalSectionDefinition extends Definition { + final bool additionalProperties; + + const LogicalSectionDefinition({ + required this.additionalProperties, + }) : super(type: 'object'); +} + +final class SegmentDefinition extends LogicalSectionDefinition { + const SegmentDefinition() : super(additionalProperties: false); +} + +final class SectionDefinition extends LogicalSectionDefinition { + const SectionDefinition() : super(additionalProperties: false); +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/definitions/other_definitions.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/definitions/other_definitions.dart new file mode 100644 index 00000000000..5e22cf052c6 --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/definitions/other_definitions.dart @@ -0,0 +1,84 @@ +import 'package:catalyst_voices_models/src/proposal_template/definitions/definition.dart'; + +final class SchemaReferenceDefinition extends Definition { + final bool readOnly; + + const SchemaReferenceDefinition({ + required this.readOnly, + required String format, + }) : super( + type: 'string', + format: format, + ); +} + +final class DropDownSingleSelectDefinition extends Definition { + const DropDownSingleSelectDefinition() + : super( + type: 'string', + contentMediaType: 'text/plain', + pattern: r'^.*$', + format: 'dropDownSingleSelect', + ); +} + +final class MultiSelectDefinition extends Definition { + final bool uniqueItems; + + const MultiSelectDefinition({ + this.uniqueItems = true, + }) : super( + type: 'array', + format: 'multiSelect', + ); +} + +final class TokenValueCardanoADADefinition extends Definition { + const TokenValueCardanoADADefinition() + : super( + type: 'integer', + format: 'token:cardano:ada', + ); +} + +final class DurationInMonthsDefinition extends Definition { + const DurationInMonthsDefinition() + : super( + type: 'integer', + format: 'datetime:duration:months', + ); +} + +final class YesNoChoiceDefinition extends Definition { + final bool defaultValue; + + const YesNoChoiceDefinition({ + this.defaultValue = false, + }) : super( + type: 'boolean', + format: 'yesNoChoice', + ); +} + +final class AgreementConfirmationDefinition extends Definition { + final bool defaultValue; + final bool constValue; + + const AgreementConfirmationDefinition({ + this.defaultValue = false, + this.constValue = true, + }) : super( + type: 'boolean', + format: 'agreementConfirmation', + ); +} + +final class SPDXLicenseOrURLDefinition extends Definition { + const SPDXLicenseOrURLDefinition() + : super( + type: 'string', + contentMediaType: 'text/plain', + pattern: r'^.*$', + format: 'spdxLicenseOrURL', + ); +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/definitions/tag_definitions.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/definitions/tag_definitions.dart new file mode 100644 index 00000000000..17b66d9f56f --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/definitions/tag_definitions.dart @@ -0,0 +1,38 @@ +import 'package:catalyst_voices_models/src/proposal_template/definitions/definition.dart'; + +sealed class TagDefinition extends Definition { + const TagDefinition({ + required super.type, + required super.format, + super.pattern, + }); +} + +final class SingleGroupedTagSelectorDefinition extends TagDefinition { + final bool additionalProperties; + + const SingleGroupedTagSelectorDefinition({ + this.additionalProperties = false, + }) : super( + type: 'object', + format: 'singleGroupedTagSelector', + ); +} + +final class TagGroupDefinition extends TagDefinition { + const TagGroupDefinition() + : super( + type: 'string', + format: 'tagGroup', + pattern: r'^.*$', + ); +} + +final class TagSelectionDefinition extends TagDefinition { + const TagSelectionDefinition() + : super( + type: 'string', + format: 'tagSelection', + pattern: r'^.*$', + ); +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/definitions/text_entry_definitions.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/definitions/text_entry_definitions.dart new file mode 100644 index 00000000000..aa9050966bb --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/definitions/text_entry_definitions.dart @@ -0,0 +1,45 @@ +import 'package:catalyst_voices_models/src/proposal_template/definitions/definition.dart'; + +sealed class TextEntryDefinition extends Definition { + const TextEntryDefinition({ + required String super.contentMediaType, + required String super.pattern, + required super.type, + }); +} + +final class SingleLineTextEntryDefinition extends TextEntryDefinition { + const SingleLineTextEntryDefinition() + : super( + contentMediaType: 'text/plain', + pattern: r'^.*$', + type: 'string', + ); +} + +final class SingleLineHttpsURLEntryDefinition extends TextEntryDefinition { + const SingleLineHttpsURLEntryDefinition() + : super( + contentMediaType: 'text/plain', + pattern: '^https:.*', + type: 'string', + ); +} + +final class MultiLineTextEntryDefinition extends TextEntryDefinition { + const MultiLineTextEntryDefinition() + : super( + contentMediaType: 'text/plain', + pattern: r'^[\S\s]*$', + type: 'string', + ); +} + +final class MultiLineTextEntryMarkdownDefinition extends TextEntryDefinition { + const MultiLineTextEntryMarkdownDefinition() + : super( + contentMediaType: 'text/markdown', + pattern: r'^[\S\s]*$', + type: 'string', + ); +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/dtos/proposal_template_dto.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/dtos/proposal_template_dto.dart new file mode 100644 index 00000000000..3b361f06312 --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/dtos/proposal_template_dto.dart @@ -0,0 +1,68 @@ +import 'package:catalyst_voices_models/src/proposal_template/dtos/proposal_template_segment_dto.dart'; +import 'package:equatable/equatable.dart'; +import 'package:json_annotation/json_annotation.dart'; + +part 'proposal_template_dto.g.dart'; + +@JsonSerializable() +class ProposalTemplateDTO extends Equatable { + @JsonKey(name: r'$schema') + final String schema; + final String title; + final String description; + final Map definitions; + final String type; + final bool additionalProperties; + final List properties; + @JsonKey(name: 'x-order') + final List order; + + const ProposalTemplateDTO({ + required this.schema, + required this.title, + required this.description, + required this.definitions, + this.type = 'object', + this.additionalProperties = false, + required this.properties, + required this.order, + }); + + factory ProposalTemplateDTO.fromJson(Map json) { + final segmentsMap = json['properties'] as Map; + json['properties'] = MapUtils.convertMapToListWithIds(segmentsMap); + + return _$ProposalTemplateDTOFromJson(json); + } + + Map toJson() => _$ProposalTemplateDTOToJson(this); + + @override + List get props => [ + schema, + title, + description, + definitions, + type, + additionalProperties, + properties, + order, + ]; +} + +class MapUtils { + static List> convertMapToListWithIds( + Map map, + ) { + final list = >[]; + + for (final entry in map.entries) { + if (entry.key == r'$schema') continue; + final value = entry.value as Map; + value['id'] = entry.key; + list.add(value); + } + + return list; + } +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/dtos/proposal_template_element_dto.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/dtos/proposal_template_element_dto.dart new file mode 100644 index 00000000000..1a898cd9629 --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/dtos/proposal_template_element_dto.dart @@ -0,0 +1,58 @@ +import 'package:catalyst_voices_models/src/proposal_template/dtos/proposal_template_dto.dart'; +import 'package:equatable/equatable.dart'; +import 'package:json_annotation/json_annotation.dart'; + +part 'proposal_template_element_dto.g.dart'; + +@JsonSerializable() +class ProposalTemplateElementDto extends Equatable { + @JsonKey(name: r'$ref', includeToJson: false) + final String ref; + final String id; + final String title; + final String description; + final String? minLength; + final String? maxLength; + @JsonKey(name: 'default') + final String defaultValue; + @JsonKey(name: 'x-guidance') + final String guidance; + @JsonKey(name: 'enum') + final List enumValues; + final int? maxItems; + final int? minItems; + final int? minimum; + final int? maximum; + final List examples; + final Map items; // TODO(ryszard-shossler): return to this + + const ProposalTemplateElementDto({ + required this.ref, + required this.id, + required this.title, + required this.description, + required this.minLength, + required this.maxLength, + this.defaultValue = '', + required this.guidance, + this.enumValues = const [], + required this.maxItems, + required this.minItems, + required this.minimum, + required this.maximum, + this.examples = const [], + this.items = const {}, + }); + + factory ProposalTemplateElementDto.fromJson(Map json) { + final segmentsMap = json['properties'] as Map; + json['properties'] = MapUtils.convertMapToListWithIds(segmentsMap); + + return _$ProposalTemplateElementDtoFromJson(json); + } + + Map toJson() => _$ProposalTemplateElementDtoToJson(this); + + @override + List get props => []; +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/dtos/proposal_template_segment_dto.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/dtos/proposal_template_segment_dto.dart new file mode 100644 index 00000000000..710f4516264 --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/dtos/proposal_template_segment_dto.dart @@ -0,0 +1,49 @@ +import 'package:catalyst_voices_models/src/proposal_template/dtos/proposal_template_dto.dart'; +import 'package:catalyst_voices_models/src/proposal_template/dtos/proposal_template_topic_dto.dart'; +import 'package:equatable/equatable.dart'; +import 'package:json_annotation/json_annotation.dart'; + +part 'proposal_template_segment_dto.g.dart'; + +@JsonSerializable() +class ProposalTemplateSegmentDTO extends Equatable { + @JsonKey(name: r'$ref') + final String ref; + final String id; + final String title; + final String description; + final List properties; + final List required; + @JsonKey(name: 'x-order') + final List order; + + const ProposalTemplateSegmentDTO({ + required this.ref, + required this.id, + this.title = '', + this.description = '', + required this.properties, + this.required = const [], + this.order = const [], + }); + + factory ProposalTemplateSegmentDTO.fromJson(Map json) { + final segmentsMap = json['properties'] as Map; + json['properties'] = MapUtils.convertMapToListWithIds(segmentsMap); + + return _$ProposalTemplateSegmentDTOFromJson(json); + } + + Map toJson() => _$ProposalTemplateSegmentDTOToJson(this); + + @override + List get props => [ + ref, + id, + title, + description, + properties, + required, + order, + ]; +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/dtos/proposal_template_topic_dto.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/dtos/proposal_template_topic_dto.dart new file mode 100644 index 00000000000..628e6424a4a --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/dtos/proposal_template_topic_dto.dart @@ -0,0 +1,58 @@ +import 'package:catalyst_voices_models/src/proposal_template/dtos/proposal_template_dto.dart'; +import 'package:equatable/equatable.dart'; +import 'package:json_annotation/json_annotation.dart'; + +part 'proposal_template_topic_dto.g.dart'; + +@JsonSerializable() +class ProposalTemplateTopicDto extends Equatable { + @JsonKey(name: r'$ref') + final String ref; + final String id; + final String description; + final List properties; + final List required; + @JsonKey(name: 'x-order') + final List order; + final Map dependencies; // Return to this + @JsonKey(name: 'if') + final Map ifs; + final Map then; // Return to this + @JsonKey(name: 'open_source') + final Map openSource; // Return to this + + const ProposalTemplateTopicDto({ + required this.ref, + required this.id, + this.description = '', + required this.properties, + this.required = const [], + this.order = const [], + this.dependencies = const {}, + this.ifs = const {}, + this.then = const {}, + this.openSource = const {}, + }); + + factory ProposalTemplateTopicDto.fromJson(Map json) { + final segmentsMap = json['properties'] as Map; + json['properties'] = MapUtils.convertMapToListWithIds(segmentsMap); + + return _$ProposalTemplateTopicDtoFromJson(json); + } + + Map toJson() => _$ProposalTemplateTopicDtoToJson(this); + + @override + List get props => [ + ref, + id, + description, + properties, + required, + order, + dependencies, + ifs, + then, + ]; +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/test/proposal/helpers/generic_proposal_template.json b/catalyst_voices/packages/internal/catalyst_voices_models/test/proposal/helpers/0ce8ab38-9258-4fbc-a62e-7faa6e58318f.schema.json similarity index 100% rename from catalyst_voices/packages/internal/catalyst_voices_models/test/proposal/helpers/generic_proposal_template.json rename to catalyst_voices/packages/internal/catalyst_voices_models/test/proposal/helpers/0ce8ab38-9258-4fbc-a62e-7faa6e58318f.schema.json diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/test/proposal/helpers/generic_proposal.json b/catalyst_voices/packages/internal/catalyst_voices_models/test/proposal/helpers/generic_proposal.json index 4b2d77cdbc3..17aafe4cd15 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_models/test/proposal/helpers/generic_proposal.json +++ b/catalyst_voices/packages/internal/catalyst_voices_models/test/proposal/helpers/generic_proposal.json @@ -18,9 +18,9 @@ "duration": 6 }, "translation": { - "translated": false, - "original": "English", - "notes": "Original proposal in English" + "isTranslated": true, + "originalLanguage": "Spanish", + "translationNotes": "Translated using DeepL with manual review" }, "problem": { "statement": "Current challenge in the Cardano ecosystem...", @@ -38,199 +38,67 @@ "Automated integration tools" ] }, - "SupportingLinks": { - "links": [ - { - "url": "https://github.com/example/project", - "type": "GitHub Repository", - "description": "Project's main repository" - } - ], + "supportingLinks": { "mainRepository": "https://github.com/example/project", - "documentation": "https://docs.example.com" + "documentation": "https://docs.example.com", + "other": [ + "https://github.com/example/project" + ] + }, + "dependencies": { + "details": [] + }, + "open_source": { + "source_code": "MIT", + "documentation": "MIT", + "note": "All project outputs will be open source under MIT license" } }, "horizons": { - "category": { - "primaryCategory": "Development & Tools", - "subCategory": "Developer Tools" - }, - "tags": [ - "defi", - "developer-tools", - "infrastructure" - ], - "impact": { - "timeframe": "Medium-term (6-18 months)", - "scale": "Global", - "metrics": [ - { - "metric": "Developer Adoption", - "target": "500 active developers", - "measurement": "GitHub analytics" - } - ] + "theme": { + "grouped_tag": { + "group": "DeFi", + "tag": "Staking" + } } }, - "proposalDetails": { + "details": { "solution": { - "description": "Our solution provides a comprehensive toolkit...", - "uniqueValue": "First integrated testing framework for Cardano", - "targetAudience": [ - "Cardano Developers", - "DApp Teams" - ], - "implementation": "We will use an agile development approach..." + "solution": "Our solution provides a comprehensive toolkit..." }, "impact": { - "communityBenefit": "Significantly reduces development time and improves code quality", - "metrics": [ - { - "name": "Developer Adoption", - "description": "Number of active developers using the toolkit", - "target": "500 developers", - "measurement": "GitHub analytics and usage statistics" - } - ], - "outputs": [ - "Testing Framework", - "Documentation", - "Training Materials" - ] + "impact": "The project will significantly impact developer productivity..." }, - "capability": { - "teamExperience": "Our team has extensive experience in blockchain development...", - "feasibilityApproach": "We have already developed a proof of concept...", - "fundManagement": "Funds will be managed through a transparent process..." + "feasibility": { + "feasibility": "Our team has extensive experience in blockchain development..." } }, "milestones": { "milestones": { "declared": [ - "a", - "bb", - "cccccccccccccccccccccccc", - "dd", - "eee", - "fff" + "# Initial Setup and Planning\n\nProject setup and infrastructure...", + "# Core Development\n\nImplementation of main features...", + "# Testing and Documentation\n\nComprehensive testing and documentation...", + "# Final Release\n\nProject completion and deployment with Project Close-out Report and Video..." ] } }, - "milestonez": { - "milestonesConfig": { - "grantAmount": 150000, - "numberOfMilestones": 4 - }, - "milestonesList": [ - { - "title": "Initial Setup and Planning", - "description": "Project setup and detailed planning phase", - "deliverables": [ - { - "name": "Project Plan", - "description": "Detailed project planning documentation", - "type": "Documentation" - } - ], - "acceptanceCriteria": [ - "Completed project plan", - "Technical specifications approved" - ], - "evidenceOfCompletion": [ - { - "type": "Documentation", - "description": "Project planning documents and specifications" - } - ], - "timeline": { - "startDate": "2024-03-01", - "endDate": "2024-04-01", - "durationInWeeks": 4 - }, - "budget": { - "amount": 37500, - "breakdown": [ - { - "category": "Development", - "amount": 30000, - "description": "Initial development work" - } - ] - } - } - ] - }, - "finalPitch": { + "pitch": { "team": { - "members": [ - { - "name": "John Doe", - "role": "Project Lead", - "expertise": [ - "Blockchain Development", - "Smart Contracts" - ], - "experience": "10 years in software development", - "links": [ - { - "type": "GitHub", - "url": "https://github.com/johndoe", - "description": "GitHub Profile" - } - ] - } - ] + "who": "Our team consists of experienced blockchain developers..." }, "budget": { - "totalBudget": 150000, - "categories": [ - { - "category": "Development", - "amount": 100000, - "description": "Core development team costs" - } - ] + "costs": "Budget breakdown:\n- Development: 70%\n- Testing: 15%\n- Documentation: 15%" }, - "valueProposition": { - "costBenefitAnalysis": "The project provides significant value...", - "longTermValue": "The solution will continue to benefit the ecosystem...", - "communityBenefits": [ - "Increased developer productivity", - "Better code quality" - ] + "value": { + "note": "This project provides excellent value for money..." } }, - "mandatoryAcknowledgments": { - "fundRules": { - "acknowledgment": true, - "version": "F14", - "timestamp": "2024-01-20T15:30:00Z" - }, - "termsAndConditions": { - "acknowledgment": true, - "version": "1.0.0", - "documentUrl": "https://cardano.org/terms", - "timestamp": "2024-01-20T15:30:00Z" - }, - "privacyPolicy": { - "acknowledgment": true, - "version": "1.0.0", - "documentUrl": "https://cardano.org/privacy", - "timestamp": "2024-01-20T15:30:00Z" - }, - "intellectualProperty": { - "acknowledgment": true, - "timestamp": "2024-01-20T15:30:00Z" - }, - "compliance": { - "legalCompliance": true, - "noConflictOfInterest": true, - "accurateInformation": true, - "jurisdictions": [ - "US", - "GB" - ], - "timestamp": "2024-01-20T15:30:00Z" + "agreements": { + "mandatory": { + "fund_rules": true, + "terms_and_conditions": true, + "privacy_policy": true } } } \ No newline at end of file diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/test/proposal/proposal_test.dart b/catalyst_voices/packages/internal/catalyst_voices_models/test/proposal/proposal_test.dart index a161aa1c249..d379a97b917 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_models/test/proposal/proposal_test.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_models/test/proposal/proposal_test.dart @@ -1,12 +1,13 @@ import 'dart:convert'; -import 'package:catalyst_voices_models/src/proposal/proposal_template/proposal_template.dart'; +import 'package:catalyst_voices_models/src/proposal_template/dtos/proposal_template_dto.dart'; import 'package:test/test.dart'; import 'helpers/read_json.dart'; Future main() async { - const filePath = '/test/proposal/helpers/generic_proposal_template.json'; + const filePath = + '/test/proposal/helpers/0ce8ab38-9258-4fbc-a62e-7faa6e58318f.schema.json'; late Map template; setUpAll(() { @@ -14,6 +15,9 @@ Future main() async { }); test('Test proposal template', () async { - final proposalTemplate = PropTemplate.fromJson(template); + final proposalTemplate = ProposalTemplateDTO.fromJson(template); + + final json = proposalTemplate.toJson(); + print(jsonEncode(json).toString()); }); } From 93f23298fa40c5e1065c17581d19d1e14e1706e3 Mon Sep 17 00:00:00 2001 From: Ryszard Schossler Date: Mon, 16 Dec 2024 18:01:04 +0100 Subject: [PATCH 04/18] feat:creating dtos for proposal schema --- .../definitions/definition.dart | 13 - .../definitions/list_entry_definitions.dart | 57 -- .../logical_section_definitions.dart | 17 - .../definitions/other_definitions.dart | 84 --- .../definitions/tag_definitions.dart | 38 -- .../definitions/text_entry_definitions.dart | 45 -- .../dtos/proposal_definitions_dto.dart | 526 ++++++++++++++++++ .../dtos/proposal_schema_dto.dart | 237 ++++++++ .../dtos/proposal_template_dto.dart | 68 --- .../dtos/proposal_template_element_dto.dart | 58 -- .../dtos/proposal_template_segment_dto.dart | 49 -- .../dtos/proposal_template_topic_dto.dart | 58 -- .../catalyst_voices_models/pubspec.yaml | 5 +- ...38-9258-4fbc-a62e-7faa6e58318f.schema.json | 282 +++++++--- .../test/assets/generic_proposal copy.json | 138 +++++ .../helpers => assets}/generic_proposal.json | 8 +- .../test/proposal/proposal_test.dart | 27 +- .../lib/src/catalyst_voices_shared.dart | 1 + .../lib/src/extension/list_to_map_ext.dart | 0 .../lib/src/extension/map_to_list_ext.dart | 14 + 20 files changed, 1157 insertions(+), 568 deletions(-) delete mode 100644 catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/definitions/definition.dart delete mode 100644 catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/definitions/list_entry_definitions.dart delete mode 100644 catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/definitions/logical_section_definitions.dart delete mode 100644 catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/definitions/other_definitions.dart delete mode 100644 catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/definitions/tag_definitions.dart delete mode 100644 catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/definitions/text_entry_definitions.dart create mode 100644 catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/dtos/proposal_definitions_dto.dart create mode 100644 catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/dtos/proposal_schema_dto.dart delete mode 100644 catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/dtos/proposal_template_dto.dart delete mode 100644 catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/dtos/proposal_template_element_dto.dart delete mode 100644 catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/dtos/proposal_template_segment_dto.dart delete mode 100644 catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/dtos/proposal_template_topic_dto.dart rename catalyst_voices/packages/internal/catalyst_voices_models/test/{proposal/helpers => assets}/0ce8ab38-9258-4fbc-a62e-7faa6e58318f.schema.json (77%) create mode 100644 catalyst_voices/packages/internal/catalyst_voices_models/test/assets/generic_proposal copy.json rename catalyst_voices/packages/internal/catalyst_voices_models/test/{proposal/helpers => assets}/generic_proposal.json (94%) create mode 100644 catalyst_voices/packages/internal/catalyst_voices_shared/lib/src/extension/list_to_map_ext.dart create mode 100644 catalyst_voices/packages/internal/catalyst_voices_shared/lib/src/extension/map_to_list_ext.dart diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/definitions/definition.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/definitions/definition.dart deleted file mode 100644 index 6d473bf92a2..00000000000 --- a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/definitions/definition.dart +++ /dev/null @@ -1,13 +0,0 @@ -abstract class Definition { - final String type; - final String? format; - final String? contentMediaType; - final String? pattern; - - const Definition({ - required this.type, - this.format, - this.contentMediaType, - this.pattern, - }); -} diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/definitions/list_entry_definitions.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/definitions/list_entry_definitions.dart deleted file mode 100644 index 78ea293cb15..00000000000 --- a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/definitions/list_entry_definitions.dart +++ /dev/null @@ -1,57 +0,0 @@ -import 'package:catalyst_voices_models/src/proposal_template/definitions/definition.dart'; - -sealed class ListEntryDefinition extends Definition { - final bool uniqueItems; - final List defaultValue; - - ListEntryDefinition({ - this.uniqueItems = true, - required this.defaultValue, - super.type = 'array', - super.format, - }); -} - -final class SingleLineTextEntryListDefinition extends ListEntryDefinition { - SingleLineTextEntryListDefinition({ - super.uniqueItems, - required super.defaultValue, - required super.type, - super.format = 'singleLineTextEntryList', - }); -} - -final class MultiLineTextEntryListMarkdownDefinition - extends ListEntryDefinition { - MultiLineTextEntryListMarkdownDefinition({ - super.uniqueItems, - required super.defaultValue, - super.format = 'multiLineTextEntryListMarkdown', - }); -} - -final class SingleLineHttpsURLEntryListDefinition extends ListEntryDefinition { - SingleLineHttpsURLEntryListDefinition({ - super.uniqueItems, - required super.defaultValue, - super.format = 'singleLineHttpsURLEntryList', - }); -} - -final class NestedQuestionsListDefinition extends ListEntryDefinition { - NestedQuestionsListDefinition({ - super.uniqueItems, - required super.defaultValue, - super.format = 'nestedQuestionsList', - }); -} - -final class NestedQuestionsDefinition extends Definition { - final bool additionalProperties; - - NestedQuestionsDefinition({ - this.additionalProperties = false, - super.type = 'object', - super.format = 'nestedQuestions', - }); -} diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/definitions/logical_section_definitions.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/definitions/logical_section_definitions.dart deleted file mode 100644 index 01ca15e1e3b..00000000000 --- a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/definitions/logical_section_definitions.dart +++ /dev/null @@ -1,17 +0,0 @@ -import 'package:catalyst_voices_models/src/proposal_template/definitions/definition.dart'; - -sealed class LogicalSectionDefinition extends Definition { - final bool additionalProperties; - - const LogicalSectionDefinition({ - required this.additionalProperties, - }) : super(type: 'object'); -} - -final class SegmentDefinition extends LogicalSectionDefinition { - const SegmentDefinition() : super(additionalProperties: false); -} - -final class SectionDefinition extends LogicalSectionDefinition { - const SectionDefinition() : super(additionalProperties: false); -} diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/definitions/other_definitions.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/definitions/other_definitions.dart deleted file mode 100644 index 5e22cf052c6..00000000000 --- a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/definitions/other_definitions.dart +++ /dev/null @@ -1,84 +0,0 @@ -import 'package:catalyst_voices_models/src/proposal_template/definitions/definition.dart'; - -final class SchemaReferenceDefinition extends Definition { - final bool readOnly; - - const SchemaReferenceDefinition({ - required this.readOnly, - required String format, - }) : super( - type: 'string', - format: format, - ); -} - -final class DropDownSingleSelectDefinition extends Definition { - const DropDownSingleSelectDefinition() - : super( - type: 'string', - contentMediaType: 'text/plain', - pattern: r'^.*$', - format: 'dropDownSingleSelect', - ); -} - -final class MultiSelectDefinition extends Definition { - final bool uniqueItems; - - const MultiSelectDefinition({ - this.uniqueItems = true, - }) : super( - type: 'array', - format: 'multiSelect', - ); -} - -final class TokenValueCardanoADADefinition extends Definition { - const TokenValueCardanoADADefinition() - : super( - type: 'integer', - format: 'token:cardano:ada', - ); -} - -final class DurationInMonthsDefinition extends Definition { - const DurationInMonthsDefinition() - : super( - type: 'integer', - format: 'datetime:duration:months', - ); -} - -final class YesNoChoiceDefinition extends Definition { - final bool defaultValue; - - const YesNoChoiceDefinition({ - this.defaultValue = false, - }) : super( - type: 'boolean', - format: 'yesNoChoice', - ); -} - -final class AgreementConfirmationDefinition extends Definition { - final bool defaultValue; - final bool constValue; - - const AgreementConfirmationDefinition({ - this.defaultValue = false, - this.constValue = true, - }) : super( - type: 'boolean', - format: 'agreementConfirmation', - ); -} - -final class SPDXLicenseOrURLDefinition extends Definition { - const SPDXLicenseOrURLDefinition() - : super( - type: 'string', - contentMediaType: 'text/plain', - pattern: r'^.*$', - format: 'spdxLicenseOrURL', - ); -} diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/definitions/tag_definitions.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/definitions/tag_definitions.dart deleted file mode 100644 index 17b66d9f56f..00000000000 --- a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/definitions/tag_definitions.dart +++ /dev/null @@ -1,38 +0,0 @@ -import 'package:catalyst_voices_models/src/proposal_template/definitions/definition.dart'; - -sealed class TagDefinition extends Definition { - const TagDefinition({ - required super.type, - required super.format, - super.pattern, - }); -} - -final class SingleGroupedTagSelectorDefinition extends TagDefinition { - final bool additionalProperties; - - const SingleGroupedTagSelectorDefinition({ - this.additionalProperties = false, - }) : super( - type: 'object', - format: 'singleGroupedTagSelector', - ); -} - -final class TagGroupDefinition extends TagDefinition { - const TagGroupDefinition() - : super( - type: 'string', - format: 'tagGroup', - pattern: r'^.*$', - ); -} - -final class TagSelectionDefinition extends TagDefinition { - const TagSelectionDefinition() - : super( - type: 'string', - format: 'tagSelection', - pattern: r'^.*$', - ); -} diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/definitions/text_entry_definitions.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/definitions/text_entry_definitions.dart deleted file mode 100644 index aa9050966bb..00000000000 --- a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/definitions/text_entry_definitions.dart +++ /dev/null @@ -1,45 +0,0 @@ -import 'package:catalyst_voices_models/src/proposal_template/definitions/definition.dart'; - -sealed class TextEntryDefinition extends Definition { - const TextEntryDefinition({ - required String super.contentMediaType, - required String super.pattern, - required super.type, - }); -} - -final class SingleLineTextEntryDefinition extends TextEntryDefinition { - const SingleLineTextEntryDefinition() - : super( - contentMediaType: 'text/plain', - pattern: r'^.*$', - type: 'string', - ); -} - -final class SingleLineHttpsURLEntryDefinition extends TextEntryDefinition { - const SingleLineHttpsURLEntryDefinition() - : super( - contentMediaType: 'text/plain', - pattern: '^https:.*', - type: 'string', - ); -} - -final class MultiLineTextEntryDefinition extends TextEntryDefinition { - const MultiLineTextEntryDefinition() - : super( - contentMediaType: 'text/plain', - pattern: r'^[\S\s]*$', - type: 'string', - ); -} - -final class MultiLineTextEntryMarkdownDefinition extends TextEntryDefinition { - const MultiLineTextEntryMarkdownDefinition() - : super( - contentMediaType: 'text/markdown', - pattern: r'^[\S\s]*$', - type: 'string', - ); -} diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/dtos/proposal_definitions_dto.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/dtos/proposal_definitions_dto.dart new file mode 100644 index 00000000000..2100db7e327 --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/dtos/proposal_definitions_dto.dart @@ -0,0 +1,526 @@ +import 'package:json_annotation/json_annotation.dart'; +part 'proposal_definitions_dto.g.dart'; + +@JsonSerializable() +class ProposalDefinitionsDTO { + final SegmentDTO segment; + final SectionDTO section; + final SingleLineTextEntryDTO singleLineTextEntry; + final SingleLineHttpsURLEntryDTO singleLineHttpsURLEntry; + final MultiLineTextEntryDTO multiLineTextEntry; + final MultiLineTextEntryMarkdownDTO multiLineTextEntryMarkdown; + final DropDownSingleSelectDTO dropDownSingleSelect; + final MultiSelectDTO multiSelect; + final SingleLineTextEntryListDTO singleLineTextEntryList; + final MultiLineTextEntryListMarkdownDTO multiLineTextEntryListMarkdown; + final SingleLineHttpsURLEntryListDTO singleLineHttpsURLEntryList; + final NestedQuestionsListDTO nestedQuestionsList; + final NestedQuestionsDTO nestedQuestions; + final SingleGroupedTagSelectorDTO singleGroupedTagSelector; + final TagGroupDTO tagGroup; + final TagSelectionDTO tagSelection; + @JsonKey(name: 'tokenValueCardanoADA') + final TokenValueCardanoAdaDTO tokenValueCardanoAda; + final DurationInMonthsDTO durationInMonths; + final YesNoChoiceDTO yesNoChoice; + final AgreementConfirmationDTO agreementConfirmation; + @JsonKey(name: 'spdxLicenseOrURL') + final SPDXLicenceOrUrlDTO spdxLicenceOrUrl; + + const ProposalDefinitionsDTO({ + required this.segment, + required this.section, + required this.singleLineTextEntry, + required this.singleLineHttpsURLEntry, + required this.multiLineTextEntry, + required this.multiLineTextEntryMarkdown, + required this.dropDownSingleSelect, + required this.multiSelect, + required this.singleLineTextEntryList, + required this.multiLineTextEntryListMarkdown, + required this.singleLineHttpsURLEntryList, + required this.nestedQuestionsList, + required this.nestedQuestions, + required this.singleGroupedTagSelector, + required this.tagGroup, + required this.tagSelection, + required this.tokenValueCardanoAda, + required this.durationInMonths, + required this.yesNoChoice, + required this.agreementConfirmation, + required this.spdxLicenceOrUrl, + }); + + factory ProposalDefinitionsDTO.fromJson(Map json) => + _$ProposalDefinitionsDTOFromJson(json); + + Map toJson() => _$ProposalDefinitionsDTOToJson(this); +} + +@JsonSerializable() +class SegmentDTO { + final String type; + final bool additionalProperties; + @JsonKey(name: 'x-note') + final String note; + + const SegmentDTO({ + required this.type, + required this.additionalProperties, + required this.note, + }); + + factory SegmentDTO.fromJson(Map json) => + _$SegmentDTOFromJson(json); + + Map toJson() => _$SegmentDTOToJson(this); +} + +@JsonSerializable() +class SectionDTO { + final String type; + final bool additionalProperties; + @JsonKey(name: 'x-note') + final String note; + + const SectionDTO({ + required this.type, + required this.additionalProperties, + required this.note, + }); + + factory SectionDTO.fromJson(Map json) => + _$SectionDTOFromJson(json); + + Map toJson() => _$SectionDTOToJson(this); +} + +@JsonSerializable() +class SingleLineTextEntryDTO { + final String type; + final String contentMediaType; + final String pattern; + @JsonKey(name: 'x-note') + final String note; + + const SingleLineTextEntryDTO({ + required this.type, + required this.contentMediaType, + required this.pattern, + required this.note, + }); + + factory SingleLineTextEntryDTO.fromJson(Map json) => + _$SingleLineTextEntryDTOFromJson(json); + + Map toJson() => _$SingleLineTextEntryDTOToJson(this); +} + +@JsonSerializable() +class SingleLineHttpsURLEntryDTO { + final String type; + final String format; + final String pattern; + @JsonKey(name: 'x-note') + final String note; + + const SingleLineHttpsURLEntryDTO({ + required this.type, + required this.format, + required this.pattern, + required this.note, + }); + + factory SingleLineHttpsURLEntryDTO.fromJson(Map json) => + _$SingleLineHttpsURLEntryDTOFromJson(json); + + Map toJson() => _$SingleLineHttpsURLEntryDTOToJson(this); +} + +@JsonSerializable() +class MultiLineTextEntryDTO { + final String type; + final String contentMediaType; + final String pattern; + final String format; + @JsonKey(name: 'x-note') + final String note; + + const MultiLineTextEntryDTO({ + required this.type, + required this.contentMediaType, + required this.pattern, + required this.format, + required this.note, + }); + + factory MultiLineTextEntryDTO.fromJson(Map json) => + _$MultiLineTextEntryDTOFromJson(json); + + Map toJson() => _$MultiLineTextEntryDTOToJson(this); +} + +@JsonSerializable() +class MultiLineTextEntryMarkdownDTO { + final String type; + final String contentMediaType; + final String pattern; + final String format; + @JsonKey(name: 'x-note') + final String note; + + const MultiLineTextEntryMarkdownDTO({ + required this.type, + required this.contentMediaType, + required this.pattern, + required this.format, + required this.note, + }); + + factory MultiLineTextEntryMarkdownDTO.fromJson(Map json) => + _$MultiLineTextEntryMarkdownDTOFromJson(json); + + Map toJson() => _$MultiLineTextEntryMarkdownDTOToJson(this); +} + +@JsonSerializable() +class DropDownSingleSelectDTO { + final String type; + final String contentMediaType; + final String pattern; + final String format; + @JsonKey(name: 'x-note') + final String note; + + const DropDownSingleSelectDTO({ + required this.type, + required this.contentMediaType, + required this.pattern, + required this.format, + required this.note, + }); + + factory DropDownSingleSelectDTO.fromJson(Map json) => + _$DropDownSingleSelectDTOFromJson(json); + + Map toJson() => _$DropDownSingleSelectDTOToJson(this); +} + +@JsonSerializable() +class MultiSelectDTO { + final String type; + final String contentMediaType; + final String pattern; + final String format; + @JsonKey(name: 'x-note') + final String note; + + const MultiSelectDTO({ + required this.type, + required this.contentMediaType, + required this.pattern, + required this.format, + required this.note, + }); + + factory MultiSelectDTO.fromJson(Map json) => + _$MultiSelectDTOFromJson(json); + + Map toJson() => _$MultiSelectDTOToJson(this); +} + +@JsonSerializable() +class SingleLineTextEntryListDTO { + final String type; + final String format; + final bool uniqueItems; + @JsonKey(name: 'default') + final List defaultValue; + final Map items; + @JsonKey(name: 'x-note') + final String note; + + const SingleLineTextEntryListDTO({ + required this.type, + required this.format, + required this.uniqueItems, + required this.defaultValue, + required this.items, + required this.note, + }); + + factory SingleLineTextEntryListDTO.fromJson(Map json) => + _$SingleLineTextEntryListDTOFromJson(json); + + Map toJson() => _$SingleLineTextEntryListDTOToJson(this); +} + +@JsonSerializable() +class MultiLineTextEntryListMarkdownDTO { + final String type; + final String format; + final bool uniqueItems; + @JsonKey(name: 'default') + final List defaultValue; + final Map items; + @JsonKey(name: 'x-note') + final String note; + + const MultiLineTextEntryListMarkdownDTO({ + required this.type, + required this.format, + required this.uniqueItems, + required this.defaultValue, + required this.items, + required this.note, + }); + + factory MultiLineTextEntryListMarkdownDTO.fromJson( + Map json) => + _$MultiLineTextEntryListMarkdownDTOFromJson(json); + + Map toJson() => + _$MultiLineTextEntryListMarkdownDTOToJson(this); +} + +@JsonSerializable() +class SingleLineHttpsURLEntryListDTO { + final String type; + final String format; + final bool uniqueItems; + @JsonKey(name: 'default') + final List defaultValue; + final Map items; + @JsonKey(name: 'x-note') + final String note; + + const SingleLineHttpsURLEntryListDTO({ + required this.type, + required this.format, + required this.uniqueItems, + required this.defaultValue, + required this.items, + required this.note, + }); + + factory SingleLineHttpsURLEntryListDTO.fromJson(Map json) => + _$SingleLineHttpsURLEntryListDTOFromJson(json); + + Map toJson() => _$SingleLineHttpsURLEntryListDTOToJson(this); +} + +@JsonSerializable() +class NestedQuestionsListDTO { + final String type; + final String format; + final bool uniqueItems; + @JsonKey(name: 'default') + final List defaultValue; + @JsonKey(name: 'x-note') + final String note; + + const NestedQuestionsListDTO({ + required this.type, + required this.format, + required this.uniqueItems, + required this.defaultValue, + required this.note, + }); + + factory NestedQuestionsListDTO.fromJson(Map json) => + _$NestedQuestionsListDTOFromJson(json); + + Map toJson() => _$NestedQuestionsListDTOToJson(this); +} + +@JsonSerializable() +class NestedQuestionsDTO { + final String type; + final String format; + final bool additionalProperties; + @JsonKey(name: 'x-note') + final String note; + + const NestedQuestionsDTO({ + required this.type, + required this.format, + required this.additionalProperties, + required this.note, + }); + + factory NestedQuestionsDTO.fromJson(Map json) => + _$NestedQuestionsDTOFromJson(json); + + Map toJson() => _$NestedQuestionsDTOToJson(this); +} + +@JsonSerializable() +class SingleGroupedTagSelectorDTO { + final String type; + final String format; + final bool additionalProperties; + @JsonKey(name: 'x-note') + final String note; + + const SingleGroupedTagSelectorDTO({ + required this.type, + required this.format, + required this.additionalProperties, + required this.note, + }); + + factory SingleGroupedTagSelectorDTO.fromJson(Map json) => + _$SingleGroupedTagSelectorDTOFromJson(json); + + Map toJson() => _$SingleGroupedTagSelectorDTOToJson(this); +} + +@JsonSerializable() +class TagGroupDTO { + final String type; + final String format; + final String additionalProperties; + @JsonKey(name: 'x-note') + final String note; + + const TagGroupDTO({ + required this.type, + required this.format, + required this.additionalProperties, + required this.note, + }); + + factory TagGroupDTO.fromJson(Map json) => + _$TagGroupDTOFromJson(json); + + Map toJson() => _$TagGroupDTOToJson(this); +} + +@JsonSerializable() +class TagSelectionDTO { + final String type; + final String format; + final String additionalProperties; + @JsonKey(name: 'x-note') + final String note; + + const TagSelectionDTO({ + required this.type, + required this.format, + required this.additionalProperties, + required this.note, + }); + + factory TagSelectionDTO.fromJson(Map json) => + _$TagSelectionDTOFromJson(json); + + Map toJson() => _$TagSelectionDTOToJson(this); +} + +@JsonSerializable() +class TokenValueCardanoAdaDTO { + final String type; + final String format; + @JsonKey(name: 'x-note') + final String note; + + const TokenValueCardanoAdaDTO({ + required this.type, + required this.format, + required this.note, + }); + + factory TokenValueCardanoAdaDTO.fromJson(Map json) => + _$TokenValueCardanoAdaDTOFromJson(json); + + Map toJson() => _$TokenValueCardanoAdaDTOToJson(this); +} + +@JsonSerializable() +class DurationInMonthsDTO { + final String type; + final String format; + @JsonKey(name: 'x-note') + final String note; + + const DurationInMonthsDTO({ + required this.type, + required this.format, + required this.note, + }); + + factory DurationInMonthsDTO.fromJson(Map json) => + _$DurationInMonthsDTOFromJson(json); + + Map toJson() => _$DurationInMonthsDTOToJson(this); +} + +@JsonSerializable() +class YesNoChoiceDTO { + final String type; + final String format; + @JsonKey(name: 'default') + final bool defaultValue; + @JsonKey(name: 'x-note') + final String note; + + const YesNoChoiceDTO({ + required this.type, + required this.format, + required this.defaultValue, + required this.note, + }); + + factory YesNoChoiceDTO.fromJson(Map json) => + _$YesNoChoiceDTOFromJson(json); + + Map toJson() => _$YesNoChoiceDTOToJson(this); +} + +@JsonSerializable() +class AgreementConfirmationDTO { + final String type; + final String format; + @JsonKey(name: 'default') + final bool defaultValue; + @JsonKey(name: 'const') + final bool constValue; + @JsonKey(name: 'x-note') + final String note; + + const AgreementConfirmationDTO({ + required this.type, + required this.format, + required this.defaultValue, + required this.constValue, + required this.note, + }); + + factory AgreementConfirmationDTO.fromJson(Map json) => + _$AgreementConfirmationDTOFromJson(json); + + Map toJson() => _$AgreementConfirmationDTOToJson(this); +} + +@JsonSerializable() +class SPDXLicenceOrUrlDTO { + final String type; + final String contentMediaType; + final String additionalProperties; + final String format; + @JsonKey(name: 'x-note') + final String note; + + const SPDXLicenceOrUrlDTO({ + required this.type, + required this.contentMediaType, + required this.additionalProperties, + required this.format, + required this.note, + }); + + factory SPDXLicenceOrUrlDTO.fromJson(Map json) => + _$SPDXLicenceOrUrlDTOFromJson(json); + + Map toJson() => _$SPDXLicenceOrUrlDTOToJson(this); +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/dtos/proposal_schema_dto.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/dtos/proposal_schema_dto.dart new file mode 100644 index 00000000000..2bd739f7787 --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/dtos/proposal_schema_dto.dart @@ -0,0 +1,237 @@ +import 'package:catalyst_voices_models/src/proposal_template/dtos/proposal_definitions_dto.dart'; +import 'package:catalyst_voices_shared/catalyst_voices_shared.dart'; +import 'package:equatable/equatable.dart'; +import 'package:json_annotation/json_annotation.dart'; + +part 'proposal_schema_dto.g.dart'; + +@JsonSerializable() +class ProposalSchemaDTO extends Equatable { + @JsonKey(name: r'$schema') + final String schema; + final String title; + final String description; + final ProposalDefinitionsDTO definitions; + final String type; + final bool additionalProperties; + @JsonKey(toJson: _toJsonProperties) + final List properties; + @JsonKey(name: 'x-order') + final List order; + + const ProposalSchemaDTO({ + required this.schema, + required this.title, + required this.description, + required this.definitions, + this.type = 'object', + this.additionalProperties = false, + required this.properties, + required this.order, + }); + + factory ProposalSchemaDTO.fromJson(Map json) { + final segmentsMap = json['properties'] as Map; + json['properties'] = segmentsMap.convertMapToListWithIds(); + + return _$ProposalSchemaDTOFromJson(json); + } + + Map toJson() => _$ProposalSchemaDTOToJson(this); + + @override + List get props => [ + schema, + title, + description, + definitions, + type, + additionalProperties, + properties, + order, + ]; + + static Map _toJsonProperties( + List properties, + ) { + final map = {}; + for (final property in properties) { + map[property.id] = property.toJson(); + } + return map; + } +} + +@JsonSerializable() +class ProposalSchemaSegmentDTO extends Equatable { + @JsonKey(name: r'$ref') + final String ref; + final String id; + final String title; + final String description; + @JsonKey(toJson: _toJsonProperties) + final List properties; + final List required; + @JsonKey(name: 'x-order') + final List order; + + const ProposalSchemaSegmentDTO({ + required this.ref, + required this.id, + this.title = '', + this.description = '', + required this.properties, + this.required = const [], + this.order = const [], + }); + + factory ProposalSchemaSegmentDTO.fromJson(Map json) { + final segmentsMap = json['properties'] as Map; + json['properties'] = segmentsMap.convertMapToListWithIds(); + + return _$ProposalSchemaSegmentDTOFromJson(json); + } + + Map toJson() => _$ProposalSchemaSegmentDTOToJson(this); + + @override + List get props => [ + ref, + id, + title, + description, + properties, + required, + order, + ]; + + static Map _toJsonProperties( + List properties, + ) { + final map = {}; + for (final property in properties) { + map[property.id] = property.toJson(); + } + return map; + } +} + +@JsonSerializable() +class ProposalSectionTopicDto extends Equatable { + @JsonKey(name: r'$ref') + final String ref; + final String id; + final String title; + final String description; + final List properties; + final List required; + @JsonKey(name: 'x-order') + final List order; + final Map dependencies; // Return to this + @JsonKey(name: 'if') + final Map ifs; + final Map then; // Return to this + @JsonKey(name: 'open_source') + final Map openSource; // Return to this + + const ProposalSectionTopicDto({ + required this.ref, + required this.id, + this.title = '', + this.description = '', + required this.properties, + this.required = const [], + this.order = const [], + this.dependencies = const {}, + this.ifs = const {}, + this.then = const {}, + this.openSource = const {}, + }); + + factory ProposalSectionTopicDto.fromJson(Map json) { + final segmentsMap = json['properties'] as Map; + json['properties'] = segmentsMap.convertMapToListWithIds(); + + return _$ProposalSectionTopicDtoFromJson(json); + } + + Map toJson() => _$ProposalSectionTopicDtoToJson(this); + + @override + List get props => [ + ref, + id, + title, + description, + properties, + required, + order, + dependencies, + ifs, + then, + ]; +} + +@JsonSerializable() +class ProposalSchemaElementDTO extends Equatable { + @JsonKey(name: r'$ref', includeToJson: false) + final String ref; + final String id; + final String title; + final String description; + final String? minLength; + final String? maxLength; + @JsonKey(name: 'default') + final String defaultValue; + @JsonKey(name: 'x-guidance') + final String guidance; + @JsonKey(name: 'enum') + final List enumValues; + final int? maxItems; + final int? minItems; + final int? minimum; + final int? maximum; + final List examples; + final Map items; // TODO(ryszard-shossler): return to this + + const ProposalSchemaElementDTO({ + required this.ref, + required this.id, + required this.title, + required this.description, + required this.minLength, + required this.maxLength, + this.defaultValue = '', + required this.guidance, + this.enumValues = const [], + required this.maxItems, + required this.minItems, + required this.minimum, + required this.maximum, + this.examples = const [], + this.items = const {}, + }); + + factory ProposalSchemaElementDTO.fromJson(Map json) => + _$ProposalSchemaElementDTOFromJson(json); + + Map toJson() => _$ProposalSchemaElementDTOToJson(this); + + @override + List get props => [ + ref, + id, + title, + description, + minLength, + maxLength, + defaultValue, + guidance, + enumValues, + maxItems, + minItems, + minimum, + maximum, + examples, + ]; +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/dtos/proposal_template_dto.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/dtos/proposal_template_dto.dart deleted file mode 100644 index 3b361f06312..00000000000 --- a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/dtos/proposal_template_dto.dart +++ /dev/null @@ -1,68 +0,0 @@ -import 'package:catalyst_voices_models/src/proposal_template/dtos/proposal_template_segment_dto.dart'; -import 'package:equatable/equatable.dart'; -import 'package:json_annotation/json_annotation.dart'; - -part 'proposal_template_dto.g.dart'; - -@JsonSerializable() -class ProposalTemplateDTO extends Equatable { - @JsonKey(name: r'$schema') - final String schema; - final String title; - final String description; - final Map definitions; - final String type; - final bool additionalProperties; - final List properties; - @JsonKey(name: 'x-order') - final List order; - - const ProposalTemplateDTO({ - required this.schema, - required this.title, - required this.description, - required this.definitions, - this.type = 'object', - this.additionalProperties = false, - required this.properties, - required this.order, - }); - - factory ProposalTemplateDTO.fromJson(Map json) { - final segmentsMap = json['properties'] as Map; - json['properties'] = MapUtils.convertMapToListWithIds(segmentsMap); - - return _$ProposalTemplateDTOFromJson(json); - } - - Map toJson() => _$ProposalTemplateDTOToJson(this); - - @override - List get props => [ - schema, - title, - description, - definitions, - type, - additionalProperties, - properties, - order, - ]; -} - -class MapUtils { - static List> convertMapToListWithIds( - Map map, - ) { - final list = >[]; - - for (final entry in map.entries) { - if (entry.key == r'$schema') continue; - final value = entry.value as Map; - value['id'] = entry.key; - list.add(value); - } - - return list; - } -} diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/dtos/proposal_template_element_dto.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/dtos/proposal_template_element_dto.dart deleted file mode 100644 index 1a898cd9629..00000000000 --- a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/dtos/proposal_template_element_dto.dart +++ /dev/null @@ -1,58 +0,0 @@ -import 'package:catalyst_voices_models/src/proposal_template/dtos/proposal_template_dto.dart'; -import 'package:equatable/equatable.dart'; -import 'package:json_annotation/json_annotation.dart'; - -part 'proposal_template_element_dto.g.dart'; - -@JsonSerializable() -class ProposalTemplateElementDto extends Equatable { - @JsonKey(name: r'$ref', includeToJson: false) - final String ref; - final String id; - final String title; - final String description; - final String? minLength; - final String? maxLength; - @JsonKey(name: 'default') - final String defaultValue; - @JsonKey(name: 'x-guidance') - final String guidance; - @JsonKey(name: 'enum') - final List enumValues; - final int? maxItems; - final int? minItems; - final int? minimum; - final int? maximum; - final List examples; - final Map items; // TODO(ryszard-shossler): return to this - - const ProposalTemplateElementDto({ - required this.ref, - required this.id, - required this.title, - required this.description, - required this.minLength, - required this.maxLength, - this.defaultValue = '', - required this.guidance, - this.enumValues = const [], - required this.maxItems, - required this.minItems, - required this.minimum, - required this.maximum, - this.examples = const [], - this.items = const {}, - }); - - factory ProposalTemplateElementDto.fromJson(Map json) { - final segmentsMap = json['properties'] as Map; - json['properties'] = MapUtils.convertMapToListWithIds(segmentsMap); - - return _$ProposalTemplateElementDtoFromJson(json); - } - - Map toJson() => _$ProposalTemplateElementDtoToJson(this); - - @override - List get props => []; -} diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/dtos/proposal_template_segment_dto.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/dtos/proposal_template_segment_dto.dart deleted file mode 100644 index 710f4516264..00000000000 --- a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/dtos/proposal_template_segment_dto.dart +++ /dev/null @@ -1,49 +0,0 @@ -import 'package:catalyst_voices_models/src/proposal_template/dtos/proposal_template_dto.dart'; -import 'package:catalyst_voices_models/src/proposal_template/dtos/proposal_template_topic_dto.dart'; -import 'package:equatable/equatable.dart'; -import 'package:json_annotation/json_annotation.dart'; - -part 'proposal_template_segment_dto.g.dart'; - -@JsonSerializable() -class ProposalTemplateSegmentDTO extends Equatable { - @JsonKey(name: r'$ref') - final String ref; - final String id; - final String title; - final String description; - final List properties; - final List required; - @JsonKey(name: 'x-order') - final List order; - - const ProposalTemplateSegmentDTO({ - required this.ref, - required this.id, - this.title = '', - this.description = '', - required this.properties, - this.required = const [], - this.order = const [], - }); - - factory ProposalTemplateSegmentDTO.fromJson(Map json) { - final segmentsMap = json['properties'] as Map; - json['properties'] = MapUtils.convertMapToListWithIds(segmentsMap); - - return _$ProposalTemplateSegmentDTOFromJson(json); - } - - Map toJson() => _$ProposalTemplateSegmentDTOToJson(this); - - @override - List get props => [ - ref, - id, - title, - description, - properties, - required, - order, - ]; -} diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/dtos/proposal_template_topic_dto.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/dtos/proposal_template_topic_dto.dart deleted file mode 100644 index 628e6424a4a..00000000000 --- a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/dtos/proposal_template_topic_dto.dart +++ /dev/null @@ -1,58 +0,0 @@ -import 'package:catalyst_voices_models/src/proposal_template/dtos/proposal_template_dto.dart'; -import 'package:equatable/equatable.dart'; -import 'package:json_annotation/json_annotation.dart'; - -part 'proposal_template_topic_dto.g.dart'; - -@JsonSerializable() -class ProposalTemplateTopicDto extends Equatable { - @JsonKey(name: r'$ref') - final String ref; - final String id; - final String description; - final List properties; - final List required; - @JsonKey(name: 'x-order') - final List order; - final Map dependencies; // Return to this - @JsonKey(name: 'if') - final Map ifs; - final Map then; // Return to this - @JsonKey(name: 'open_source') - final Map openSource; // Return to this - - const ProposalTemplateTopicDto({ - required this.ref, - required this.id, - this.description = '', - required this.properties, - this.required = const [], - this.order = const [], - this.dependencies = const {}, - this.ifs = const {}, - this.then = const {}, - this.openSource = const {}, - }); - - factory ProposalTemplateTopicDto.fromJson(Map json) { - final segmentsMap = json['properties'] as Map; - json['properties'] = MapUtils.convertMapToListWithIds(segmentsMap); - - return _$ProposalTemplateTopicDtoFromJson(json); - } - - Map toJson() => _$ProposalTemplateTopicDtoToJson(this); - - @override - List get props => [ - ref, - id, - description, - properties, - required, - order, - dependencies, - ifs, - then, - ]; -} diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/pubspec.yaml b/catalyst_voices/packages/internal/catalyst_voices_models/pubspec.yaml index 2816e42f049..6cd4eb2eac8 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_models/pubspec.yaml +++ b/catalyst_voices/packages/internal/catalyst_voices_models/pubspec.yaml @@ -11,6 +11,8 @@ dependencies: catalyst_cardano: ^0.3.0 catalyst_cardano_serialization: ^0.4.0 catalyst_cardano_web: ^0.3.0 + catalyst_voices_shared: + path: ../catalyst_voices_shared collection: ^1.18.0 convert: ^3.1.1 equatable: ^2.0.7 @@ -19,8 +21,7 @@ dependencies: password_strength: ^0.2.0 dev_dependencies: - build_runner: ^2.4.13 + build_runner: ^2.4.12 catalyst_analysis: ^2.0.0 - json_serializable: ^6.9.0 test: ^1.24.9 diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/test/proposal/helpers/0ce8ab38-9258-4fbc-a62e-7faa6e58318f.schema.json b/catalyst_voices/packages/internal/catalyst_voices_models/test/assets/0ce8ab38-9258-4fbc-a62e-7faa6e58318f.schema.json similarity index 77% rename from catalyst_voices/packages/internal/catalyst_voices_models/test/proposal/helpers/0ce8ab38-9258-4fbc-a62e-7faa6e58318f.schema.json rename to catalyst_voices/packages/internal/catalyst_voices_models/test/assets/0ce8ab38-9258-4fbc-a62e-7faa6e58318f.schema.json index dc5812c5be1..93e6bef9b69 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_models/test/proposal/helpers/0ce8ab38-9258-4fbc-a62e-7faa6e58318f.schema.json +++ b/catalyst_voices/packages/internal/catalyst_voices_models/test/assets/0ce8ab38-9258-4fbc-a62e-7faa6e58318f.schema.json @@ -13,49 +13,57 @@ "segment": { "$comment": "UI - Logical Document Section Break.", "type": "object", - "additionalProperties": false + "additionalProperties": false, + "x-note": "Major sections of the proposal. Each segment contains sections of information grouped together." }, "section": { "$comment": "UI - Logical Document Sub-Section Break.", "type": "object", - "additionalProperties": false + "additionalProperties": false, + "x-note": "Subsections containing specific details about the proposal." }, "singleLineTextEntry": { "$comment": "UI - Single Line text entry without any markup or rich text capability.", "type": "string", "contentMediaType": "text/plain", - "pattern": "^.*$" + "pattern": "^.*$", + "x-note": "Enter a single line of text. No formatting, line breaks, or special characters are allowed." }, "singleLineHttpsURLEntry": { "$comment": "UI - Single Line text entry for HTTPS Urls.", "type": "string", "format": "uri", - "pattern": "^https:.*" + "pattern": "^https:.*", + "x-note": "Enter a valid HTTPS URL. Must start with 'https://' and be a complete, working web address." }, "multiLineTextEntry": { "$comment": "UI - Multiline text entry without any markup or rich text capability.", "type": "string", "contentMediaType": "text/plain", - "pattern": "^[\\S\\s]*$" + "pattern": "^[\\S\\s]*$", + "x-note": "Enter multiple lines of plain text. You can use line breaks but no special formatting." }, "multiLineTextEntryMarkdown": { "$comment": "UI - Multiline text entry with Markdown content.", "type": "string", "contentMediaType": "text/markdown", - "pattern": "^[\\S\\s]*$" + "pattern": "^[\\S\\s]*$", + "x-note": "Use Markdown formatting for rich text. Available formatting:\n- Headers: # for h1, ## for h2, etc.\n- Lists: * or - for bullets, 1. for numbered\n- Emphasis: *italic* or **bold**\n- Links: [text](url)\n- Code: `inline` or ```block```" }, "dropDownSingleSelect": { "$comment": "UI - Drop Down Selection of a single entry from the defined enum.", "type": "string", "contentMediaType": "text/plain", "pattern": "^.*$", - "format": "dropDownSingleSelect" + "format": "dropDownSingleSelect", + "x-note": "Select one option from the dropdown menu. Only one choice is allowed." }, "multiSelect": { "$comment": "UI - Multiselect from the given items.", "type": "array", "uniqueItems": true, - "format": "multiSelect" + "format": "multiSelect", + "x-note": "Select multiple options from the dropdown menu. Multiple choices are allowed." }, "singleLineTextEntryList": { "$comment": "UI - A Growable List of single line text (no markup or richtext).", @@ -66,7 +74,8 @@ "items": { "$ref": "#/definitions/singleLineTextEntry", "maxLength": 1024 - } + }, + "x-note": "Add multiple single-line text entries. Each entry should be unique and under 1024 characters." }, "multiLineTextEntryListMarkdown": { "$comment": "UI - A Growable List of markdown formatted text fields.", @@ -77,7 +86,8 @@ "items": { "$ref": "#/definitions/multiLineTextEntryMarkdown", "maxLength": 10240 - } + }, + "x-note": "Add multiple markdown-formatted text entries. Each entry can include rich formatting and should be unique." }, "singleLineHttpsURLEntryList": { "$comment": "UI - A Growable List of HTTPS URLs.", @@ -88,68 +98,79 @@ "items": { "$ref": "#/definitions/singleLineHttpsURLEntry", "maxLength": 1024 - } + }, + "x-note": "Enter multiple HTTPS URLs. Each URL should be unique and under 1024 characters." }, "nestedQuestionsList": { "$comment": "UI - A Growable List of Questions. The contents are an object, that can have any UI elements within.", "type": "array", "format": "nestedQuestionsList", "uniqueItems": true, - "default": [] + "default": [], + "x-note": "Add multiple questions. Each question should be unique." }, "nestedQuestions": { "$comment": "UI - The container for a nested question set.", "type": "object", "format": "nestedQuestions", - "additionalProperties": false + "additionalProperties": false, + "x-note": "Add multiple questions. Each question should be unique." }, "singleGroupedTagSelector": { "$comment": "UI - A selector where a top level selection, gives a single choice from a list of tags.", "type": "object", "format": "singleGroupedTagSelector", - "additionalProperties": false + "additionalProperties": true, + "x-note": "Select one option from the dropdown menu. Only one choice is allowed." }, "tagGroup": { "$comment": "UI - An individual group within a singleGroupedTagSelector.", "type": "string", "format": "tagGroup", - "pattern": "^.*$" + "pattern": "^.*$", + "x-note": "Select one option from the dropdown menu. Only one choice is allowed." }, "tagSelection": { "$comment": "UI - An individual tag within the group of a singleGroupedTagSelector.", "type": "string", "format": "tagSelection", - "pattern": "^.*$" + "pattern": "^.*$", + "x-note": "Select one option from the dropdown menu. Only one choice is allowed." }, "tokenValueCardanoADA": { "$comment": "UI - A Token Value denominated in Cardano ADA.", "type": "integer", - "format": "token:cardano:ada" + "format": "token:cardano:ada", + "x-note": "Enter the amount of Cardano ADA to be used in the proposal." }, "durationInMonths": { "$comment": "UI - A Duration represented in total months.", "type": "integer", - "format": "datetime:duration:months" + "format": "datetime:duration:months", + "x-note": "Enter the duration of the proposal in months." }, "yesNoChoice": { "$comment": "UI - A Boolean choice, represented as a Yes/No selection. Yes = true.", "type": "boolean", "format": "yesNoChoice", - "default": false + "default": false, + "x-note": "Select Yes or No." }, "agreementConfirmation": { "$comment": "UI - A Boolean choice, defaults to `false` but its invalid if its not set to `true`.", "type": "boolean", "format": "agreementConfirmation", "default": false, - "const": true + "const": true, + "x-note": "Select Yes or No." }, "spdxLicenseOrURL": { "$comment": "UI - Drop Down Selection of any valid SPDX Identifier. This is a complex type, it should let the user select one of the valid SPDX licenses, or enter a URL of the license if its proprietary. In the form its just a string.", "type": "string", "contentMediaType": "text/plain", "pattern": "^.*$", - "format": "spdxLicenseOrURL" + "format": "spdxLicenseOrURL", + "x-note": "Select one option from the dropdown menu. Only one choice is allowed." } }, "type": "object", @@ -198,7 +219,7 @@ "$ref": "#/definitions/dropDownSingleSelect", "title": "Are you delivering this project as an individual or as an entity (whether formally incorporated or not)", "description": "Are you delivering this project as an individual or as an entity (whether formally incorporated or not)", - "x-mad-guidance": "

Please select from one of the following:

  1. Individual
  2. Entity (Incorporated)
  3. Entity (Not Incorporated)
", + "x-guidance": "

Please select from one of the following:

  1. Individual
  2. Entity (Incorporated)
  3. Entity (Not Incorporated)
", "enum": [ "Individual", "Entity (Incorporated)", @@ -218,12 +239,21 @@ "required": [ "applicant", "type" + ], + "x-order": [ + "applicant", + "type", + "coproposers" ] } }, "required": [ "title", "proposer" + ], + "x-order": [ + "title", + "proposer" ] }, "summary": { @@ -246,6 +276,9 @@ }, "required": [ "requestedFunds" + ], + "x-order": [ + "requestedFunds" ] }, "time": { @@ -269,42 +302,39 @@ "title": "Translation Information", "description": "Information about the proposal's language and translation status", "properties": { - "translated": { + "isTranslated": { "$ref": "#/definitions/yesNoChoice", "title": "Auto-translated Status", "description": "Indicate if your proposal has been auto-translated into English from another language", "x-guidance": "

Tick YES if your proposal has been auto-translated into English from another language so readers are reminded that your proposal has been translated, and that they should be tolerant of any language imperfections. Tick NO if your proposal has not been auto-translated into English from another language

" }, - "original": { + "originalLanguage": { "$ref": "#/definitions/singleLineTextEntry", "title": "Original Language", "description": "If auto-translated, specify the original language of your proposal", - "minLength": 2, - "maxLength": 50, - "examples": [ - "Spanish", + "enum": [ + "Arabic", + "Chinese", + "French", + "German", + "Indonesian", + "Italian", "Japanese", - "French" + "Korean", + "Portuguese", + "Russian", + "Spanish", + "Turkish", + "Vietnamese", + "Other" ] }, - "notes": { - "$ref": "#/definitions/multiLineTextEntry", - "title": "Translation Notes", - "description": "Additional notes about the translation or original language content", - "maxLength": 500 + "originalDocumentLink": { + "$ref": "#/definitions/singleLineHttpsURLEntry", + "title": "Original Document Link", + "description": "Provide a link to the original proposal document in its original language" } }, - "required": [ - "isTranslated" - ], - "dependencies": { - "originalLanguage": [ - "isTranslated" - ], - "translationNotes": [ - "isTranslated" - ] - }, "if": { "properties": { "isTranslated": { @@ -314,9 +344,31 @@ }, "then": { "required": [ - "originalLanguage" - ] - } + "originalLanguage", + "originalDocumentLink" + ], + "properties": { + "originalLanguage": { + "description": "Original language is required when the proposal is translated" + }, + "originalDocumentLink": { + "description": "Link to the original document is required when the proposal is translated" + } + } + }, + "else": { + "properties": { + "originalLanguage": { + "not": {} + }, + "originalDocumentLink": { + "not": {} + } + } + }, + "required": [ + "isTranslated" + ] }, "problem": { "$ref": "#/definitions/section", @@ -391,7 +443,7 @@ "approach" ] }, - "SupportingLinks": { + "supportingLinks": { "$ref": "#/definitions/section", "title": "Supporting Documentation", "description": "Additional resources and documentation for your proposal", @@ -474,7 +526,7 @@ "open_source": { "$ref": "#/definitions/section", "title": "Project Open Source", - "description": "Will your project's output/be s fully open source? Open source refers to something people can modify and share because its design is publicly accessible.", + "description": "Will your project's output be fully open source? Open source refers to something people can modify and share because its design is publicly accessible.", "x-guidance": "

Open source software is software with source code that anyone can inspect, modify, and enhance. Conversely, only the original authors of proprietary software can legally copy, inspect, and alter that software

", "properties": { "source_code": { @@ -488,15 +540,30 @@ "title": "More Information", "description": "Please provide here more information on the open source status of your project outputs", "maxLength": 500, - "x-guidance": "

If you did not answer PROPRIETARY to the above questions, the project should be open source-available throughout the entire lifecycle of the project with a declared open-source repository. Please indicate here the type of license you intend to use for open source and provide any further information you feel is relevant to the open source status of your project outputs If only certain elements of your code will be open source please clarify which elements will be open source here. If you answered NO to the above question, please give further details as to why your projects outputs will not be open source METADATA

" + "x-guidance": "

If you did not answer PROPRIETARY to the above questions, the project should be open source available throughout the entire lifecycle of the project with a declared open-source repository. Please indicate here the type of license you intend to use for open source and provide any further information you feel is relevant to the open source status of your project outputs If only certain elements of your code will be open source please clarify which elements will be open source here. If you answered NO to the above question, please give further details as to why your projects outputs will not be open source METADATA

" } }, "required": [ "source_code", "documentation" + ], + "x-order": [ + "source_code", + "documentation", + "note" ] } - } + }, + "x-order": [ + "budget", + "time", + "translation", + "problem", + "solution", + "supportingLinks", + "dependencies", + "open_source" + ] }, "horizons": { "$ref": "#/definitions/segment", @@ -752,9 +819,15 @@ } ] } - } + }, + "x-order": [ + "theme" + ] } - } + }, + "x-order": [ + "theme" + ] }, "details": { "$ref": "#/definitions/segment", @@ -799,7 +872,12 @@ } } } - } + }, + "x-order": [ + "solution", + "impact", + "feasibility" + ] }, "milestones": { "$ref": "#/definitions/segment", @@ -807,16 +885,87 @@ "properties": { "milestones": { "$ref": "#/definitions/section", - "description": "

A clear set of milestones and acceptance criteria will demonstrate your capability to deliver the project as proposed. More guidance on submitting milestones as part of your project proposal can be found here.


Milestones guidance


  • For Grant Amounts of up to 75k ada, at least 2 milestones, plus the final one including Project Close-out Report and Video, must be included (3 milestones in total)
  • For Grant Amounts over 75k ada up to 150k ada, at least 3 milestones, plus the final one including Project Close-out Report and Video, must be included (4 milestones in total)
  • For Grant Amounts over 150k ada up to 300k ada, at least 4 milestones, plus the final one including Project Close-out Report and Video, must be included (5 milestones in total)
  • For Grant Amounts exceeding 300k ada, at least 5 milestones, plus the final one including Project Close-out Report and Video, must be included (6 milestones in total)
", + "title": "Project Milestones", + "description": "

Each milestone must declare:

  • A: Milestone outputs
  • B: Acceptance criteria
  • C: Evidence of completion

Requirements:

  • For Grant Amounts up to 75k ada: minimum 3 milestones (2 + final)
  • For Grant Amounts 75k-150k ada: minimum 4 milestones (3 + final)
  • The final milestone must include Project Close-out Report and Video
", "properties": { - "declared": { - "$ref": "#/definitions/multiLineTextEntryListMarkdown", + "milestone_list": { + "type": "array", + "title": "Milestones", + "description": "What are the key milestones you need to achieve in order to complete your project successfully?", + "x-guidance": "

Milestone Requirements:

  • For Grant Amounts of up to 75k ada: at least 2 milestones, plus the final one including Project Close-out Report and Video, must be included (3 milestones in total)
  • For Grant Amounts over 75k ada up to 150k ada: at least 3 milestones, plus the final one including Project Close-out Report and Video, must be included (4 milestones in total)
  • For Grant Amounts over 150k ada up to 300k ada: at least 4 milestones, plus the final one including Project Close-out Report and Video, must be included (5 milestones in total)
  • For Grant Amounts exceeding 300k ada: at least 5 milestones, plus the final one including Project Close-out Report and Video, must be included (6 milestones in total)
", "minItems": 3, - "maxItems": 6 + "maxItems": 6, + "items": { + "type": "object", + "required": [ + "title", + "outputs", + "acceptance_criteria", + "evidence", + "delivery_month", + "cost" + ], + "properties": { + "title": { + "$ref": "#/definitions/singleLineTextEntry", + "title": "Milestone Title", + "description": "A clear, concise title for this milestone", + "maxLength": 100 + }, + "outputs": { + "$ref": "#/definitions/multiLineTextEntryMarkdown", + "title": "Milestone Outputs", + "description": "What will be delivered in this milestone", + "maxLength": 1000 + }, + "acceptance_criteria": { + "$ref": "#/definitions/multiLineTextEntryMarkdown", + "title": "Acceptance Criteria", + "description": "Specific conditions that must be met", + "maxLength": 1000 + }, + "evidence": { + "$ref": "#/definitions/multiLineTextEntryMarkdown", + "title": "Evidence of Completion", + "description": "How you will demonstrate achievement", + "maxLength": 1000 + }, + "delivery_month": { + "$ref": "#/definitions/durationInMonths", + "title": "Delivery Month", + "description": "The month when this milestone will be delivered", + "minimum": 1, + "maximum": 12 + }, + "cost": { + "$ref": "#/definitions/tokenValueCardanoADA", + "title": "Cost in ADA", + "description": "The cost of this milestone in ADA" + }, + "progress": { + "$ref": "#/definitions/dropDownSingleSelect", + "title": "Progress Status", + "description": "Current status of the milestone", + "enum": [ + "Not Started", + "In Progress", + "Completed", + "Delayed" + ], + "default": "Not Started" + } + } + } } - } + }, + "required": [ + "milestone_list" + ] } - } + }, + "x-order": [ + "milestones" + ] }, "pitch": { "$ref": "#/definitions/segment", @@ -829,7 +978,7 @@ "who": { "$ref": "#/definitions/multiLineTextEntryMarkdown", "title": "Who is in the project team and what are their roles?", - "description": "p>List your team, their Linkedin profiles (or similar) and state what aspect of the proposal’s work each team member will undertake.


If you are planning to recruit additional team members, please state what specific skills you will be looking for in the people you recruit, so readers can see that you understand what skills will be needed to complete the project.


You are expected to have already engaged the relevant members of the organizations referenced so you understand if they are willing and/or have capacity to support the project. If you have not taken any steps to engage with your team yet, it is likely that the resources will not be available if you are approved for funding, which can jeopardize the project before it has even begun. The Catalyst team cannot help with this, meaning you are expected to have understood the requirements and engaged the necessary people before submitting a proposal.


Have you engaged anyone on any of the technical group channels (eg Discord or Telegram), or do you have a direct line of communications with the people and resources required?


Important: Catalyst funding is not anonymous, and some level of ‘proof of life’ verifications will take place before initial funding is released. Also remember that your proposal will be publicly available, so make sure to obtain any consent required before including confidential or third party information.


All Project Participants must disclose their role and scope of services across any submitted proposals, even if they are not in the lead or co-proposer role, such as an implementer, vendor, service provider, etc. Failure to disclose this information may lead to disqualification from the current grant round.

", + "description": "

List your team, their Linkedin profiles (or similar) and state what aspect of the proposal’s work each team member will undertake.


If you are planning to recruit additional team members, please state what specific skills you will be looking for in the people you recruit, so readers can see that you understand what skills will be needed to complete the project.


You are expected to have already engaged the relevant members of the organizations referenced so you understand if they are willing and/or have capacity to support the project. If you have not taken any steps to engage with your team yet, it is likely that the resources will not be available if you are approved for funding, which can jeopardize the project before it has even begun. The Catalyst team cannot help with this, meaning you are expected to have understood the requirements and engaged the necessary people before submitting a proposal.


Have you engaged anyone on any of the technical group channels (eg Discord or Telegram), or do you have a direct line of communications with the people and resources required?


Important: Catalyst funding is not anonymous, and some level of ‘proof of life’ verifications will take place before initial funding is released. Also remember that your proposal will be publicly available, so make sure to obtain any consent required before including confidential or third party information.


All Project Participants must disclose their role and scope of services across any submitted proposals, even if they are not in the lead or co-proposer role, such as an implementer, vendor, service provider, etc. Failure to disclose this information may lead to disqualification from the current grant round.

", "minLength": 1, "maxLength": 10240 } @@ -861,7 +1010,12 @@ } } } - } + }, + "x-order": [ + "team", + "budget", + "value" + ] }, "agreements": { "$ref": "#/definitions/segment", @@ -911,6 +1065,6 @@ "details", "milestones", "pitch", - "agreement" + "agreements" ] } \ No newline at end of file diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/test/assets/generic_proposal copy.json b/catalyst_voices/packages/internal/catalyst_voices_models/test/assets/generic_proposal copy.json new file mode 100644 index 00000000000..e0100f00cc8 --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_models/test/assets/generic_proposal copy.json @@ -0,0 +1,138 @@ +{ + "$schema": "./0ce8ab38-9258-4fbc-a62e-7faa6e58318f.schema.json", + "setup": { + "title": { + "title": "Example Catalyst Proposal" + }, + "proposer": { + "applicant": "John Smith", + "type": "Individual", + "coproposers": [ + "Jane Doe", + "Bob Wilson" + ] + } + }, + "summary": { + "budget": { + "requestedFunds": 150000 + }, + "time": { + "duration": 6 + }, + "translation": { + "isTranslated": true, + "originalLanguage": "German", + "originalDocumentLink": "https://example.com/original-doc" + }, + "problem": { + "statement": "Current challenge in the Cardano ecosystem...", + "impact": [ + "Technical Infrastructure", + "Developer Tooling", + "Adoption" + ] + }, + "solution": { + "summary": "Our solution provides a comprehensive toolkit...", + "approach": "We will implement this solution using...", + "innovationAspects": [ + "Novel testing framework", + "Automated integration tools" + ] + }, + "supportingLinks": { + "mainRepository": "https://github.com/example/project", + "documentation": "https://docs.example.com", + "other": [ + "https://example.com/whitepaper", + "https://example.com/roadmap" + ] + }, + "dependencies": { + "details": [ + { + "name": "External API Service", + "type": "Technical", + "description": "Integration with third-party API service", + "mitigationPlan": "Build fallback mechanisms and maintain alternative providers" + } + ] + }, + "open_source": { + "source_code": "MIT", + "documentation": "MIT", + "note": "All project outputs will be open source under MIT license" + } + }, + "horizons": { + "theme": { + "grouped_tag": { + "group": "DeFi", + "tag": "Staking" + } + } + }, + "details": { + "solution": { + "solution": "Our solution involves developing a comprehensive toolkit that will enhance the Cardano developer experience..." + }, + "impact": { + "impact": "The project will significantly impact developer productivity by reducing development time and improving code quality..." + }, + "feasibility": { + "feasibility": "Our team has extensive experience in blockchain development and has successfully delivered similar projects..." + } + }, + "milestones": { + "milestones": { + "milestone_list": [ + { + "title": "Initial Setup and Planning", + "outputs": "Project infrastructure setup and detailed planning documents", + "acceptance_criteria": "- Development environment configured\n- Detailed project plan approved", + "evidence": "- GitHub repository setup\n- Documentation of infrastructure\n- Project planning documents", + "delivery_month": 1, + "cost": 30000, + "progress": "Not Started" + }, + { + "title": "Core Development", + "outputs": "Implementation of main features", + "acceptance_criteria": "- Core features implemented\n- Unit tests passing", + "evidence": "- Code repository\n- Test results\n- Technical documentation", + "delivery_month": 3, + "cost": 60000, + "progress": "Not Started" + }, + { + "title": "Final Release and Documentation", + "outputs": "Project completion, documentation, and Project Close-out Report and Video", + "acceptance_criteria": "- All features implemented and tested\n- Documentation complete\n- Close-out report and video delivered", + "evidence": "- Final release\n- Complete documentation\n- Close-out report and video", + "delivery_month": 6, + "cost": 60000, + "progress": "Not Started" + } + ] + } + }, + "pitch": { + "team": { + "who": "Our team consists of experienced blockchain developers with proven track records..." + }, + "budget": { + "costs": "Budget breakdown:\n- Development (70%): 105,000 ADA\n- Testing (15%): 22,500 ADA\n- Documentation (15%): 22,500 ADA" + }, + "value": { + "note": "This project provides excellent value for money by delivering essential developer tools..." + } + }, + "agreements": { + "mandatory": { + "fund_rules": true, + "terms_and_conditions": true, + "privacy_policy": true + } + } +} \ No newline at end of file diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/test/proposal/helpers/generic_proposal.json b/catalyst_voices/packages/internal/catalyst_voices_models/test/assets/generic_proposal.json similarity index 94% rename from catalyst_voices/packages/internal/catalyst_voices_models/test/proposal/helpers/generic_proposal.json rename to catalyst_voices/packages/internal/catalyst_voices_models/test/assets/generic_proposal.json index 17aafe4cd15..01fbbf20cfd 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_models/test/proposal/helpers/generic_proposal.json +++ b/catalyst_voices/packages/internal/catalyst_voices_models/test/assets/generic_proposal.json @@ -19,8 +19,8 @@ }, "translation": { "isTranslated": true, - "originalLanguage": "Spanish", - "translationNotes": "Translated using DeepL with manual review" + "originalLanguage": "German", + "originalDocumentLink": "https://example.com/proposal.pdf" }, "problem": { "statement": "Current challenge in the Cardano ecosystem...", @@ -57,8 +57,7 @@ "horizons": { "theme": { "grouped_tag": { - "group": "DeFi", - "tag": "Staking" + "group": "Governance" } } }, @@ -75,6 +74,7 @@ }, "milestones": { "milestones": { + "milestone_list": [], "declared": [ "# Initial Setup and Planning\n\nProject setup and infrastructure...", "# Core Development\n\nImplementation of main features...", diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/test/proposal/proposal_test.dart b/catalyst_voices/packages/internal/catalyst_voices_models/test/proposal/proposal_test.dart index d379a97b917..be8b39d44db 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_models/test/proposal/proposal_test.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_models/test/proposal/proposal_test.dart @@ -1,23 +1,28 @@ import 'dart:convert'; -import 'package:catalyst_voices_models/src/proposal_template/dtos/proposal_template_dto.dart'; +import 'package:catalyst_voices_models/src/proposal_template/dtos/proposal_schema_dto.dart'; import 'package:test/test.dart'; import 'helpers/read_json.dart'; Future main() async { - const filePath = - '/test/proposal/helpers/0ce8ab38-9258-4fbc-a62e-7faa6e58318f.schema.json'; - late Map template; + // const filePath = + // 'test/assets/0ce8ab38-9258-4fbc-a62e-7faa6e58318f.schema.json'; - setUpAll(() { - template = json.decode(readJson(filePath)) as Map; - }); + // late Map template; + + // setUpAll(() { + // template = json.decode(readJson(filePath)) as Map; + // }); + + // test('Test proposal template', () async { + // final proposalTemplate = ProposalSchemaDTO.fromJson(template); - test('Test proposal template', () async { - final proposalTemplate = ProposalTemplateDTO.fromJson(template); + // final json = proposalTemplate.toJson(); + // print(jsonEncode(json).toString()); + // }); - final json = proposalTemplate.toJson(); - print(jsonEncode(json).toString()); + test("sdad", () { + expect(true, true); }); } diff --git a/catalyst_voices/packages/internal/catalyst_voices_shared/lib/src/catalyst_voices_shared.dart b/catalyst_voices/packages/internal/catalyst_voices_shared/lib/src/catalyst_voices_shared.dart index a69ca464d61..9dd43565dbc 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_shared/lib/src/catalyst_voices_shared.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_shared/lib/src/catalyst_voices_shared.dart @@ -1,6 +1,7 @@ export 'common/build_config.dart'; export 'common/build_environment.dart'; export 'dependency/dependency_provider.dart'; +export 'extension/map_to_list_ext.dart'; export 'formatter/cryptocurrency_formatter.dart'; export 'formatter/wallet_address_formatter.dart'; export 'logging/logging_service.dart'; diff --git a/catalyst_voices/packages/internal/catalyst_voices_shared/lib/src/extension/list_to_map_ext.dart b/catalyst_voices/packages/internal/catalyst_voices_shared/lib/src/extension/list_to_map_ext.dart new file mode 100644 index 00000000000..e69de29bb2d diff --git a/catalyst_voices/packages/internal/catalyst_voices_shared/lib/src/extension/map_to_list_ext.dart b/catalyst_voices/packages/internal/catalyst_voices_shared/lib/src/extension/map_to_list_ext.dart new file mode 100644 index 00000000000..19390355db9 --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_shared/lib/src/extension/map_to_list_ext.dart @@ -0,0 +1,14 @@ +extension MapToListExt on Map { + List> convertMapToListWithIds() { + final list = >[]; + + for (final entry in entries) { + if (entry.key == r'$schema') continue; + final value = entry.value as Map; + value['id'] = entry.key; + list.add(value); + } + + return list; + } +} From 8eb4a81541ea933910fd6989a7cee63cf470864c Mon Sep 17 00:00:00 2001 From: Ryszard Schossler Date: Tue, 17 Dec 2024 10:57:39 +0100 Subject: [PATCH 05/18] feat: creating toModels --- .../dtos/proposal_definitions_dto.dart | 32 ++++- .../dtos/proposal_schema_dto.dart | 85 ++++++++++-- .../proposal_schema/proposal_definitions.dart | 126 ++++++++++++++++++ .../src/proposal_schema/proposal_schema.dart | 97 ++++++++++++++ .../test/proposal/proposal_test.dart | 28 ---- 5 files changed, 327 insertions(+), 41 deletions(-) rename catalyst_voices/packages/internal/catalyst_voices_models/lib/src/{proposal_template => proposal_schema}/dtos/proposal_definitions_dto.dart (92%) rename catalyst_voices/packages/internal/catalyst_voices_models/lib/src/{proposal_template => proposal_schema}/dtos/proposal_schema_dto.dart (70%) create mode 100644 catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/proposal_definitions.dart create mode 100644 catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/proposal_schema.dart delete mode 100644 catalyst_voices/packages/internal/catalyst_voices_models/test/proposal/proposal_test.dart diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/dtos/proposal_definitions_dto.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/dtos/proposal_definitions_dto.dart similarity index 92% rename from catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/dtos/proposal_definitions_dto.dart rename to catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/dtos/proposal_definitions_dto.dart index 2100db7e327..9b8e2d6113f 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/dtos/proposal_definitions_dto.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/dtos/proposal_definitions_dto.dart @@ -1,3 +1,4 @@ +import 'package:catalyst_voices_models/src/proposal_schema/proposal_definitions.dart'; import 'package:json_annotation/json_annotation.dart'; part 'proposal_definitions_dto.g.dart'; @@ -55,6 +56,14 @@ class ProposalDefinitionsDTO { _$ProposalDefinitionsDTOFromJson(json); Map toJson() => _$ProposalDefinitionsDTOToJson(this); + + ProposalDefinitions toModel() { + return ProposalDefinitions( + segmentDefinition: segment.toModel(), + sectionDefinition: section.toModel(), + singleLineTextEntryDefinition: singleLineTextEntry.toModel(), + ); + } } @JsonSerializable() @@ -74,6 +83,12 @@ class SegmentDTO { _$SegmentDTOFromJson(json); Map toJson() => _$SegmentDTOToJson(this); + + SegmentProposalDefinition toModel() => SegmentProposalDefinition( + type: DefinitionsObjectTypes.fromString(type), + note: note, + additionalProperties: additionalProperties, + ); } @JsonSerializable() @@ -93,6 +108,12 @@ class SectionDTO { _$SectionDTOFromJson(json); Map toJson() => _$SectionDTOToJson(this); + + SectionProposalDefinition toModel() => SectionProposalDefinition( + type: DefinitionsObjectTypes.fromString(type), + note: note, + additionalProperties: additionalProperties, + ); } @JsonSerializable() @@ -114,6 +135,14 @@ class SingleLineTextEntryDTO { _$SingleLineTextEntryDTOFromJson(json); Map toJson() => _$SingleLineTextEntryDTOToJson(this); + + SingleLineTextEntryDefinition toModel() => SingleLineTextEntryDefinition( + type: DefinitionsObjectTypes.fromString(type), + note: note, + contentMediaType: + DefinitionsContentMediaType.fromString(contentMediaType), + pattern: pattern, + ); } @JsonSerializable() @@ -276,7 +305,8 @@ class MultiLineTextEntryListMarkdownDTO { }); factory MultiLineTextEntryListMarkdownDTO.fromJson( - Map json) => + Map json, + ) => _$MultiLineTextEntryListMarkdownDTOFromJson(json); Map toJson() => diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/dtos/proposal_schema_dto.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/dtos/proposal_schema_dto.dart similarity index 70% rename from catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/dtos/proposal_schema_dto.dart rename to catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/dtos/proposal_schema_dto.dart index 2bd739f7787..2d08d2d3b22 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_template/dtos/proposal_schema_dto.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/dtos/proposal_schema_dto.dart @@ -1,4 +1,6 @@ -import 'package:catalyst_voices_models/src/proposal_template/dtos/proposal_definitions_dto.dart'; +import 'package:catalyst_voices_models/src/proposal_schema/dtos/proposal_definitions_dto.dart'; +import 'package:catalyst_voices_models/src/proposal_schema/proposal_definitions.dart'; +import 'package:catalyst_voices_models/src/proposal_schema/proposal_schema.dart'; import 'package:catalyst_voices_shared/catalyst_voices_shared.dart'; import 'package:equatable/equatable.dart'; import 'package:json_annotation/json_annotation.dart'; @@ -39,6 +41,19 @@ class ProposalSchemaDTO extends Equatable { Map toJson() => _$ProposalSchemaDTOToJson(this); + ProposalSchema toModel() { + return ProposalSchema( + schema: '', + title: '', + description: '', + definitions: definitions.toModel(), + type: DefinitionsObjectTypes.fromString(type), + additionalProperties: false, + properties: [], + order: [], + ); + } + @override List get props => [ schema, @@ -70,7 +85,7 @@ class ProposalSchemaSegmentDTO extends Equatable { final String title; final String description; @JsonKey(toJson: _toJsonProperties) - final List properties; + final List properties; final List required; @JsonKey(name: 'x-order') final List order; @@ -94,6 +109,20 @@ class ProposalSchemaSegmentDTO extends Equatable { Map toJson() => _$ProposalSchemaSegmentDTOToJson(this); + ProposalSchemaSegment toModel(ProposalDefinitions definitions) { + final properties = + this.properties.map((e) => e.toModel(definitions)).toList(); + return ProposalSchemaSegment( + ref: definitions.getDefinition(ref), + id: id, + title: title, + description: description, + properties: properties, + required: required, + order: order, + ); + } + @override List get props => [ ref, @@ -106,7 +135,7 @@ class ProposalSchemaSegmentDTO extends Equatable { ]; static Map _toJsonProperties( - List properties, + List properties, ) { final map = {}; for (final property in properties) { @@ -117,13 +146,13 @@ class ProposalSchemaSegmentDTO extends Equatable { } @JsonSerializable() -class ProposalSectionTopicDto extends Equatable { +class ProposalSectionDto extends Equatable { @JsonKey(name: r'$ref') final String ref; final String id; final String title; final String description; - final List properties; + final List properties; final List required; @JsonKey(name: 'x-order') final List order; @@ -134,7 +163,7 @@ class ProposalSectionTopicDto extends Equatable { @JsonKey(name: 'open_source') final Map openSource; // Return to this - const ProposalSectionTopicDto({ + const ProposalSectionDto({ required this.ref, required this.id, this.title = '', @@ -148,14 +177,28 @@ class ProposalSectionTopicDto extends Equatable { this.openSource = const {}, }); - factory ProposalSectionTopicDto.fromJson(Map json) { + factory ProposalSectionDto.fromJson(Map json) { final segmentsMap = json['properties'] as Map; json['properties'] = segmentsMap.convertMapToListWithIds(); - return _$ProposalSectionTopicDtoFromJson(json); + return _$ProposalSectionDtoFromJson(json); } - Map toJson() => _$ProposalSectionTopicDtoToJson(this); + Map toJson() => _$ProposalSectionDtoToJson(this); + + ProposalSchemaSection toModel(ProposalDefinitions definitions) { + final properties = + this.properties.map((e) => e.toModel(definitions)).toList(); + return ProposalSchemaSection( + ref: definitions.getDefinition(ref), + id: id, + title: title, + description: description, + properties: properties, + required: required, + order: order, + ); + } @override List get props => [ @@ -174,13 +217,13 @@ class ProposalSectionTopicDto extends Equatable { @JsonSerializable() class ProposalSchemaElementDTO extends Equatable { - @JsonKey(name: r'$ref', includeToJson: false) + @JsonKey(name: r'$ref') final String ref; final String id; final String title; final String description; - final String? minLength; - final String? maxLength; + final int? minLength; + final int? maxLength; @JsonKey(name: 'default') final String defaultValue; @JsonKey(name: 'x-guidance') @@ -217,6 +260,24 @@ class ProposalSchemaElementDTO extends Equatable { Map toJson() => _$ProposalSchemaElementDTOToJson(this); + ProposalSchemaElement toModel(ProposalDefinitions definitions) => + ProposalSchemaElement( + ref: definitions.getDefinition(ref), + id: id, + title: title, + description: description, + minLength: minLength, + maxLength: maxLength, + defaultValue: defaultValue, + guidance: guidance, + enumValues: enumValues, + maxItems: maxItems, + minItems: minItems, + minimum: minimum, + maximum: maximum, + examples: examples, + ); + @override List get props => [ ref, diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/proposal_definitions.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/proposal_definitions.dart new file mode 100644 index 00000000000..de4c838dad4 --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/proposal_definitions.dart @@ -0,0 +1,126 @@ +enum DefinitionsObjectTypes { + string, + object, + integer, + array, + unknown; + + const DefinitionsObjectTypes(); + + static DefinitionsObjectTypes fromString(String value) { + return DefinitionsObjectTypes.values.firstWhere( + (type) => type.name == value, + orElse: () => DefinitionsObjectTypes.unknown, + ); + } +} + +enum DefinitionsContentMediaType { + textPlain('text/plain'), + markdown('text/markdown'), + unknown('unknown'); + + final String value; + + const DefinitionsContentMediaType(this.value); + + static DefinitionsContentMediaType fromString(String value) { + return DefinitionsContentMediaType.values.firstWhere( + (type) => type.name == value, + orElse: () => DefinitionsContentMediaType.unknown, + ); + } +} + +enum DefinitionsFormats { + singleLineTextEntry, + multiLineTextEntry, + multiLineTextEntryMarkdown, + dropDownSingleSelect, + multiSelect, + singleLineHttpsURLEntry, + nestedQuestions, + nestedQuestionsList, + singleGroupedTagSelector, + tagGroup, + tagSelection, + tokenValueCardanoADA, + durationInMonths, + yesNoChoice, + agreementConfirmation, + spdxLicenseOrURL, +} + +abstract class BaseProposalDefinition { + final DefinitionsObjectTypes type; + final String note; + + const BaseProposalDefinition({ + required this.type, + required this.note, + }); +} + +class ProposalDefinitions { + final SegmentProposalDefinition segmentDefinition; + final SectionProposalDefinition sectionDefinition; + final SingleLineTextEntryDefinition singleLineTextEntryDefinition; + + const ProposalDefinitions({ + required this.segmentDefinition, + required this.sectionDefinition, + required this.singleLineTextEntryDefinition, + }); + + BaseProposalDefinition getDefinition(String refPath) { + final ref = refPath.split('/').last; + return switch (ref) { + 'segment' => segmentDefinition, + 'section' => sectionDefinition, + 'singleLineTextEntry' => singleLineTextEntryDefinition, + _ => UnknownProposalDefinition( + type: DefinitionsObjectTypes.fromString(ref.split('/').last), + note: 'Unknown definition', + ), + }; + } +} + +class SegmentProposalDefinition extends BaseProposalDefinition { + final bool additionalProperties; + + const SegmentProposalDefinition({ + required super.type, + required super.note, + required this.additionalProperties, + }); +} + +class SectionProposalDefinition extends BaseProposalDefinition { + final bool additionalProperties; + + const SectionProposalDefinition({ + required super.type, + required super.note, + required this.additionalProperties, + }); +} + +class SingleLineTextEntryDefinition extends BaseProposalDefinition { + final DefinitionsContentMediaType contentMediaType; + final String pattern; + + const SingleLineTextEntryDefinition({ + required super.type, + required super.note, + required this.contentMediaType, + required this.pattern, + }); +} + +class UnknownProposalDefinition extends BaseProposalDefinition { + const UnknownProposalDefinition({ + required super.type, + required super.note, + }); +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/proposal_schema.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/proposal_schema.dart new file mode 100644 index 00000000000..063004e2324 --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/proposal_schema.dart @@ -0,0 +1,97 @@ +import 'package:catalyst_voices_models/src/proposal_schema/proposal_definitions.dart'; + +class ProposalSchema { + final String schema; + final String title; + final String description; + final ProposalDefinitions definitions; + final DefinitionsObjectTypes type; + final bool additionalProperties; + final List properties; + final List order; + + const ProposalSchema({ + required this.schema, + required this.title, + required this.description, + required this.definitions, + required this.type, + required this.additionalProperties, + required this.properties, + required this.order, + }); +} + +class ProposalSchemaSegment { + final BaseProposalDefinition ref; + final String id; + final String title; + final String description; + final List properties; + final List required; + final List order; + + const ProposalSchemaSegment({ + required this.ref, + required this.id, + required this.title, + required this.description, + required this.properties, + required this.required, + required this.order, + }); +} + +class ProposalSchemaSection { + final BaseProposalDefinition ref; + final String id; + final String title; + final String description; + final List properties; + final List required; + final List order; + + const ProposalSchemaSection({ + required this.ref, + required this.id, + required this.title, + required this.description, + required this.properties, + required this.required, + required this.order, + }); +} + +class ProposalSchemaElement { + final BaseProposalDefinition ref; + final String id; + final String title; + final String description; + final int? minLength; + final int? maxLength; + final String? defaultValue; + final String guidance; + final List? enumValues; + final int? maxItems; + final int? minItems; + final int? minimum; + final int? maximum; + final List examples; + + const ProposalSchemaElement({ + required this.ref, + required this.id, + required this.title, + required this.description, + required this.minLength, + required this.maxLength, + required this.defaultValue, + required this.guidance, + required this.enumValues, + required this.maxItems, + required this.minItems, + required this.minimum, + required this.maximum, + required this.examples, + }); +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/test/proposal/proposal_test.dart b/catalyst_voices/packages/internal/catalyst_voices_models/test/proposal/proposal_test.dart deleted file mode 100644 index be8b39d44db..00000000000 --- a/catalyst_voices/packages/internal/catalyst_voices_models/test/proposal/proposal_test.dart +++ /dev/null @@ -1,28 +0,0 @@ -import 'dart:convert'; - -import 'package:catalyst_voices_models/src/proposal_template/dtos/proposal_schema_dto.dart'; -import 'package:test/test.dart'; - -import 'helpers/read_json.dart'; - -Future main() async { - // const filePath = - // 'test/assets/0ce8ab38-9258-4fbc-a62e-7faa6e58318f.schema.json'; - - // late Map template; - - // setUpAll(() { - // template = json.decode(readJson(filePath)) as Map; - // }); - - // test('Test proposal template', () async { - // final proposalTemplate = ProposalSchemaDTO.fromJson(template); - - // final json = proposalTemplate.toJson(); - // print(jsonEncode(json).toString()); - // }); - - test("sdad", () { - expect(true, true); - }); -} From 9d916182aeec086129e866c4478d05a0016844cc Mon Sep 17 00:00:00 2001 From: Ryszard Schossler Date: Wed, 18 Dec 2024 11:04:29 +0100 Subject: [PATCH 06/18] feat: sort section/elements by xorder --- .../lib/src/catalyst_voices_models.dart | 2 + .../lib/src/proposal_schema/definitions.dart | 154 ++++++++ .../dtos/proposal_schema_dto.dart | 298 --------------- .../src/proposal_schema/proposal_builder.dart | 120 ++++++ .../proposal_schema/proposal_definitions.dart | 126 ------ .../src/proposal_schema/proposal_schema.dart | 97 ----- .../lib/src/proposal_schema/schema.dart | 93 +++++ ...38-9258-4fbc-a62e-7faa6e58318f.schema.json | 36 +- .../test/assets/generic_proposal.json | 70 +++- .../test/assets/proposal_builder_output.json | 1 + .../lib/src/dto/definitions_dto.dart} | 318 ++++++++-------- .../lib/src/dto/schema_dto.dart | 359 ++++++++++++++++++ .../catalyst_voices_repositories/pubspec.yaml | 1 + .../lib/src/extension/list_to_map_ext.dart | 0 14 files changed, 959 insertions(+), 716 deletions(-) create mode 100644 catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/definitions.dart delete mode 100644 catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/dtos/proposal_schema_dto.dart create mode 100644 catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/proposal_builder.dart delete mode 100644 catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/proposal_definitions.dart delete mode 100644 catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/proposal_schema.dart create mode 100644 catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/schema.dart create mode 100644 catalyst_voices/packages/internal/catalyst_voices_models/test/assets/proposal_builder_output.json rename catalyst_voices/packages/internal/{catalyst_voices_models/lib/src/proposal_schema/dtos/proposal_definitions_dto.dart => catalyst_voices_repositories/lib/src/dto/definitions_dto.dart} (52%) create mode 100644 catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/schema_dto.dart delete mode 100644 catalyst_voices/packages/internal/catalyst_voices_shared/lib/src/extension/list_to_map_ext.dart diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/catalyst_voices_models.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/catalyst_voices_models.dart index f17f3498d2a..c1af5e088cd 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/catalyst_voices_models.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/catalyst_voices_models.dart @@ -15,6 +15,8 @@ export 'proposal/guidance.dart'; export 'proposal/proposal.dart'; export 'proposal/proposal_section.dart'; export 'proposal/proposal_template.dart'; +export 'proposal_schema/definitions.dart'; +export 'proposal_schema/schema.dart'; export 'registration/registration.dart'; export 'seed_phrase.dart'; export 'space.dart'; diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/definitions.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/definitions.dart new file mode 100644 index 00000000000..7880d125947 --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/definitions.dart @@ -0,0 +1,154 @@ +enum DefinitionsObjectType { + string, + object, + integer, + boolean, + array, + unknown; + + const DefinitionsObjectType(); + + static DefinitionsObjectType fromString(String value) { + return DefinitionsObjectType.values.asNameMap()[value] ?? + DefinitionsObjectType.unknown; + } + + dynamic get getDefaultValue => switch (this) { + string => '', + integer => 0, + boolean => true, + array => [], + object => {}, + unknown => 'unknown', + }; +} + +enum DefinitionsContentMediaType { + textPlain('text/plain'), + markdown('text/markdown'), + unknown('unknown'); + + final String value; + + const DefinitionsContentMediaType(this.value); + + static DefinitionsContentMediaType fromString(String value) { + return DefinitionsContentMediaType.values.asNameMap()[value] ?? + DefinitionsContentMediaType.unknown; + } +} + +enum DefinitionsFormat { + path, + uri, + dropDownSingleSelect, + multiSelect, + singleLineTextEntryList, + singleLineTextEntryListMarkdown, + singleLineHttpsURLEntryList, + nestedQuestionsList, + nestedQuestions, + singleGroupedTagSelector, + tagGroup, + tagSelection, + tokenValueCardanoADA, + datetimeDurationMonths, + yesNoChoice, + agreementConfirmation, + spdxLicenseOrURL, + unknown; + + const DefinitionsFormat(); + + static DefinitionsFormat fromString(String value) { + return DefinitionsFormat.values.firstWhere( + (type) => type.name == value, + orElse: () => DefinitionsFormat.unknown, + ); + } +} + +enum DefinitionsType { + section, + segment, + singleLineTextEntry, + // singleLineHttpsURLEntry, + + // multiLineTextEntry; + durationInMonths; + + const DefinitionsType(); + + static DefinitionsType fromString(String value) { + return DefinitionsType.values.byName(value); + } + + Object get definitionType => switch (this) { + section => SectionDefinition, + segment => SegmentDefinition, + singleLineTextEntry => SingleLineTextEntryDefinition, + durationInMonths => DurationInMonthsDefinition, + }; +} + +abstract class BaseDefinition { + final DefinitionsObjectType type; + final String note; + + const BaseDefinition({ + required this.type, + required this.note, + }); +} + +extension BaseDefinitionListExt on List { + BaseDefinition getDefinition(String refPath) { + final ref = refPath.split('/').last; + final enum2 = DefinitionsType.fromString(ref); + final obj = enum2.definitionType; + + return firstWhere((e) => e.runtimeType == obj); + } +} + +class SegmentDefinition extends BaseDefinition { + final bool additionalProperties; + + const SegmentDefinition({ + required super.type, + required super.note, + required this.additionalProperties, + }); +} + +class SectionDefinition extends BaseDefinition { + final bool additionalProperties; + + const SectionDefinition({ + required super.type, + required super.note, + required this.additionalProperties, + }); +} + +class SingleLineTextEntryDefinition extends BaseDefinition { + final DefinitionsContentMediaType contentMediaType; + final String pattern; + + const SingleLineTextEntryDefinition({ + required super.type, + required super.note, + required this.contentMediaType, + required this.pattern, + }); +} + +class DurationInMonthsDefinition extends BaseDefinition { + final DefinitionsFormat format; + + const DurationInMonthsDefinition({ + required super.type, + required super.note, + required this.format, + }); +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/dtos/proposal_schema_dto.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/dtos/proposal_schema_dto.dart deleted file mode 100644 index 2d08d2d3b22..00000000000 --- a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/dtos/proposal_schema_dto.dart +++ /dev/null @@ -1,298 +0,0 @@ -import 'package:catalyst_voices_models/src/proposal_schema/dtos/proposal_definitions_dto.dart'; -import 'package:catalyst_voices_models/src/proposal_schema/proposal_definitions.dart'; -import 'package:catalyst_voices_models/src/proposal_schema/proposal_schema.dart'; -import 'package:catalyst_voices_shared/catalyst_voices_shared.dart'; -import 'package:equatable/equatable.dart'; -import 'package:json_annotation/json_annotation.dart'; - -part 'proposal_schema_dto.g.dart'; - -@JsonSerializable() -class ProposalSchemaDTO extends Equatable { - @JsonKey(name: r'$schema') - final String schema; - final String title; - final String description; - final ProposalDefinitionsDTO definitions; - final String type; - final bool additionalProperties; - @JsonKey(toJson: _toJsonProperties) - final List properties; - @JsonKey(name: 'x-order') - final List order; - - const ProposalSchemaDTO({ - required this.schema, - required this.title, - required this.description, - required this.definitions, - this.type = 'object', - this.additionalProperties = false, - required this.properties, - required this.order, - }); - - factory ProposalSchemaDTO.fromJson(Map json) { - final segmentsMap = json['properties'] as Map; - json['properties'] = segmentsMap.convertMapToListWithIds(); - - return _$ProposalSchemaDTOFromJson(json); - } - - Map toJson() => _$ProposalSchemaDTOToJson(this); - - ProposalSchema toModel() { - return ProposalSchema( - schema: '', - title: '', - description: '', - definitions: definitions.toModel(), - type: DefinitionsObjectTypes.fromString(type), - additionalProperties: false, - properties: [], - order: [], - ); - } - - @override - List get props => [ - schema, - title, - description, - definitions, - type, - additionalProperties, - properties, - order, - ]; - - static Map _toJsonProperties( - List properties, - ) { - final map = {}; - for (final property in properties) { - map[property.id] = property.toJson(); - } - return map; - } -} - -@JsonSerializable() -class ProposalSchemaSegmentDTO extends Equatable { - @JsonKey(name: r'$ref') - final String ref; - final String id; - final String title; - final String description; - @JsonKey(toJson: _toJsonProperties) - final List properties; - final List required; - @JsonKey(name: 'x-order') - final List order; - - const ProposalSchemaSegmentDTO({ - required this.ref, - required this.id, - this.title = '', - this.description = '', - required this.properties, - this.required = const [], - this.order = const [], - }); - - factory ProposalSchemaSegmentDTO.fromJson(Map json) { - final segmentsMap = json['properties'] as Map; - json['properties'] = segmentsMap.convertMapToListWithIds(); - - return _$ProposalSchemaSegmentDTOFromJson(json); - } - - Map toJson() => _$ProposalSchemaSegmentDTOToJson(this); - - ProposalSchemaSegment toModel(ProposalDefinitions definitions) { - final properties = - this.properties.map((e) => e.toModel(definitions)).toList(); - return ProposalSchemaSegment( - ref: definitions.getDefinition(ref), - id: id, - title: title, - description: description, - properties: properties, - required: required, - order: order, - ); - } - - @override - List get props => [ - ref, - id, - title, - description, - properties, - required, - order, - ]; - - static Map _toJsonProperties( - List properties, - ) { - final map = {}; - for (final property in properties) { - map[property.id] = property.toJson(); - } - return map; - } -} - -@JsonSerializable() -class ProposalSectionDto extends Equatable { - @JsonKey(name: r'$ref') - final String ref; - final String id; - final String title; - final String description; - final List properties; - final List required; - @JsonKey(name: 'x-order') - final List order; - final Map dependencies; // Return to this - @JsonKey(name: 'if') - final Map ifs; - final Map then; // Return to this - @JsonKey(name: 'open_source') - final Map openSource; // Return to this - - const ProposalSectionDto({ - required this.ref, - required this.id, - this.title = '', - this.description = '', - required this.properties, - this.required = const [], - this.order = const [], - this.dependencies = const {}, - this.ifs = const {}, - this.then = const {}, - this.openSource = const {}, - }); - - factory ProposalSectionDto.fromJson(Map json) { - final segmentsMap = json['properties'] as Map; - json['properties'] = segmentsMap.convertMapToListWithIds(); - - return _$ProposalSectionDtoFromJson(json); - } - - Map toJson() => _$ProposalSectionDtoToJson(this); - - ProposalSchemaSection toModel(ProposalDefinitions definitions) { - final properties = - this.properties.map((e) => e.toModel(definitions)).toList(); - return ProposalSchemaSection( - ref: definitions.getDefinition(ref), - id: id, - title: title, - description: description, - properties: properties, - required: required, - order: order, - ); - } - - @override - List get props => [ - ref, - id, - title, - description, - properties, - required, - order, - dependencies, - ifs, - then, - ]; -} - -@JsonSerializable() -class ProposalSchemaElementDTO extends Equatable { - @JsonKey(name: r'$ref') - final String ref; - final String id; - final String title; - final String description; - final int? minLength; - final int? maxLength; - @JsonKey(name: 'default') - final String defaultValue; - @JsonKey(name: 'x-guidance') - final String guidance; - @JsonKey(name: 'enum') - final List enumValues; - final int? maxItems; - final int? minItems; - final int? minimum; - final int? maximum; - final List examples; - final Map items; // TODO(ryszard-shossler): return to this - - const ProposalSchemaElementDTO({ - required this.ref, - required this.id, - required this.title, - required this.description, - required this.minLength, - required this.maxLength, - this.defaultValue = '', - required this.guidance, - this.enumValues = const [], - required this.maxItems, - required this.minItems, - required this.minimum, - required this.maximum, - this.examples = const [], - this.items = const {}, - }); - - factory ProposalSchemaElementDTO.fromJson(Map json) => - _$ProposalSchemaElementDTOFromJson(json); - - Map toJson() => _$ProposalSchemaElementDTOToJson(this); - - ProposalSchemaElement toModel(ProposalDefinitions definitions) => - ProposalSchemaElement( - ref: definitions.getDefinition(ref), - id: id, - title: title, - description: description, - minLength: minLength, - maxLength: maxLength, - defaultValue: defaultValue, - guidance: guidance, - enumValues: enumValues, - maxItems: maxItems, - minItems: minItems, - minimum: minimum, - maximum: maximum, - examples: examples, - ); - - @override - List get props => [ - ref, - id, - title, - description, - minLength, - maxLength, - defaultValue, - guidance, - enumValues, - maxItems, - minItems, - minimum, - maximum, - examples, - ]; -} diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/proposal_builder.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/proposal_builder.dart new file mode 100644 index 00000000000..e9e2ea3db62 --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/proposal_builder.dart @@ -0,0 +1,120 @@ +import 'package:catalyst_voices_models/src/proposal_schema/schema.dart'; +import 'package:json_annotation/json_annotation.dart'; + +part 'proposal_builder.g.dart'; + +@JsonSerializable() +class ProposalBuilder { + final String schema; + final List segments; + + const ProposalBuilder({ + required this.schema, + required this.segments, + }); + + factory ProposalBuilder.build(Schema proposalSchema) { + return ProposalBuilder( + schema: proposalSchema.propertiesSchema, + segments: proposalSchema.segments + .map( + (element) => ProposalBuilderSegment( + id: element.id, + sections: element.sections + .map( + (element) => ProposalBuilderSection( + id: element.id, + elements: element.elements + .map( + (e) => ProposalBuilderElement( + id: e.id, + value: e.ref.type.getDefaultValue, + ), + ) + .toList(), + ), + ) + .toList(), + ), + ) + .toList(), + ); + } + + factory ProposalBuilder.fromJson(Map json) => + _$ProposalBuilderFromJson(json); + + Map toJson() { + final sections = {}..addAll({r'$schema': schema}); + for (final section in segments) { + sections.addAll(section.toJson()); + } + return sections; + } +} + +@JsonSerializable() +class ProposalBuilderSegment { + final String id; + final List sections; + + const ProposalBuilderSegment({ + required this.id, + required this.sections, + }); + + factory ProposalBuilderSegment.fromJson(Map json) => + _$ProposalBuilderSegmentFromJson(json); + + Map toJson() { + final sections = {}; + for (final section in this.sections) { + sections.addAll(section.toJson()); + } + return { + id: sections, + }; + } +} + +@JsonSerializable() +class ProposalBuilderSection { + final String id; + final List elements; + + const ProposalBuilderSection({ + required this.id, + required this.elements, + }); + + factory ProposalBuilderSection.fromJson(Map json) => + _$ProposalBuilderSectionFromJson(json); + + Map toJson() { + final map = {}; + for (final element in elements) { + map.addAll(element.toJson()); + } + return { + id: map, + }; + } +} + +@JsonSerializable() +class ProposalBuilderElement { + final String id; + final dynamic value; + + const ProposalBuilderElement({ + required this.id, + required this.value, + }); + + factory ProposalBuilderElement.fromJson(Map json) => + _$ProposalBuilderElementFromJson(json); + + Map toJson() => { + id: value, + }; +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/proposal_definitions.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/proposal_definitions.dart deleted file mode 100644 index de4c838dad4..00000000000 --- a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/proposal_definitions.dart +++ /dev/null @@ -1,126 +0,0 @@ -enum DefinitionsObjectTypes { - string, - object, - integer, - array, - unknown; - - const DefinitionsObjectTypes(); - - static DefinitionsObjectTypes fromString(String value) { - return DefinitionsObjectTypes.values.firstWhere( - (type) => type.name == value, - orElse: () => DefinitionsObjectTypes.unknown, - ); - } -} - -enum DefinitionsContentMediaType { - textPlain('text/plain'), - markdown('text/markdown'), - unknown('unknown'); - - final String value; - - const DefinitionsContentMediaType(this.value); - - static DefinitionsContentMediaType fromString(String value) { - return DefinitionsContentMediaType.values.firstWhere( - (type) => type.name == value, - orElse: () => DefinitionsContentMediaType.unknown, - ); - } -} - -enum DefinitionsFormats { - singleLineTextEntry, - multiLineTextEntry, - multiLineTextEntryMarkdown, - dropDownSingleSelect, - multiSelect, - singleLineHttpsURLEntry, - nestedQuestions, - nestedQuestionsList, - singleGroupedTagSelector, - tagGroup, - tagSelection, - tokenValueCardanoADA, - durationInMonths, - yesNoChoice, - agreementConfirmation, - spdxLicenseOrURL, -} - -abstract class BaseProposalDefinition { - final DefinitionsObjectTypes type; - final String note; - - const BaseProposalDefinition({ - required this.type, - required this.note, - }); -} - -class ProposalDefinitions { - final SegmentProposalDefinition segmentDefinition; - final SectionProposalDefinition sectionDefinition; - final SingleLineTextEntryDefinition singleLineTextEntryDefinition; - - const ProposalDefinitions({ - required this.segmentDefinition, - required this.sectionDefinition, - required this.singleLineTextEntryDefinition, - }); - - BaseProposalDefinition getDefinition(String refPath) { - final ref = refPath.split('/').last; - return switch (ref) { - 'segment' => segmentDefinition, - 'section' => sectionDefinition, - 'singleLineTextEntry' => singleLineTextEntryDefinition, - _ => UnknownProposalDefinition( - type: DefinitionsObjectTypes.fromString(ref.split('/').last), - note: 'Unknown definition', - ), - }; - } -} - -class SegmentProposalDefinition extends BaseProposalDefinition { - final bool additionalProperties; - - const SegmentProposalDefinition({ - required super.type, - required super.note, - required this.additionalProperties, - }); -} - -class SectionProposalDefinition extends BaseProposalDefinition { - final bool additionalProperties; - - const SectionProposalDefinition({ - required super.type, - required super.note, - required this.additionalProperties, - }); -} - -class SingleLineTextEntryDefinition extends BaseProposalDefinition { - final DefinitionsContentMediaType contentMediaType; - final String pattern; - - const SingleLineTextEntryDefinition({ - required super.type, - required super.note, - required this.contentMediaType, - required this.pattern, - }); -} - -class UnknownProposalDefinition extends BaseProposalDefinition { - const UnknownProposalDefinition({ - required super.type, - required super.note, - }); -} diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/proposal_schema.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/proposal_schema.dart deleted file mode 100644 index 063004e2324..00000000000 --- a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/proposal_schema.dart +++ /dev/null @@ -1,97 +0,0 @@ -import 'package:catalyst_voices_models/src/proposal_schema/proposal_definitions.dart'; - -class ProposalSchema { - final String schema; - final String title; - final String description; - final ProposalDefinitions definitions; - final DefinitionsObjectTypes type; - final bool additionalProperties; - final List properties; - final List order; - - const ProposalSchema({ - required this.schema, - required this.title, - required this.description, - required this.definitions, - required this.type, - required this.additionalProperties, - required this.properties, - required this.order, - }); -} - -class ProposalSchemaSegment { - final BaseProposalDefinition ref; - final String id; - final String title; - final String description; - final List properties; - final List required; - final List order; - - const ProposalSchemaSegment({ - required this.ref, - required this.id, - required this.title, - required this.description, - required this.properties, - required this.required, - required this.order, - }); -} - -class ProposalSchemaSection { - final BaseProposalDefinition ref; - final String id; - final String title; - final String description; - final List properties; - final List required; - final List order; - - const ProposalSchemaSection({ - required this.ref, - required this.id, - required this.title, - required this.description, - required this.properties, - required this.required, - required this.order, - }); -} - -class ProposalSchemaElement { - final BaseProposalDefinition ref; - final String id; - final String title; - final String description; - final int? minLength; - final int? maxLength; - final String? defaultValue; - final String guidance; - final List? enumValues; - final int? maxItems; - final int? minItems; - final int? minimum; - final int? maximum; - final List examples; - - const ProposalSchemaElement({ - required this.ref, - required this.id, - required this.title, - required this.description, - required this.minLength, - required this.maxLength, - required this.defaultValue, - required this.guidance, - required this.enumValues, - required this.maxItems, - required this.minItems, - required this.minimum, - required this.maximum, - required this.examples, - }); -} diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/schema.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/schema.dart new file mode 100644 index 00000000000..6ad49deccc5 --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/schema.dart @@ -0,0 +1,93 @@ +import 'package:catalyst_voices_models/src/proposal_schema/definitions.dart'; + +class Schema { + final String schema; + final String title; + final String description; + final DefinitionsObjectType type; + final bool additionalProperties; + final List segments; + final List order; + final String propertiesSchema; + + const Schema({ + required this.schema, + required this.title, + required this.description, + required this.type, + required this.additionalProperties, + required this.segments, + required this.order, + required this.propertiesSchema, + }); +} + +class SchemaSegment { + final BaseDefinition ref; + final String id; + final String title; + final String description; + final List sections; + + const SchemaSegment({ + required this.ref, + required this.id, + required this.title, + required this.description, + required this.sections, + }); +} + +class SchemaSection { + final BaseDefinition ref; + final String id; + final String title; + final String description; + final List elements; + final bool isRequired; + + const SchemaSection({ + required this.ref, + required this.id, + required this.title, + required this.description, + required this.elements, + required this.isRequired, + }); +} + +class SchemaElement { + final BaseDefinition ref; + final String id; + final String title; + final String description; + final int? minLength; + final int? maxLength; + final String? defaultValue; + final String guidance; + final List enumValues; + final int? maxItems; + final int? minItems; + final int? minimum; + final int? maximum; + // Sample JSON values associated with a particular schema, + // for the purpose of illustrating usage. + final List examples; + + const SchemaElement({ + required this.ref, + required this.id, + required this.title, + required this.description, + this.minLength, + this.maxLength, + required this.defaultValue, + required this.guidance, + this.enumValues = const [], + this.maxItems, + this.minItems, + this.minimum, + this.maximum, + this.examples = const [], + }); +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/test/assets/0ce8ab38-9258-4fbc-a62e-7faa6e58318f.schema.json b/catalyst_voices/packages/internal/catalyst_voices_models/test/assets/0ce8ab38-9258-4fbc-a62e-7faa6e58318f.schema.json index 93e6bef9b69..d92a2281bc1 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_models/test/assets/0ce8ab38-9258-4fbc-a62e-7faa6e58318f.schema.json +++ b/catalyst_voices/packages/internal/catalyst_voices_models/test/assets/0ce8ab38-9258-4fbc-a62e-7faa6e58318f.schema.json @@ -186,24 +186,6 @@ "title": "proposal setup", "description": "Proposal title", "properties": { - "title": { - "$ref": "#/definitions/section", - "title": "proposal setup", - "description": "Proposal title", - "properties": { - "title": { - "$ref": "#/definitions/singleLineTextEntry", - "title": "Proposal Title", - "description": "

Proposal title

Please note we suggest you use no more than 60 characters for your proposal title so that it can be easily viewed in the voting app.

", - "minLength": 1, - "maxLength": 60, - "x-guidance": "

The title should clearly express what the proposal is about. Voters can see the title in the voting app, even without opening the proposal, so a clear, unambiguous, and concise title is very important.

" - } - }, - "required": [ - "title" - ] - }, "proposer": { "$ref": "#/definitions/section", "properties": { @@ -245,6 +227,24 @@ "type", "coproposers" ] + }, + "title": { + "$ref": "#/definitions/section", + "title": "proposal setup", + "description": "Proposal title", + "properties": { + "title": { + "$ref": "#/definitions/singleLineTextEntry", + "title": "Proposal Title", + "description": "

Proposal title

Please note we suggest you use no more than 60 characters for your proposal title so that it can be easily viewed in the voting app.

", + "minLength": 1, + "maxLength": 60, + "x-guidance": "

The title should clearly express what the proposal is about. Voters can see the title in the voting app, even without opening the proposal, so a clear, unambiguous, and concise title is very important.

" + } + }, + "required": [ + "title" + ] } }, "required": [ diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/test/assets/generic_proposal.json b/catalyst_voices/packages/internal/catalyst_voices_models/test/assets/generic_proposal.json index 01fbbf20cfd..e0100f00cc8 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_models/test/assets/generic_proposal.json +++ b/catalyst_voices/packages/internal/catalyst_voices_models/test/assets/generic_proposal.json @@ -5,9 +5,12 @@ "title": "Example Catalyst Proposal" }, "proposer": { - "applicant": "John Doe", + "applicant": "John Smith", "type": "Individual", - "coproposers": [] + "coproposers": [ + "Jane Doe", + "Bob Wilson" + ] } }, "summary": { @@ -20,7 +23,7 @@ "translation": { "isTranslated": true, "originalLanguage": "German", - "originalDocumentLink": "https://example.com/proposal.pdf" + "originalDocumentLink": "https://example.com/original-doc" }, "problem": { "statement": "Current challenge in the Cardano ecosystem...", @@ -42,11 +45,19 @@ "mainRepository": "https://github.com/example/project", "documentation": "https://docs.example.com", "other": [ - "https://github.com/example/project" + "https://example.com/whitepaper", + "https://example.com/roadmap" ] }, "dependencies": { - "details": [] + "details": [ + { + "name": "External API Service", + "type": "Technical", + "description": "Integration with third-party API service", + "mitigationPlan": "Build fallback mechanisms and maintain alternative providers" + } + ] }, "open_source": { "source_code": "MIT", @@ -57,41 +68,64 @@ "horizons": { "theme": { "grouped_tag": { - "group": "Governance" + "group": "DeFi", + "tag": "Staking" } } }, "details": { "solution": { - "solution": "Our solution provides a comprehensive toolkit..." + "solution": "Our solution involves developing a comprehensive toolkit that will enhance the Cardano developer experience..." }, "impact": { - "impact": "The project will significantly impact developer productivity..." + "impact": "The project will significantly impact developer productivity by reducing development time and improving code quality..." }, "feasibility": { - "feasibility": "Our team has extensive experience in blockchain development..." + "feasibility": "Our team has extensive experience in blockchain development and has successfully delivered similar projects..." } }, "milestones": { "milestones": { - "milestone_list": [], - "declared": [ - "# Initial Setup and Planning\n\nProject setup and infrastructure...", - "# Core Development\n\nImplementation of main features...", - "# Testing and Documentation\n\nComprehensive testing and documentation...", - "# Final Release\n\nProject completion and deployment with Project Close-out Report and Video..." + "milestone_list": [ + { + "title": "Initial Setup and Planning", + "outputs": "Project infrastructure setup and detailed planning documents", + "acceptance_criteria": "- Development environment configured\n- Detailed project plan approved", + "evidence": "- GitHub repository setup\n- Documentation of infrastructure\n- Project planning documents", + "delivery_month": 1, + "cost": 30000, + "progress": "Not Started" + }, + { + "title": "Core Development", + "outputs": "Implementation of main features", + "acceptance_criteria": "- Core features implemented\n- Unit tests passing", + "evidence": "- Code repository\n- Test results\n- Technical documentation", + "delivery_month": 3, + "cost": 60000, + "progress": "Not Started" + }, + { + "title": "Final Release and Documentation", + "outputs": "Project completion, documentation, and Project Close-out Report and Video", + "acceptance_criteria": "- All features implemented and tested\n- Documentation complete\n- Close-out report and video delivered", + "evidence": "- Final release\n- Complete documentation\n- Close-out report and video", + "delivery_month": 6, + "cost": 60000, + "progress": "Not Started" + } ] } }, "pitch": { "team": { - "who": "Our team consists of experienced blockchain developers..." + "who": "Our team consists of experienced blockchain developers with proven track records..." }, "budget": { - "costs": "Budget breakdown:\n- Development: 70%\n- Testing: 15%\n- Documentation: 15%" + "costs": "Budget breakdown:\n- Development (70%): 105,000 ADA\n- Testing (15%): 22,500 ADA\n- Documentation (15%): 22,500 ADA" }, "value": { - "note": "This project provides excellent value for money..." + "note": "This project provides excellent value for money by delivering essential developer tools..." } }, "agreements": { diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/test/assets/proposal_builder_output.json b/catalyst_voices/packages/internal/catalyst_voices_models/test/assets/proposal_builder_output.json new file mode 100644 index 00000000000..72450e9c461 --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_models/test/assets/proposal_builder_output.json @@ -0,0 +1 @@ +{"$schema":"http://json-schema.org/draft-07/schema#","$id":"https://cardano.org/schemas/catalyst/f14/proposal","title":"F14 Submission Form","description":"Schema for the F14 Catalyst Proposal Submission Form","definitions":{"segment":{"type":"object","additionalProperties":false,"x-note":"Major sections of the proposal. Each segment contains sections of information grouped together."},"section":{"type":"object","additionalProperties":false,"x-note":"Subsections containing specific details about the proposal."},"singleLineTextEntry":{"type":"string","contentMediaType":"text/plain","pattern":"^.*$","x-note":"Enter a single line of text. No formatting, line breaks, or special characters are allowed."},"singleLineHttpsURLEntry":{"type":"string","format":"uri","pattern":"^https:.*","x-note":"Enter a valid HTTPS URL. Must start with 'https://' and be a complete, working web address."},"multiLineTextEntry":{"type":"string","contentMediaType":"text/plain","pattern":"^[\\S\\s]*$","x-note":"Enter multiple lines of plain text. You can use line breaks but no special formatting."},"multiLineTextEntryMarkdown":{"type":"string","contentMediaType":"text/markdown","pattern":"^[\\S\\s]*$","x-note":"Use Markdown formatting for rich text. Available formatting:\n- Headers: # for h1, ## for h2, etc.\n- Lists: * or - for bullets, 1. for numbered\n- Emphasis: *italic* or **bold**\n- Links: [text](url)\n- Code: `inline` or ```block```"},"dropDownSingleSelect":{"type":"string","contentMediaType":"text/plain","pattern":"^.*$","format":"dropDownSingleSelect","x-note":"Select one option from the dropdown menu. Only one choice is allowed."},"multiSelect":{"type":"array","uniqueItems":true,"format":"multiSelect","x-note":"Select multiple options from the dropdown menu. Multiple choices are allowed."},"singleLineTextEntryList":{"type":"array","format":"singleLineTextEntryList","uniqueItems":true,"default":[],"items":{"$ref":"#/definitions/singleLineTextEntry","maxLength":1024},"x-note":"Add multiple single-line text entries. Each entry should be unique and under 1024 characters."},"multiLineTextEntryListMarkdown":{"type":"array","format":"multiLineTextEntryListMarkdown","uniqueItems":true,"default":[],"items":{"$ref":"#/definitions/multiLineTextEntryMarkdown","maxLength":10240},"x-note":"Add multiple markdown-formatted text entries. Each entry can include rich formatting and should be unique."},"singleLineHttpsURLEntryList":{"type":"array","format":"singleLineHttpsURLEntryList","uniqueItems":true,"default":[],"items":{"$ref":"#/definitions/singleLineHttpsURLEntry","maxLength":1024},"x-note":"Enter multiple HTTPS URLs. Each URL should be unique and under 1024 characters."},"nestedQuestionsList":{"type":"array","format":"nestedQuestionsList","uniqueItems":true,"default":[],"x-note":"Add multiple questions. Each question should be unique."},"nestedQuestions":{"type":"object","format":"nestedQuestions","additionalProperties":false,"x-note":"Add multiple questions. Each question should be unique."},"singleGroupedTagSelector":{"type":"object","format":"singleGroupedTagSelector","additionalProperties":true,"x-note":"Select one option from the dropdown menu. Only one choice is allowed."},"tagGroup":{"type":"string","format":"tagGroup","pattern":"^.*$","x-note":"Select one option from the dropdown menu. Only one choice is allowed."},"tagSelection":{"type":"string","format":"tagSelection","x-note":"Select one option from the dropdown menu. Only one choice is allowed."},"tokenValueCardanoADA":{"type":"integer","format":"token:cardano:ada","x-note":"Enter the amount of Cardano ADA to be used in the proposal."},"durationInMonths":{"type":"integer","format":"datetime:duration:months","x-note":"Enter the duration of the proposal in months."},"yesNoChoice":{"type":"boolean","format":"yesNoChoice","default":false,"x-note":"Select Yes or No."},"agreementConfirmation":{"type":"boolean","format":"agreementConfirmation","default":false,"const":true,"x-note":"Select Yes or No."},"spdxLicenseOrURL":{"type":"string","contentMediaType":"text/plain","pattern":"^.*$","format":"spdxLicenseOrURL","x-note":"Select one option from the dropdown menu. Only one choice is allowed."}},"type":"object","additionalProperties":false,"properties":{"setup":{"$ref":"#/definitions/segment","id":"setup","title":"proposal setup","description":"Proposal title","properties":{"proposer":{"$ref":"#/definitions/section","id":"proposer","title":"","description":"","properties":{"applicant":{"$ref":"#/definitions/singleLineTextEntry","id":"applicant","title":"Name and surname of main applicant","description":"Name and surname of main applicant","minLength":2,"maxLength":100,"default":"","x-guidance":"

Please provide the name and surname of the main applicant. The main applicant is considered as the individual responsible for the project and the person authorized to act on behalf of other applicants (where applicable).

","enum":[],"examples":[],"items":{}},"type":{"$ref":"#/definitions/dropDownSingleSelect","id":"type","title":"Are you delivering this project as an individual or as an entity (whether formally incorporated or not)","description":"Are you delivering this project as an individual or as an entity (whether formally incorporated or not)","default":"Individual","x-guidance":"

Please select from one of the following:

  1. Individual
  2. Entity (Incorporated)
  3. Entity (Not Incorporated)
","enum":["Individual","Entity (Incorporated)","Entity (Not Incorporated)"],"examples":[],"items":{}},"coproposers":{"$ref":"#/definitions/singleLineTextEntryList","id":"coproposers","title":"Co-proposers and additional applicants","description":"Co-proposers and additional applicants","default":"","x-guidance":"

List any persons who are submitting the proposal jointly with the main applicant. Make sure you have confirmed approval/awareness with these individuals/accounts before adding them. If there is more than one proposer, identify the lead person who is authorized to act on behalf of other co-proposers. IMPORTANT A maximum of 6 (six) proposals can be led or co-proposed by the same applicant or enterprise. Please, reference Fund 14 rules for added detail.

","enum":[],"maxItems":5,"minItems":0,"examples":[],"items":{}}},"required":["applicant","type"],"x-order":["applicant","type","coproposers"],"dependencies":{},"if":{},"then":{},"open_source":{}},"title":{"$ref":"#/definitions/section","id":"title","title":"proposal setup","description":"Proposal title","properties":{"title":{"$ref":"#/definitions/singleLineTextEntry","id":"title","title":"Proposal Title","description":"

Proposal title

Please note we suggest you use no more than 60 characters for your proposal title so that it can be easily viewed in the voting app.

","minLength":1,"maxLength":60,"default":"","x-guidance":"

The title should clearly express what the proposal is about. Voters can see the title in the voting app, even without opening the proposal, so a clear, unambiguous, and concise title is very important.

","enum":[],"examples":[],"items":{}}},"required":["title"],"x-order":[],"dependencies":{},"if":{},"then":{},"open_source":{}}},"required":["title","proposer"],"x-order":["title","proposer"]},"summary":{"$ref":"#/definitions/segment","id":"summary","title":"Proposal Summary","description":"Key information about your proposal","properties":{"budget":{"$ref":"#/definitions/section","id":"budget","title":"Budget Information","description":"","properties":{"requestedFunds":{"$ref":"#/definitions/tokenValueCardanoADA","id":"requestedFunds","title":"Requested funds in ADA","description":"The amount of funding requested for your proposal","default":"","x-guidance":"

There is a minimum and a maximum amount of funding that can be requested in a single Catalyst proposal. These are outlined below per each category:

Minimum Funding Amount per proposal:

Cardano Open: A15,000

Cardano Uses Cases: A15,000

Cardano Partners: A500,000

Maximum Funding Amount per proposal:

Cardano Open:

  • Developers (technical): A200,000
  • Ecosystem (non-technical): A100,000

Cardano Uses Cases:

  • Concept A150,000
  • Product: A500,000

Cardano Partners:

  • Enterprise R&D A2,000,000
  • Growth & Acceleration: A2,000,000
","enum":[],"minimum":15000,"maximum":2000000,"examples":[],"items":{}}},"required":["requestedFunds"],"x-order":["requestedFunds"],"dependencies":{},"if":{},"then":{},"open_source":{}},"time":{"$ref":"#/definitions/section","id":"time","title":"","description":"","properties":{"duration":{"$ref":"#/definitions/durationInMonths","id":"duration","title":"Project Duration in Months","description":"Specify the expected duration of your project. Projects must be completable within 2-12 months.","default":"","x-guidance":"

Minimum 2 months-Maximum 12 months. The scope of your funding request and this project is expected to produce the deliverables you specify in the proposal within 2-12 months If you believe your project will take longer than 12 months, consider reducing the project's scope so that it becomes achievable within 12 months If your project completes earlier than scheduled so long as you have submitted your PoAs and Project Close-out report and video then your project can be closed out.

","enum":[],"minimum":2,"maximum":12,"examples":[],"items":{}}},"required":["duration"],"x-order":[],"dependencies":{},"if":{},"then":{},"open_source":{}},"translation":{"$ref":"#/definitions/section","id":"translation","title":"Translation Information","description":"Information about the proposal's language and translation status","properties":{"isTranslated":{"$ref":"#/definitions/yesNoChoice","id":"isTranslated","title":"Auto-translated Status","description":"Indicate if your proposal has been auto-translated into English from another language","default":"","x-guidance":"

Tick YES if your proposal has been auto-translated into English from another language so readers are reminded that your proposal has been translated, and that they should be tolerant of any language imperfections. Tick NO if your proposal has not been auto-translated into English from another language

","enum":[],"examples":[],"items":{}},"originalLanguage":{"$ref":"#/definitions/singleLineTextEntry","id":"originalLanguage","title":"Original Language","description":"If auto-translated, specify the original language of your proposal","default":"","x-guidance":"","enum":["Arabic","Chinese","French","German","Indonesian","Italian","Japanese","Korean","Portuguese","Russian","Spanish","Turkish","Vietnamese","Other"],"examples":[],"items":{}},"originalDocumentLink":{"$ref":"#/definitions/singleLineHttpsURLEntry","id":"originalDocumentLink","title":"Original Document Link","description":"Provide a link to the original proposal document in its original language","default":"","x-guidance":"","enum":[],"examples":[],"items":{}}},"required":["isTranslated"],"x-order":[],"dependencies":{},"if":{"properties":{"isTranslated":{"const":true}}},"then":{"required":["originalLanguage","originalDocumentLink"],"properties":{"originalLanguage":{"description":"Original language is required when the proposal is translated"},"originalDocumentLink":{"description":"Link to the original document is required when the proposal is translated"}}},"open_source":{}},"problem":{"$ref":"#/definitions/section","id":"problem","title":"Problem Statement","description":"Define the problem your proposal aims to solve","properties":{"statement":{"$ref":"#/definitions/multiLineTextEntry","id":"statement","title":"Problem Description","description":"Clearly define the problem you aim to solve. This will be visible in the Catalyst voting app.","minLength":10,"maxLength":200,"default":"","x-guidance":"

Ensure you present a well-defined problem. What is the core issue that you hope to fix? Remember: the reader might not recognize the problem unless you state it clearly. This answer will be displayed on the Catalyst voting app, so voters will see it even if they don't open your proposal to read it in detail.

","enum":[],"examples":[],"items":{}},"impact":{"$ref":"#/definitions/multiSelect","id":"impact","title":"Impact Areas","description":"Select the areas that will be most impacted by solving this problem","default":"","x-guidance":"","enum":[],"maxItems":3,"minItems":1,"examples":[],"items":{"$ref":"#/definitions/singleLineTextEntry","enum":["Technical Infrastructure","User Experience","Developer Tooling","Community Growth","Economic Sustainability","Interoperability","Security","Scalability","Education","Adoption"]}}},"required":["statement","impact"],"x-order":[],"dependencies":{},"if":{},"then":{},"open_source":{}},"solution":{"$ref":"#/definitions/section","id":"solution","title":"Solution Overview","description":"Describe your proposed solution to the problem","properties":{"summary":{"$ref":"#/definitions/multiLineTextEntry","id":"summary","title":"Solution Summary","description":"Briefly describe your solution. Focus on what you will do or create to solve the problem.","minLength":10,"maxLength":200,"default":"","x-guidance":"

Focus on what you are going to do, or make, or change, to solve the problem. So not 'There should be a way to....' but 'We will make a Clearly state how the solution addresses the specific problem you have identified - connect the 'why' and the 'how' This answer will be displayed on the Catalyst voting app, so voters will see it even if they do not open your proposal and read it in detail.

","enum":[],"examples":[],"items":{}},"approach":{"$ref":"#/definitions/multiLineTextEntry","id":"approach","title":"Technical Approach","description":"Outline the technical approach or methodology you will use","maxLength":500,"default":"","x-guidance":"","enum":[],"examples":[],"items":{}},"innovationAspects":{"$ref":"#/definitions/singleLineTextEntryList","id":"innovationAspects","title":"Innovation Aspects","description":"Key innovative aspects of your solution","default":"","x-guidance":"","enum":[],"maxItems":5,"minItems":1,"examples":[],"items":{}}},"required":["summary","approach"],"x-order":[],"dependencies":{},"if":{},"then":{},"open_source":{}},"supportingLinks":{"$ref":"#/definitions/section","id":"supportingLinks","title":"Supporting Documentation","description":"Additional resources and documentation for your proposal","properties":{"mainRepository":{"$ref":"#/definitions/singleLineHttpsURLEntry","id":"mainRepository","title":"Main Code Repository","description":"Primary repository where the project's code will be hosted","default":"","x-guidance":"","enum":[],"examples":[],"items":{}},"documentation":{"$ref":"#/definitions/singleLineHttpsURLEntry","id":"documentation","title":"Documentation URL","description":"Main documentation site or resource for the project","default":"","x-guidance":"","enum":[],"examples":[],"items":{}},"other":{"$ref":"#/definitions/singleLineHttpsURLEntryList","id":"other","title":"Resource Links","description":"Links to any other relevant documentation, code repositories, or marketing materials. All links must use HTTPS.","default":"","x-guidance":"","enum":[],"maxItems":5,"minItems":0,"examples":[],"items":{}}},"required":[],"x-order":[],"dependencies":{},"if":{},"then":{},"open_source":{}},"dependencies":{"$ref":"#/definitions/section","id":"dependencies","title":"Project Dependencies","description":"External dependencies and requirements for project success","properties":{"details":{"$ref":"#/definitions/nestedQuestionsList","id":"details","title":"Dependency Details","description":"List and describe each dependency","default":"","x-guidance":"","enum":[],"maxItems":10,"minItems":0,"examples":[],"items":{"$ref":"#/definitions/nestedQuestions","properties":{"name":{"$ref":"#/definitions/singleLineTextEntry","title":"Dependency Name","description":"Name of the organization, technology, or resource","maxLength":100},"type":{"$ref":"#/definitions/dropDownSingleSelect","title":"Dependency Type","description":"Type of dependency","enum":["Technical","Organizational","Legal","Financial","Other"]},"description":{"$ref":"#/definitions/multiLineTextEntry","title":"Description","description":"Explain why this dependency is essential and how it affects your project","maxLength":500},"mitigationPlan":{"$ref":"#/definitions/multiLineTextEntry","title":"Mitigation Plan","description":"How will you handle potential issues with this dependency","maxLength":300}},"required":["name","type","description"]}}},"required":[],"x-order":[],"dependencies":{},"if":{},"then":{},"open_source":{}},"open_source":{"$ref":"#/definitions/section","id":"open_source","title":"Project Open Source","description":"Will your project's output be fully open source? Open source refers to something people can modify and share because its design is publicly accessible.","properties":{"source_code":{"$ref":"#/definitions/spdxLicenseOrURL","id":"source_code","title":"","description":"","default":"","x-guidance":"","enum":[],"examples":[],"items":{}},"documentation":{"$ref":"#/definitions/spdxLicenseOrURL","id":"documentation","title":"","description":"","default":"","x-guidance":"","enum":[],"examples":[],"items":{}},"note":{"$ref":"#/definitions/multiLineTextEntry","id":"note","title":"More Information","description":"Please provide here more information on the open source status of your project outputs","maxLength":500,"default":"","x-guidance":"

If you did not answer PROPRIETARY to the above questions, the project should be open source available throughout the entire lifecycle of the project with a declared open-source repository. Please indicate here the type of license you intend to use for open source and provide any further information you feel is relevant to the open source status of your project outputs If only certain elements of your code will be open source please clarify which elements will be open source here. If you answered NO to the above question, please give further details as to why your projects outputs will not be open source METADATA

","enum":[],"examples":[],"items":{}}},"required":["source_code","documentation"],"x-order":["source_code","documentation","note"],"dependencies":{},"if":{},"then":{},"open_source":{}}},"required":[],"x-order":["budget","time","translation","problem","solution","supportingLinks","dependencies","open_source"]},"horizons":{"$ref":"#/definitions/segment","id":"horizons","title":"Horizons","description":"","properties":{"theme":{"$ref":"#/definitions/section","id":"theme","title":"Horizons","description":"Long-term vision and categorization of your project","properties":{"grouped_tag":{"$ref":"#/definitions/singleGroupedTagSelector","id":"grouped_tag","title":"","description":"","default":"","x-guidance":"","enum":[],"examples":[],"items":{}}},"required":[],"x-order":["theme"],"dependencies":{},"if":{},"then":{},"open_source":{}}},"required":[],"x-order":["theme"]},"details":{"$ref":"#/definitions/segment","id":"details","title":"Your Project and Solution","description":"","properties":{"solution":{"$ref":"#/definitions/section","id":"solution","title":"Solution","description":"

How you write this section will depend on what type of proposal you are writing. You might want to include details on:


  • How do you perceive the problem you are solving?
  • What are your reasons for approaching it in the way that you have?
  • Who will your project engage?
  • How will you demonstrate or prove your impact?


Explain what is unique about your solution, who will benefit, and why this is important to Cardano.

","properties":{"solution":{"$ref":"#/definitions/multiLineTextEntryMarkdown","id":"solution","title":"","description":"","minLength":1,"maxLength":10240,"default":"","x-guidance":"","enum":[],"examples":["Our solution involves developing a decentralized education platform that will..."],"items":{}}},"required":[],"x-order":[],"dependencies":{},"if":{},"then":{},"open_source":{}},"impact":{"$ref":"#/definitions/section","id":"impact","title":"Impact","description":"

Please include here a description of how you intend to measure impact (whether quantitative or qualitative) and how and with whom you will share your outputs:


  • In what way will the success of your project bring value to the Cardano Community? 
  • How will you measure this impact? 
  • How will you share the outputs and opportunities that result from your project?
","properties":{"impact":{"$ref":"#/definitions/multiLineTextEntryMarkdown","id":"impact","title":"","description":"","minLength":1,"maxLength":10240,"default":"","x-guidance":"","enum":[],"examples":[],"items":{}}},"required":[],"x-order":[],"dependencies":{},"if":{},"then":{},"open_source":{}},"feasibility":{"$ref":"#/definitions/section","id":"feasibility","title":"Capabilities & Feasibility","description":"

Please describe your existing capabilities that demonstrate how and why you believe you’re best suited to deliver this project?

Please include the steps or processes that demonstrate that you can be trusted to manage funds properly.

","properties":{"feasibility":{"$ref":"#/definitions/multiLineTextEntryMarkdown","id":"feasibility","title":"","description":"","minLength":1,"maxLength":10240,"default":"","x-guidance":"","enum":[],"examples":[],"items":{}}},"required":[],"x-order":[],"dependencies":{},"if":{},"then":{},"open_source":{}}},"required":[],"x-order":["solution","impact","feasibility"]},"milestones":{"$ref":"#/definitions/segment","id":"milestones","title":"Milestones","description":"","properties":{"milestones":{"$ref":"#/definitions/section","id":"milestones","title":"Project Milestones","description":"

Each milestone must declare:

  • A: Milestone outputs
  • B: Acceptance criteria
  • C: Evidence of completion

Requirements:

  • For Grant Amounts up to 75k ada: minimum 3 milestones (2 + final)
  • For Grant Amounts 75k-150k ada: minimum 4 milestones (3 + final)
  • The final milestone must include Project Close-out Report and Video
","properties":{"milestone_list":{"$ref":"","id":"milestone_list","title":"Milestones","description":"What are the key milestones you need to achieve in order to complete your project successfully?","default":"","x-guidance":"

Milestone Requirements:

  • For Grant Amounts of up to 75k ada: at least 2 milestones, plus the final one including Project Close-out Report and Video, must be included (3 milestones in total)
  • For Grant Amounts over 75k ada up to 150k ada: at least 3 milestones, plus the final one including Project Close-out Report and Video, must be included (4 milestones in total)
  • For Grant Amounts over 150k ada up to 300k ada: at least 4 milestones, plus the final one including Project Close-out Report and Video, must be included (5 milestones in total)
  • For Grant Amounts exceeding 300k ada: at least 5 milestones, plus the final one including Project Close-out Report and Video, must be included (6 milestones in total)
","enum":[],"maxItems":6,"minItems":3,"examples":[],"items":{"type":"object","required":["title","outputs","acceptance_criteria","evidence","delivery_month","cost"],"properties":{"title":{"$ref":"#/definitions/singleLineTextEntry","title":"Milestone Title","description":"A clear, concise title for this milestone","maxLength":100},"outputs":{"$ref":"#/definitions/multiLineTextEntryMarkdown","title":"Milestone Outputs","description":"What will be delivered in this milestone","maxLength":1000},"acceptance_criteria":{"$ref":"#/definitions/multiLineTextEntryMarkdown","title":"Acceptance Criteria","description":"Specific conditions that must be met","maxLength":1000},"evidence":{"$ref":"#/definitions/multiLineTextEntryMarkdown","title":"Evidence of Completion","description":"How you will demonstrate achievement","maxLength":1000},"delivery_month":{"$ref":"#/definitions/durationInMonths","title":"Delivery Month","description":"The month when this milestone will be delivered","minimum":1,"maximum":12},"cost":{"$ref":"#/definitions/tokenValueCardanoADA","title":"Cost in ADA","description":"The cost of this milestone in ADA"},"progress":{"$ref":"#/definitions/dropDownSingleSelect","title":"Progress Status","description":"Current status of the milestone","enum":["Not Started","In Progress","Completed","Delayed"],"default":"Not Started"}}}}},"required":["milestone_list"],"x-order":[],"dependencies":{},"if":{},"then":{},"open_source":{}}},"required":[],"x-order":["milestones"]},"pitch":{"$ref":"#/definitions/segment","id":"pitch","title":"Final Pitch","description":"","properties":{"team":{"$ref":"#/definitions/section","id":"team","title":"Team","description":"","properties":{"who":{"$ref":"#/definitions/multiLineTextEntryMarkdown","id":"who","title":"Who is in the project team and what are their roles?","description":"

List your team, their Linkedin profiles (or similar) and state what aspect of the proposal’s work each team member will undertake.


If you are planning to recruit additional team members, please state what specific skills you will be looking for in the people you recruit, so readers can see that you understand what skills will be needed to complete the project.


You are expected to have already engaged the relevant members of the organizations referenced so you understand if they are willing and/or have capacity to support the project. If you have not taken any steps to engage with your team yet, it is likely that the resources will not be available if you are approved for funding, which can jeopardize the project before it has even begun. The Catalyst team cannot help with this, meaning you are expected to have understood the requirements and engaged the necessary people before submitting a proposal.


Have you engaged anyone on any of the technical group channels (eg Discord or Telegram), or do you have a direct line of communications with the people and resources required?


Important: Catalyst funding is not anonymous, and some level of ‘proof of life’ verifications will take place before initial funding is released. Also remember that your proposal will be publicly available, so make sure to obtain any consent required before including confidential or third party information.


All Project Participants must disclose their role and scope of services across any submitted proposals, even if they are not in the lead or co-proposer role, such as an implementer, vendor, service provider, etc. Failure to disclose this information may lead to disqualification from the current grant round.

","minLength":1,"maxLength":10240,"default":"","x-guidance":"","enum":[],"examples":[],"items":{}}},"required":[],"x-order":[],"dependencies":{},"if":{},"then":{},"open_source":{}},"budget":{"$ref":"#/definitions/section","id":"budget","title":"Budget & Costs","description":"","properties":{"costs":{"$ref":"#/definitions/multiLineTextEntryMarkdown","id":"costs","title":"Please provide a cost breakdown of the proposed work and resources","description":"

Make sure every element mentioned in your plan reflects its cost. It may be helpful to refer to your plan and timeline, list all the resources you will need at each stage, and what they cost.


Here, provide a clear description of any third party product or service you will be using. This could be hardware, software licenses, professional services (legal, accounting, code auditing, etc) but does not need to include the use of contracted programmers and developers.


The exact budget elements you include will depend on what type of work you are doing, and you might need to give less detail for a small, low-budget proposal. If the cost of the project will exceed the funding request, please provide information about alternative sources of funding.


Consider including budget elements for publicity / marketing / promotion / community engagement; project management; documentation; and reporting back to the community. Most proposals need these, but many proposers forget to include them.


It is the project team’s responsibility to properly manage the funds provided. Make sure to reference Fund Rules to understand eligibility around costs.

","minLength":1,"maxLength":10240,"default":"","x-guidance":"","enum":[],"examples":[],"items":{}}},"required":[],"x-order":[],"dependencies":{},"if":{},"then":{},"open_source":{}},"value":{"$ref":"#/definitions/section","id":"value","title":"Value for Money","description":"","properties":{"note":{"$ref":"#/definitions/multiLineTextEntryMarkdown","id":"note","title":"How does the cost of the project represent value for money for the Cardano ecosystem?","description":"

Use the response to provide the context about the costs you listed previously, particularly if they are high.


It may be helpful to include some brief information on how you have decided on the costs of the project. 


For instance, can you justify with supporting evidence that costs are proportional to the average wage in your country, or typical freelance rates in your industry? Is there anything else that helps to support how the project represents value for money?

","minLength":1,"maxLength":10240,"default":"","x-guidance":"","enum":[],"examples":[],"items":{}}},"required":[],"x-order":[],"dependencies":{},"if":{},"then":{},"open_source":{}}},"required":[],"x-order":["team","budget","value"]},"agreements":{"$ref":"#/definitions/segment","id":"agreements","title":"Acknowledgements","description":"","properties":{"mandatory":{"$ref":"#/definitions/section","id":"mandatory","title":"Mandatory","description":"","properties":{"fund_rules":{"$ref":"#/definitions/agreementConfirmation","id":"fund_rules","title":"Fund Rules:","description":"

By submitting a proposal to Project Catalyst Fund14, I confirm that I have read and agree to be bound by the Fund Rules.

","default":"","x-guidance":"","enum":[],"examples":[],"items":{}},"terms_and_conditions":{"$ref":"#/definitions/agreementConfirmation","id":"terms_and_conditions","title":"Terms and Conditions:","description":"

By submitting a proposal to Project Catalyst Fund14, I confirm that I have read and agree to be bound by the Project Catalyst Terms and Conditions.

","default":"","x-guidance":"","enum":[],"examples":[],"items":{}},"privacy_policy":{"$ref":"#/definitions/agreementConfirmation","id":"privacy_policy","title":"Privacy Policy: ","description":"

I acknowledge and agree that any data I share in connection with my participation in Project Catalyst Fund14 will be collected, stored, used and processed in accordance with the Catalyst FC’s Privacy Policy.

","default":"","x-guidance":"","enum":[],"examples":[],"items":{}}},"required":["fund_rules","terms_and_conditions","privacy_policy"],"x-order":["fund_rules","terms_and_conditions","privacy_policy"],"dependencies":{},"if":{},"then":{},"open_source":{}}},"required":[],"x-order":["mandatory"]}},"x-order":["setup","summary","horizons","details","milestones","pitch","agreements"]} \ No newline at end of file diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/dtos/proposal_definitions_dto.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/definitions_dto.dart similarity index 52% rename from catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/dtos/proposal_definitions_dto.dart rename to catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/definitions_dto.dart index 9b8e2d6113f..88eb5d653f7 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/dtos/proposal_definitions_dto.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/definitions_dto.dart @@ -1,34 +1,35 @@ -import 'package:catalyst_voices_models/src/proposal_schema/proposal_definitions.dart'; +import 'package:catalyst_voices_models/src/proposal_schema/definitions.dart'; import 'package:json_annotation/json_annotation.dart'; -part 'proposal_definitions_dto.g.dart'; + +part 'definitions_dto.g.dart'; @JsonSerializable() -class ProposalDefinitionsDTO { - final SegmentDTO segment; - final SectionDTO section; - final SingleLineTextEntryDTO singleLineTextEntry; - final SingleLineHttpsURLEntryDTO singleLineHttpsURLEntry; - final MultiLineTextEntryDTO multiLineTextEntry; - final MultiLineTextEntryMarkdownDTO multiLineTextEntryMarkdown; - final DropDownSingleSelectDTO dropDownSingleSelect; - final MultiSelectDTO multiSelect; - final SingleLineTextEntryListDTO singleLineTextEntryList; - final MultiLineTextEntryListMarkdownDTO multiLineTextEntryListMarkdown; - final SingleLineHttpsURLEntryListDTO singleLineHttpsURLEntryList; - final NestedQuestionsListDTO nestedQuestionsList; - final NestedQuestionsDTO nestedQuestions; - final SingleGroupedTagSelectorDTO singleGroupedTagSelector; - final TagGroupDTO tagGroup; - final TagSelectionDTO tagSelection; +class DefinitionsDto { + final SegmentDto segment; + final SectionDto section; + final SingleLineTextEntryDto singleLineTextEntry; + final SingleLineHttpsURLEntryDto singleLineHttpsURLEntry; + final MultiLineTextEntryDto multiLineTextEntry; + final MultiLineTextEntryMarkdownDto multiLineTextEntryMarkdown; + final DropDownSingleSelectDto dropDownSingleSelect; + final MultiSelectDto multiSelect; + final SingleLineTextEntryListDto singleLineTextEntryList; + final MultiLineTextEntryListMarkdownDto multiLineTextEntryListMarkdown; + final SingleLineHttpsURLEntryListDto singleLineHttpsURLEntryList; + final NestedQuestionsListDto nestedQuestionsList; + final NestedQuestionsDto nestedQuestions; + final SingleGroupedTagSelectorDto singleGroupedTagSelector; + final TagGroupDto tagGroup; + final TagSelectionDto tagSelection; @JsonKey(name: 'tokenValueCardanoADA') - final TokenValueCardanoAdaDTO tokenValueCardanoAda; - final DurationInMonthsDTO durationInMonths; - final YesNoChoiceDTO yesNoChoice; - final AgreementConfirmationDTO agreementConfirmation; + final TokenValueCardanoAdaDto tokenValueCardanoAda; + final DurationInMonthsDto durationInMonths; + final YesNoChoiceDto yesNoChoice; + final AgreementConfirmationDto agreementConfirmation; @JsonKey(name: 'spdxLicenseOrURL') - final SPDXLicenceOrUrlDTO spdxLicenceOrUrl; + final SPDXLicenceOrUrlDto spdxLicenceOrUrl; - const ProposalDefinitionsDTO({ + const DefinitionsDto({ required this.segment, required this.section, required this.singleLineTextEntry, @@ -52,92 +53,91 @@ class ProposalDefinitionsDTO { required this.spdxLicenceOrUrl, }); - factory ProposalDefinitionsDTO.fromJson(Map json) => - _$ProposalDefinitionsDTOFromJson(json); + factory DefinitionsDto.fromJson(Map json) => + _$DefinitionsDtoFromJson(json); - Map toJson() => _$ProposalDefinitionsDTOToJson(this); + Map toJson() => _$DefinitionsDtoToJson(this); - ProposalDefinitions toModel() { - return ProposalDefinitions( - segmentDefinition: segment.toModel(), - sectionDefinition: section.toModel(), - singleLineTextEntryDefinition: singleLineTextEntry.toModel(), - ); - } + List get definitions => [ + segment.toModel(), + section.toModel(), + singleLineTextEntry.toModel(), + durationInMonths.toModel(), + ]; } @JsonSerializable() -class SegmentDTO { +class SegmentDto { final String type; final bool additionalProperties; @JsonKey(name: 'x-note') final String note; - const SegmentDTO({ + const SegmentDto({ required this.type, required this.additionalProperties, required this.note, }); - factory SegmentDTO.fromJson(Map json) => - _$SegmentDTOFromJson(json); + factory SegmentDto.fromJson(Map json) => + _$SegmentDtoFromJson(json); - Map toJson() => _$SegmentDTOToJson(this); + Map toJson() => _$SegmentDtoToJson(this); - SegmentProposalDefinition toModel() => SegmentProposalDefinition( - type: DefinitionsObjectTypes.fromString(type), + SegmentDefinition toModel() => SegmentDefinition( + type: DefinitionsObjectType.fromString(type), note: note, additionalProperties: additionalProperties, ); } @JsonSerializable() -class SectionDTO { +class SectionDto { final String type; final bool additionalProperties; @JsonKey(name: 'x-note') final String note; - const SectionDTO({ + const SectionDto({ required this.type, required this.additionalProperties, required this.note, }); - factory SectionDTO.fromJson(Map json) => - _$SectionDTOFromJson(json); + factory SectionDto.fromJson(Map json) => + _$SectionDtoFromJson(json); - Map toJson() => _$SectionDTOToJson(this); + Map toJson() => _$SectionDtoToJson(this); - SectionProposalDefinition toModel() => SectionProposalDefinition( - type: DefinitionsObjectTypes.fromString(type), + SectionDefinition toModel() => SectionDefinition( + type: DefinitionsObjectType.fromString(type), note: note, additionalProperties: additionalProperties, ); } @JsonSerializable() -class SingleLineTextEntryDTO { +class SingleLineTextEntryDto { final String type; final String contentMediaType; final String pattern; @JsonKey(name: 'x-note') final String note; - const SingleLineTextEntryDTO({ + const SingleLineTextEntryDto({ required this.type, required this.contentMediaType, required this.pattern, required this.note, }); - factory SingleLineTextEntryDTO.fromJson(Map json) => - _$SingleLineTextEntryDTOFromJson(json); + factory SingleLineTextEntryDto.fromJson(Map json) => + _$SingleLineTextEntryDtoFromJson(json); - Map toJson() => _$SingleLineTextEntryDTOToJson(this); + Map toJson() => _$SingleLineTextEntryDtoToJson(this); SingleLineTextEntryDefinition toModel() => SingleLineTextEntryDefinition( - type: DefinitionsObjectTypes.fromString(type), + type: DefinitionsObjectType.fromString(type), note: note, contentMediaType: DefinitionsContentMediaType.fromString(contentMediaType), @@ -146,74 +146,70 @@ class SingleLineTextEntryDTO { } @JsonSerializable() -class SingleLineHttpsURLEntryDTO { +class SingleLineHttpsURLEntryDto { final String type; final String format; final String pattern; @JsonKey(name: 'x-note') final String note; - const SingleLineHttpsURLEntryDTO({ + const SingleLineHttpsURLEntryDto({ required this.type, required this.format, required this.pattern, required this.note, }); - factory SingleLineHttpsURLEntryDTO.fromJson(Map json) => - _$SingleLineHttpsURLEntryDTOFromJson(json); + factory SingleLineHttpsURLEntryDto.fromJson(Map json) => + _$SingleLineHttpsURLEntryDtoFromJson(json); - Map toJson() => _$SingleLineHttpsURLEntryDTOToJson(this); + Map toJson() => _$SingleLineHttpsURLEntryDtoToJson(this); } @JsonSerializable() -class MultiLineTextEntryDTO { +class MultiLineTextEntryDto { final String type; final String contentMediaType; final String pattern; - final String format; @JsonKey(name: 'x-note') final String note; - const MultiLineTextEntryDTO({ + const MultiLineTextEntryDto({ required this.type, required this.contentMediaType, required this.pattern, - required this.format, required this.note, }); - factory MultiLineTextEntryDTO.fromJson(Map json) => - _$MultiLineTextEntryDTOFromJson(json); + factory MultiLineTextEntryDto.fromJson(Map json) => + _$MultiLineTextEntryDtoFromJson(json); - Map toJson() => _$MultiLineTextEntryDTOToJson(this); + Map toJson() => _$MultiLineTextEntryDtoToJson(this); } @JsonSerializable() -class MultiLineTextEntryMarkdownDTO { +class MultiLineTextEntryMarkdownDto { final String type; final String contentMediaType; final String pattern; - final String format; @JsonKey(name: 'x-note') final String note; - const MultiLineTextEntryMarkdownDTO({ + const MultiLineTextEntryMarkdownDto({ required this.type, required this.contentMediaType, required this.pattern, - required this.format, required this.note, }); - factory MultiLineTextEntryMarkdownDTO.fromJson(Map json) => - _$MultiLineTextEntryMarkdownDTOFromJson(json); + factory MultiLineTextEntryMarkdownDto.fromJson(Map json) => + _$MultiLineTextEntryMarkdownDtoFromJson(json); - Map toJson() => _$MultiLineTextEntryMarkdownDTOToJson(this); + Map toJson() => _$MultiLineTextEntryMarkdownDtoToJson(this); } @JsonSerializable() -class DropDownSingleSelectDTO { +class DropDownSingleSelectDto { final String type; final String contentMediaType; final String pattern; @@ -221,7 +217,7 @@ class DropDownSingleSelectDTO { @JsonKey(name: 'x-note') final String note; - const DropDownSingleSelectDTO({ + const DropDownSingleSelectDto({ required this.type, required this.contentMediaType, required this.pattern, @@ -229,37 +225,35 @@ class DropDownSingleSelectDTO { required this.note, }); - factory DropDownSingleSelectDTO.fromJson(Map json) => - _$DropDownSingleSelectDTOFromJson(json); + factory DropDownSingleSelectDto.fromJson(Map json) => + _$DropDownSingleSelectDtoFromJson(json); - Map toJson() => _$DropDownSingleSelectDTOToJson(this); + Map toJson() => _$DropDownSingleSelectDtoToJson(this); } @JsonSerializable() -class MultiSelectDTO { +class MultiSelectDto { final String type; - final String contentMediaType; - final String pattern; + final bool uniqueItems; final String format; @JsonKey(name: 'x-note') final String note; - const MultiSelectDTO({ + const MultiSelectDto({ required this.type, - required this.contentMediaType, - required this.pattern, + required this.uniqueItems, required this.format, required this.note, }); - factory MultiSelectDTO.fromJson(Map json) => - _$MultiSelectDTOFromJson(json); + factory MultiSelectDto.fromJson(Map json) => + _$MultiSelectDtoFromJson(json); - Map toJson() => _$MultiSelectDTOToJson(this); + Map toJson() => _$MultiSelectDtoToJson(this); } @JsonSerializable() -class SingleLineTextEntryListDTO { +class SingleLineTextEntryListDto { final String type; final String format; final bool uniqueItems; @@ -269,7 +263,7 @@ class SingleLineTextEntryListDTO { @JsonKey(name: 'x-note') final String note; - const SingleLineTextEntryListDTO({ + const SingleLineTextEntryListDto({ required this.type, required this.format, required this.uniqueItems, @@ -278,14 +272,14 @@ class SingleLineTextEntryListDTO { required this.note, }); - factory SingleLineTextEntryListDTO.fromJson(Map json) => - _$SingleLineTextEntryListDTOFromJson(json); + factory SingleLineTextEntryListDto.fromJson(Map json) => + _$SingleLineTextEntryListDtoFromJson(json); - Map toJson() => _$SingleLineTextEntryListDTOToJson(this); + Map toJson() => _$SingleLineTextEntryListDtoToJson(this); } @JsonSerializable() -class MultiLineTextEntryListMarkdownDTO { +class MultiLineTextEntryListMarkdownDto { final String type; final String format; final bool uniqueItems; @@ -295,7 +289,7 @@ class MultiLineTextEntryListMarkdownDTO { @JsonKey(name: 'x-note') final String note; - const MultiLineTextEntryListMarkdownDTO({ + const MultiLineTextEntryListMarkdownDto({ required this.type, required this.format, required this.uniqueItems, @@ -304,17 +298,17 @@ class MultiLineTextEntryListMarkdownDTO { required this.note, }); - factory MultiLineTextEntryListMarkdownDTO.fromJson( + factory MultiLineTextEntryListMarkdownDto.fromJson( Map json, ) => - _$MultiLineTextEntryListMarkdownDTOFromJson(json); + _$MultiLineTextEntryListMarkdownDtoFromJson(json); Map toJson() => - _$MultiLineTextEntryListMarkdownDTOToJson(this); + _$MultiLineTextEntryListMarkdownDtoToJson(this); } @JsonSerializable() -class SingleLineHttpsURLEntryListDTO { +class SingleLineHttpsURLEntryListDto { final String type; final String format; final bool uniqueItems; @@ -324,7 +318,7 @@ class SingleLineHttpsURLEntryListDTO { @JsonKey(name: 'x-note') final String note; - const SingleLineHttpsURLEntryListDTO({ + const SingleLineHttpsURLEntryListDto({ required this.type, required this.format, required this.uniqueItems, @@ -333,14 +327,14 @@ class SingleLineHttpsURLEntryListDTO { required this.note, }); - factory SingleLineHttpsURLEntryListDTO.fromJson(Map json) => - _$SingleLineHttpsURLEntryListDTOFromJson(json); + factory SingleLineHttpsURLEntryListDto.fromJson(Map json) => + _$SingleLineHttpsURLEntryListDtoFromJson(json); - Map toJson() => _$SingleLineHttpsURLEntryListDTOToJson(this); + Map toJson() => _$SingleLineHttpsURLEntryListDtoToJson(this); } @JsonSerializable() -class NestedQuestionsListDTO { +class NestedQuestionsListDto { final String type; final String format; final bool uniqueItems; @@ -349,7 +343,7 @@ class NestedQuestionsListDTO { @JsonKey(name: 'x-note') final String note; - const NestedQuestionsListDTO({ + const NestedQuestionsListDto({ required this.type, required this.format, required this.uniqueItems, @@ -357,136 +351,142 @@ class NestedQuestionsListDTO { required this.note, }); - factory NestedQuestionsListDTO.fromJson(Map json) => - _$NestedQuestionsListDTOFromJson(json); + factory NestedQuestionsListDto.fromJson(Map json) => + _$NestedQuestionsListDtoFromJson(json); - Map toJson() => _$NestedQuestionsListDTOToJson(this); + Map toJson() => _$NestedQuestionsListDtoToJson(this); } @JsonSerializable() -class NestedQuestionsDTO { +class NestedQuestionsDto { final String type; final String format; final bool additionalProperties; @JsonKey(name: 'x-note') final String note; - const NestedQuestionsDTO({ + const NestedQuestionsDto({ required this.type, required this.format, required this.additionalProperties, required this.note, }); - factory NestedQuestionsDTO.fromJson(Map json) => - _$NestedQuestionsDTOFromJson(json); + factory NestedQuestionsDto.fromJson(Map json) => + _$NestedQuestionsDtoFromJson(json); - Map toJson() => _$NestedQuestionsDTOToJson(this); + Map toJson() => _$NestedQuestionsDtoToJson(this); } @JsonSerializable() -class SingleGroupedTagSelectorDTO { +class SingleGroupedTagSelectorDto { final String type; final String format; final bool additionalProperties; @JsonKey(name: 'x-note') final String note; - const SingleGroupedTagSelectorDTO({ + const SingleGroupedTagSelectorDto({ required this.type, required this.format, required this.additionalProperties, required this.note, }); - factory SingleGroupedTagSelectorDTO.fromJson(Map json) => - _$SingleGroupedTagSelectorDTOFromJson(json); + factory SingleGroupedTagSelectorDto.fromJson(Map json) => + _$SingleGroupedTagSelectorDtoFromJson(json); - Map toJson() => _$SingleGroupedTagSelectorDTOToJson(this); + Map toJson() => _$SingleGroupedTagSelectorDtoToJson(this); } @JsonSerializable() -class TagGroupDTO { +class TagGroupDto { final String type; final String format; - final String additionalProperties; + final String pattern; @JsonKey(name: 'x-note') final String note; - const TagGroupDTO({ + const TagGroupDto({ required this.type, required this.format, - required this.additionalProperties, + required this.pattern, required this.note, }); - factory TagGroupDTO.fromJson(Map json) => - _$TagGroupDTOFromJson(json); + factory TagGroupDto.fromJson(Map json) => + _$TagGroupDtoFromJson(json); - Map toJson() => _$TagGroupDTOToJson(this); + Map toJson() => _$TagGroupDtoToJson(this); } @JsonSerializable() -class TagSelectionDTO { +class TagSelectionDto { final String type; final String format; - final String additionalProperties; @JsonKey(name: 'x-note') final String note; - const TagSelectionDTO({ + const TagSelectionDto({ required this.type, required this.format, - required this.additionalProperties, required this.note, }); - factory TagSelectionDTO.fromJson(Map json) => - _$TagSelectionDTOFromJson(json); + factory TagSelectionDto.fromJson(Map json) => + _$TagSelectionDtoFromJson(json); - Map toJson() => _$TagSelectionDTOToJson(this); + Map toJson() => _$TagSelectionDtoToJson(this); } @JsonSerializable() -class TokenValueCardanoAdaDTO { +class TokenValueCardanoAdaDto { final String type; final String format; @JsonKey(name: 'x-note') final String note; - const TokenValueCardanoAdaDTO({ + const TokenValueCardanoAdaDto({ required this.type, required this.format, required this.note, }); - factory TokenValueCardanoAdaDTO.fromJson(Map json) => - _$TokenValueCardanoAdaDTOFromJson(json); + factory TokenValueCardanoAdaDto.fromJson(Map json) => + _$TokenValueCardanoAdaDtoFromJson(json); - Map toJson() => _$TokenValueCardanoAdaDTOToJson(this); + Map toJson() => _$TokenValueCardanoAdaDtoToJson(this); } @JsonSerializable() -class DurationInMonthsDTO { +class DurationInMonthsDto { final String type; final String format; @JsonKey(name: 'x-note') final String note; - const DurationInMonthsDTO({ + const DurationInMonthsDto({ required this.type, required this.format, required this.note, }); - factory DurationInMonthsDTO.fromJson(Map json) => - _$DurationInMonthsDTOFromJson(json); + factory DurationInMonthsDto.fromJson(Map json) => + _$DurationInMonthsDtoFromJson(json); + + Map toJson() => _$DurationInMonthsDtoToJson(this); - Map toJson() => _$DurationInMonthsDTOToJson(this); + DurationInMonthsDefinition toModel() { + return DurationInMonthsDefinition( + type: DefinitionsObjectType.fromString(type), + note: note, + format: DefinitionsFormat.fromString(format), + ); + } } @JsonSerializable() -class YesNoChoiceDTO { +class YesNoChoiceDto { final String type; final String format; @JsonKey(name: 'default') @@ -494,21 +494,21 @@ class YesNoChoiceDTO { @JsonKey(name: 'x-note') final String note; - const YesNoChoiceDTO({ + const YesNoChoiceDto({ required this.type, required this.format, required this.defaultValue, required this.note, }); - factory YesNoChoiceDTO.fromJson(Map json) => - _$YesNoChoiceDTOFromJson(json); + factory YesNoChoiceDto.fromJson(Map json) => + _$YesNoChoiceDtoFromJson(json); - Map toJson() => _$YesNoChoiceDTOToJson(this); + Map toJson() => _$YesNoChoiceDtoToJson(this); } @JsonSerializable() -class AgreementConfirmationDTO { +class AgreementConfirmationDto { final String type; final String format; @JsonKey(name: 'default') @@ -518,7 +518,7 @@ class AgreementConfirmationDTO { @JsonKey(name: 'x-note') final String note; - const AgreementConfirmationDTO({ + const AgreementConfirmationDto({ required this.type, required this.format, required this.defaultValue, @@ -526,31 +526,31 @@ class AgreementConfirmationDTO { required this.note, }); - factory AgreementConfirmationDTO.fromJson(Map json) => - _$AgreementConfirmationDTOFromJson(json); + factory AgreementConfirmationDto.fromJson(Map json) => + _$AgreementConfirmationDtoFromJson(json); - Map toJson() => _$AgreementConfirmationDTOToJson(this); + Map toJson() => _$AgreementConfirmationDtoToJson(this); } @JsonSerializable() -class SPDXLicenceOrUrlDTO { +class SPDXLicenceOrUrlDto { final String type; final String contentMediaType; - final String additionalProperties; + final String pattern; final String format; @JsonKey(name: 'x-note') final String note; - const SPDXLicenceOrUrlDTO({ + const SPDXLicenceOrUrlDto({ required this.type, required this.contentMediaType, - required this.additionalProperties, + required this.pattern, required this.format, required this.note, }); - factory SPDXLicenceOrUrlDTO.fromJson(Map json) => - _$SPDXLicenceOrUrlDTOFromJson(json); + factory SPDXLicenceOrUrlDto.fromJson(Map json) => + _$SPDXLicenceOrUrlDtoFromJson(json); - Map toJson() => _$SPDXLicenceOrUrlDTOToJson(this); + Map toJson() => _$SPDXLicenceOrUrlDtoToJson(this); } diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/schema_dto.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/schema_dto.dart new file mode 100644 index 00000000000..7a7400402fe --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/schema_dto.dart @@ -0,0 +1,359 @@ +import 'package:catalyst_voices_models/catalyst_voices_models.dart'; +import 'package:catalyst_voices_repositories/src/dto/definitions_dto.dart'; +import 'package:catalyst_voices_shared/catalyst_voices_shared.dart'; +import 'package:equatable/equatable.dart'; +import 'package:json_annotation/json_annotation.dart'; + +part 'schema_dto.g.dart'; + +@JsonSerializable() +class SchemaDto extends Equatable { + @JsonKey(name: r'$schema') + final String schema; + @JsonKey(name: r'$id') + final String id; + final String title; + final String description; + final DefinitionsDto definitions; + final String type; + final bool additionalProperties; + @JsonKey(toJson: _toJsonProperties, fromJson: _fromJsonProperties) + final List properties; + @JsonKey(name: 'x-order') + final List order; + @JsonKey(includeToJson: false) + final String propertiesSchema; + + const SchemaDto({ + required this.schema, + required this.id, + required this.title, + required this.description, + required this.definitions, + this.type = 'object', + this.additionalProperties = false, + required this.properties, + required this.order, + required this.propertiesSchema, + }); + + factory SchemaDto.fromJson(Map json) { + final segmentsMap = json['properties'] as Map; + json['propertiesSchema'] = + (segmentsMap[r'$schema'] as Map)['const']; + + return _$SchemaDtoFromJson(json); + } + + Map toJson() => _$SchemaDtoToJson(this); + + Schema toModel() { + final properties = + this.properties.map((e) => e.toModel(definitions.definitions)).toList(); + return Schema( + schema: schema, + title: title, + description: description, + type: DefinitionsObjectType.fromString(type), + additionalProperties: false, + segments: properties, + order: order, + propertiesSchema: propertiesSchema, + ); + } + + @override + List get props => [ + schema, + title, + description, + definitions, + type, + additionalProperties, + properties, + order, + ]; + + static Map _toJsonProperties( + List properties, + ) { + final map = {}; + for (final property in properties) { + map[property.id] = property.toJson(); + } + return map; + } + + static List _fromJsonProperties(Map json) { + final listOfProperties = json.convertMapToListWithIds(); + return listOfProperties.map(SchemaSegmentDto.fromJson).toList(); + } +} + +@JsonSerializable() +class SchemaSegmentDto extends Equatable { + @JsonKey(name: r'$ref') + final String ref; + final String id; + final String title; + final String description; + @JsonKey(toJson: _toJsonProperties, fromJson: _fromJsonProperties) + final List properties; + final List required; + @JsonKey(name: 'x-order') + final List order; + + static late Map orderMap; + + const SchemaSegmentDto({ + required this.ref, + required this.id, + this.title = '', + this.description = '', + required this.properties, + this.required = const [], + this.order = const [], + }); + + factory SchemaSegmentDto.fromJson(Map json) => + _$SchemaSegmentDtoFromJson(json); + + Map toJson() => _$SchemaSegmentDtoToJson(this); + + SchemaSegment toModel(List definitions) { + orderMap = {for (var i = 0; i < order.length; i++) order[i]: i}; + final sortedProperties = List.from(properties)..sort(); + final sections = sortedProperties + .where((element) => element.ref.contains('section')) + .map((e) => e.toModel(definitions, isRequired: required.contains(e.id))) + .toList(); + return SchemaSegment( + ref: definitions.getDefinition(ref), + id: id, + title: title, + description: description, + sections: sections, + ); + } + + @override + List get props => [ + ref, + id, + title, + description, + properties, + required, + order, + ]; + + static Map _toJsonProperties( + List properties, + ) { + final map = {}; + for (final property in properties) { + map[property.id] = property.toJson(); + } + return map; + } + + static List _fromJsonProperties(Map json) { + final listOfProperties = json.convertMapToListWithIds(); + return listOfProperties.map(SchemaSectionDto.fromJson).toList(); + } +} + +@JsonSerializable() +class SchemaSectionDto extends Equatable + implements Comparable { + @JsonKey(name: r'$ref') + final String ref; + final String id; + final String title; + final String description; + @JsonKey(toJson: _toJsonProperties, fromJson: _fromJsonProperties) + final List properties; + final List required; + @JsonKey(name: 'x-order') + final List order; + final Map dependencies; // Return to this + @JsonKey(name: 'if') + final Map ifs; + final Map then; // Return to this + @JsonKey(name: 'open_source') + final Map openSource; // Return to this + + static late Map orderMap; + + const SchemaSectionDto({ + required this.ref, + required this.id, + this.title = '', + this.description = '', + required this.properties, + this.required = const [], + this.order = const [], + this.dependencies = const {}, + this.ifs = const {}, + this.then = const {}, + this.openSource = const {}, + }); + + factory SchemaSectionDto.fromJson(Map json) => + _$SchemaSectionDtoFromJson(json); + + Map toJson() => _$SchemaSectionDtoToJson(this); + + SchemaSection toModel( + List definitions, { + required bool isRequired, + }) { + orderMap = {for (var i = 0; i < order.length; i++) order[i]: i}; + final sortedProperties = List.from(properties)..sort(); + final elements = sortedProperties + // .where((element) => element.ref.contains('section')) + .map((e) => e.toModel(definitions)) + .toList(); + return SchemaSection( + ref: definitions.getDefinition(ref), + id: id, + title: title, + description: description, + elements: elements, + isRequired: isRequired, + ); + } + + @override + List get props => [ + ref, + id, + title, + description, + properties, + required, + order, + dependencies, + ifs, + then, + ]; + + static Map _toJsonProperties( + List properties, + ) { + final map = {}; + for (final property in properties) { + map[property.id] = property.toJson(); + } + return map; + } + + static List _fromJsonProperties(Map json) { + final listOfProperties = json.convertMapToListWithIds(); + return listOfProperties.map(SchemaElementDto.fromJson).toList(); + } + + @override + int compareTo(SchemaSectionDto other) { + final thisIndex = SchemaSegmentDto.orderMap[id] ?? double.maxFinite.toInt(); + final otherIndex = + SchemaSegmentDto.orderMap[other.id] ?? double.maxFinite.toInt(); + return thisIndex.compareTo(otherIndex); + } +} + +@JsonSerializable() +class SchemaElementDto extends Equatable + implements Comparable { + @JsonKey(name: r'$ref') + final String ref; + final String id; + final String title; + final String description; + @JsonKey(includeIfNull: false) + final int? minLength; + @JsonKey(includeIfNull: false) + final int? maxLength; + @JsonKey(name: 'default') + final String defaultValue; + @JsonKey(name: 'x-guidance') + final String guidance; + @JsonKey(name: 'enum') + final List enumValues; + @JsonKey(includeIfNull: false) + final int? maxItems; + @JsonKey(includeIfNull: false) + final int? minItems; + @JsonKey(includeIfNull: false) + final int? minimum; + @JsonKey(includeIfNull: false) + final int? maximum; + final List examples; + final Map items; // TODO(ryszard-shossler): return to this + + const SchemaElementDto({ + this.ref = '', + required this.id, + this.title = '', + this.description = '', + required this.minLength, + required this.maxLength, + this.defaultValue = '', + this.guidance = '', + this.enumValues = const [], + required this.maxItems, + required this.minItems, + required this.minimum, + required this.maximum, + this.examples = const [], + this.items = const {}, + }); + + factory SchemaElementDto.fromJson(Map json) => + _$SchemaElementDtoFromJson(json); + + Map toJson() => _$SchemaElementDtoToJson(this); + + SchemaElement toModel(List definitions) => SchemaElement( + ref: definitions.getDefinition(ref), + id: id, + title: title, + description: description, + minLength: minLength, + maxLength: maxLength, + defaultValue: defaultValue, + guidance: guidance, + enumValues: enumValues, + maxItems: maxItems, + minItems: minItems, + minimum: minimum, + maximum: maximum, + examples: examples, + ); + + @override + List get props => [ + ref, + id, + title, + description, + minLength, + maxLength, + defaultValue, + guidance, + enumValues, + maxItems, + minItems, + minimum, + maximum, + examples, + ]; + + @override + int compareTo(SchemaElementDto other) { + final thisIndex = SchemaSectionDto.orderMap[id] ?? double.maxFinite.toInt(); + final otherIndex = + SchemaSectionDto.orderMap[other.id] ?? double.maxFinite.toInt(); + return thisIndex.compareTo(otherIndex); + } +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/pubspec.yaml b/catalyst_voices/packages/internal/catalyst_voices_repositories/pubspec.yaml index 937dbe004fe..60fe81f45ca 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/pubspec.yaml +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/pubspec.yaml @@ -14,6 +14,7 @@ dependencies: catalyst_voices_shared: path: ../catalyst_voices_shared chopper: ^8.0.3 + equatable: ^2.0.7 flutter: sdk: flutter http: ^1.2.2 diff --git a/catalyst_voices/packages/internal/catalyst_voices_shared/lib/src/extension/list_to_map_ext.dart b/catalyst_voices/packages/internal/catalyst_voices_shared/lib/src/extension/list_to_map_ext.dart deleted file mode 100644 index e69de29bb2d..00000000000 From 4b5487ade380297e32267bdf3ba3f37bdc65b1fc Mon Sep 17 00:00:00 2001 From: Ryszard Schossler Date: Wed, 18 Dec 2024 13:17:02 +0100 Subject: [PATCH 07/18] feat: adding missing toModels for definitions --- .../lib/src/proposal_schema/definitions.dart | 280 +++++++++++++++++- .../test/assets/proposal_builder_output.json | 1 - .../lib/src/dto/definitions_dto.dart | 175 ++++++++++- .../lib/src/dto/schema_dto.dart | 116 +++++--- ...38-9258-4fbc-a62e-7faa6e58318f.schema.json | 0 .../test/assets/generic_proposal copy.json | 0 .../test/assets/generic_proposal.json | 0 .../test}/helpers/read_json.dart | 1 + .../test/src/proposal/proposal_test.dart | 48 +++ 9 files changed, 562 insertions(+), 59 deletions(-) delete mode 100644 catalyst_voices/packages/internal/catalyst_voices_models/test/assets/proposal_builder_output.json rename catalyst_voices/packages/internal/{catalyst_voices_models => catalyst_voices_repositories}/test/assets/0ce8ab38-9258-4fbc-a62e-7faa6e58318f.schema.json (100%) rename catalyst_voices/packages/internal/{catalyst_voices_models => catalyst_voices_repositories}/test/assets/generic_proposal copy.json (100%) rename catalyst_voices/packages/internal/{catalyst_voices_models => catalyst_voices_repositories}/test/assets/generic_proposal.json (100%) rename catalyst_voices/packages/internal/{catalyst_voices_models/test/proposal => catalyst_voices_repositories/test}/helpers/read_json.dart (93%) create mode 100644 catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/proposal/proposal_test.dart diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/definitions.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/definitions.dart index 7880d125947..f2389cbaffc 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/definitions.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/definitions.dart @@ -61,10 +61,8 @@ enum DefinitionsFormat { const DefinitionsFormat(); static DefinitionsFormat fromString(String value) { - return DefinitionsFormat.values.firstWhere( - (type) => type.name == value, - orElse: () => DefinitionsFormat.unknown, - ); + return DefinitionsFormat.values.asNameMap()[value] ?? + DefinitionsFormat.unknown; } } @@ -72,15 +70,34 @@ enum DefinitionsType { section, segment, singleLineTextEntry, - // singleLineHttpsURLEntry, - - // multiLineTextEntry; - durationInMonths; + singleLineHttpsURLEntry, + multiLineTextEntry, + multiLineTextEntryMarkdown, + dropDownSingleSelect, + multiSelect, + singleLineTextEntryList, + multiLineTextEntryListMarkdown, + singleLineHttpsURLEntryList, + nestedQuestionsList, + nestedQuestions, + singleGroupedTagSelector, + tagGroup, + tagSelection, + tokenValueCardanoADA, + durationInMonths, + yesNoChoice, + agreementConfirmation, + spdxLicenseOrURL; const DefinitionsType(); static DefinitionsType fromString(String value) { - return DefinitionsType.values.byName(value); + return values.byName(value); + } + + static bool isKnownType(String refPath) { + final ref = refPath.split('/').last; + return values.asNameMap()[ref] != null; } Object get definitionType => switch (this) { @@ -88,6 +105,24 @@ enum DefinitionsType { segment => SegmentDefinition, singleLineTextEntry => SingleLineTextEntryDefinition, durationInMonths => DurationInMonthsDefinition, + singleLineHttpsURLEntry => SingleLineHttpsURLEntryDefinition, + multiLineTextEntry => MultiLineTextEntryDefinition, + multiLineTextEntryMarkdown => MultiLineTextEntryListMarkdownDefinition, + dropDownSingleSelect => DropDownSingleSelectDefinition, + multiSelect => MultiSelectDefinition, + singleLineTextEntryList => SingleLineTextEntryListDefinition, + multiLineTextEntryListMarkdown => + MultiLineTextEntryListMarkdownDefinition, + singleLineHttpsURLEntryList => SingleLineHttpsURLEntryListDefinition, + nestedQuestionsList => NestedQuestionsListDefinition, + nestedQuestions => NestedQuestionsDefinition, + singleGroupedTagSelector => SingleGroupedTagSelectorDefinition, + tagGroup => TagGroupDefinition, + tagSelection => TagSelectionDefinition, + tokenValueCardanoADA => TokenValueCardanoADADefinition, + yesNoChoice => YesNoChoiceDefinition, + agreementConfirmation => AgreementConfirmationDefinition, + spdxLicenseOrURL => SPDXLicenceOrUrlDefinition, }; } @@ -104,10 +139,10 @@ abstract class BaseDefinition { extension BaseDefinitionListExt on List { BaseDefinition getDefinition(String refPath) { final ref = refPath.split('/').last; - final enum2 = DefinitionsType.fromString(ref); - final obj = enum2.definitionType; + final definitionType = DefinitionsType.fromString(ref); + final classType = definitionType.definitionType; - return firstWhere((e) => e.runtimeType == obj); + return firstWhere((e) => e.runtimeType == classType); } } @@ -143,6 +178,187 @@ class SingleLineTextEntryDefinition extends BaseDefinition { }); } +class SingleLineHttpsURLEntryDefinition extends BaseDefinition { + final DefinitionsFormat format; + final String pattern; + + const SingleLineHttpsURLEntryDefinition({ + required super.type, + required super.note, + required this.format, + required this.pattern, + }); +} + +class MultiLineTextEntryDefinition extends BaseDefinition { + final DefinitionsContentMediaType contentMediaType; + final String pattern; + + const MultiLineTextEntryDefinition({ + required super.type, + required super.note, + required this.contentMediaType, + required this.pattern, + }); +} + +class MultiLineTextEntryMarkdownDefinition extends BaseDefinition { + final DefinitionsContentMediaType contentMediaType; + final String pattern; + + const MultiLineTextEntryMarkdownDefinition({ + required super.type, + required super.note, + required this.contentMediaType, + required this.pattern, + }); +} + +class DropDownSingleSelectDefinition extends BaseDefinition { + final DefinitionsFormat format; + final DefinitionsContentMediaType contentMediaType; + final String pattern; + + const DropDownSingleSelectDefinition({ + required super.type, + required super.note, + required this.format, + required this.contentMediaType, + required this.pattern, + }); +} + +class MultiSelectDefinition extends BaseDefinition { + final DefinitionsFormat format; + final bool uniqueItems; + + const MultiSelectDefinition({ + required super.type, + required super.note, + required this.format, + required this.uniqueItems, + }); +} + +class SingleLineTextEntryListDefinition extends BaseDefinition { + final DefinitionsFormat format; + final bool uniqueItems; + final List defaultValues; + final Map items; + + const SingleLineTextEntryListDefinition({ + required super.type, + required super.note, + required this.format, + required this.uniqueItems, + required this.defaultValues, + required this.items, + }); +} + +class MultiLineTextEntryListMarkdownDefinition extends BaseDefinition { + final DefinitionsFormat format; + final bool uniqueItems; + final List defaultValue; + final Map items; + + const MultiLineTextEntryListMarkdownDefinition({ + required super.type, + required super.note, + required this.format, + required this.uniqueItems, + required this.defaultValue, + required this.items, + }); +} + +class SingleLineHttpsURLEntryListDefinition extends BaseDefinition { + final DefinitionsFormat format; + final bool uniqueItems; + final List defaultValue; + final Map items; + + const SingleLineHttpsURLEntryListDefinition({ + required super.type, + required super.note, + required this.format, + required this.uniqueItems, + required this.defaultValue, + required this.items, + }); +} + +class NestedQuestionsListDefinition extends BaseDefinition { + final DefinitionsFormat format; + final bool uniqueItems; + final List defaultValue; + + const NestedQuestionsListDefinition({ + required super.type, + required super.note, + required this.format, + required this.uniqueItems, + required this.defaultValue, + }); +} + +class NestedQuestionsDefinition extends BaseDefinition { + final DefinitionsFormat format; + final bool additionalProperties; + const NestedQuestionsDefinition({ + required super.type, + required super.note, + required this.format, + required this.additionalProperties, + }); +} + +class SingleGroupedTagSelectorDefinition extends BaseDefinition { + final DefinitionsFormat format; + final bool additionalProperties; + + const SingleGroupedTagSelectorDefinition({ + required super.type, + required super.note, + required this.format, + required this.additionalProperties, + }); +} + +class TagGroupDefinition extends BaseDefinition { + final DefinitionsFormat format; + final String pattern; + + const TagGroupDefinition({ + required super.type, + required super.note, + required this.format, + required this.pattern, + }); +} + +class TagSelectionDefinition extends BaseDefinition { + final DefinitionsFormat format; + final String pattern; + + const TagSelectionDefinition({ + required super.type, + required super.note, + required this.format, + required this.pattern, + }); +} + +class TokenValueCardanoADADefinition extends BaseDefinition { + final DefinitionsFormat format; + + const TokenValueCardanoADADefinition({ + required super.type, + required super.note, + required this.format, + }); +} + class DurationInMonthsDefinition extends BaseDefinition { final DefinitionsFormat format; @@ -152,3 +368,43 @@ class DurationInMonthsDefinition extends BaseDefinition { required this.format, }); } + +class YesNoChoiceDefinition extends BaseDefinition { + final DefinitionsFormat format; + final bool defaultValue; + + const YesNoChoiceDefinition({ + required super.type, + required super.note, + required this.format, + required this.defaultValue, + }); +} + +class AgreementConfirmationDefinition extends BaseDefinition { + final DefinitionsFormat format; + final bool defaultValue; + final bool constValue; + + const AgreementConfirmationDefinition({ + required super.type, + required super.note, + required this.format, + required this.defaultValue, + required this.constValue, + }); +} + +class SPDXLicenceOrUrlDefinition extends BaseDefinition { + final DefinitionsFormat format; + final String pattern; + final DefinitionsContentMediaType contentMediaType; + + const SPDXLicenceOrUrlDefinition({ + required super.type, + required super.note, + required this.format, + required this.pattern, + required this.contentMediaType, + }); +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/test/assets/proposal_builder_output.json b/catalyst_voices/packages/internal/catalyst_voices_models/test/assets/proposal_builder_output.json deleted file mode 100644 index 72450e9c461..00000000000 --- a/catalyst_voices/packages/internal/catalyst_voices_models/test/assets/proposal_builder_output.json +++ /dev/null @@ -1 +0,0 @@ -{"$schema":"http://json-schema.org/draft-07/schema#","$id":"https://cardano.org/schemas/catalyst/f14/proposal","title":"F14 Submission Form","description":"Schema for the F14 Catalyst Proposal Submission Form","definitions":{"segment":{"type":"object","additionalProperties":false,"x-note":"Major sections of the proposal. Each segment contains sections of information grouped together."},"section":{"type":"object","additionalProperties":false,"x-note":"Subsections containing specific details about the proposal."},"singleLineTextEntry":{"type":"string","contentMediaType":"text/plain","pattern":"^.*$","x-note":"Enter a single line of text. No formatting, line breaks, or special characters are allowed."},"singleLineHttpsURLEntry":{"type":"string","format":"uri","pattern":"^https:.*","x-note":"Enter a valid HTTPS URL. Must start with 'https://' and be a complete, working web address."},"multiLineTextEntry":{"type":"string","contentMediaType":"text/plain","pattern":"^[\\S\\s]*$","x-note":"Enter multiple lines of plain text. You can use line breaks but no special formatting."},"multiLineTextEntryMarkdown":{"type":"string","contentMediaType":"text/markdown","pattern":"^[\\S\\s]*$","x-note":"Use Markdown formatting for rich text. Available formatting:\n- Headers: # for h1, ## for h2, etc.\n- Lists: * or - for bullets, 1. for numbered\n- Emphasis: *italic* or **bold**\n- Links: [text](url)\n- Code: `inline` or ```block```"},"dropDownSingleSelect":{"type":"string","contentMediaType":"text/plain","pattern":"^.*$","format":"dropDownSingleSelect","x-note":"Select one option from the dropdown menu. Only one choice is allowed."},"multiSelect":{"type":"array","uniqueItems":true,"format":"multiSelect","x-note":"Select multiple options from the dropdown menu. Multiple choices are allowed."},"singleLineTextEntryList":{"type":"array","format":"singleLineTextEntryList","uniqueItems":true,"default":[],"items":{"$ref":"#/definitions/singleLineTextEntry","maxLength":1024},"x-note":"Add multiple single-line text entries. Each entry should be unique and under 1024 characters."},"multiLineTextEntryListMarkdown":{"type":"array","format":"multiLineTextEntryListMarkdown","uniqueItems":true,"default":[],"items":{"$ref":"#/definitions/multiLineTextEntryMarkdown","maxLength":10240},"x-note":"Add multiple markdown-formatted text entries. Each entry can include rich formatting and should be unique."},"singleLineHttpsURLEntryList":{"type":"array","format":"singleLineHttpsURLEntryList","uniqueItems":true,"default":[],"items":{"$ref":"#/definitions/singleLineHttpsURLEntry","maxLength":1024},"x-note":"Enter multiple HTTPS URLs. Each URL should be unique and under 1024 characters."},"nestedQuestionsList":{"type":"array","format":"nestedQuestionsList","uniqueItems":true,"default":[],"x-note":"Add multiple questions. Each question should be unique."},"nestedQuestions":{"type":"object","format":"nestedQuestions","additionalProperties":false,"x-note":"Add multiple questions. Each question should be unique."},"singleGroupedTagSelector":{"type":"object","format":"singleGroupedTagSelector","additionalProperties":true,"x-note":"Select one option from the dropdown menu. Only one choice is allowed."},"tagGroup":{"type":"string","format":"tagGroup","pattern":"^.*$","x-note":"Select one option from the dropdown menu. Only one choice is allowed."},"tagSelection":{"type":"string","format":"tagSelection","x-note":"Select one option from the dropdown menu. Only one choice is allowed."},"tokenValueCardanoADA":{"type":"integer","format":"token:cardano:ada","x-note":"Enter the amount of Cardano ADA to be used in the proposal."},"durationInMonths":{"type":"integer","format":"datetime:duration:months","x-note":"Enter the duration of the proposal in months."},"yesNoChoice":{"type":"boolean","format":"yesNoChoice","default":false,"x-note":"Select Yes or No."},"agreementConfirmation":{"type":"boolean","format":"agreementConfirmation","default":false,"const":true,"x-note":"Select Yes or No."},"spdxLicenseOrURL":{"type":"string","contentMediaType":"text/plain","pattern":"^.*$","format":"spdxLicenseOrURL","x-note":"Select one option from the dropdown menu. Only one choice is allowed."}},"type":"object","additionalProperties":false,"properties":{"setup":{"$ref":"#/definitions/segment","id":"setup","title":"proposal setup","description":"Proposal title","properties":{"proposer":{"$ref":"#/definitions/section","id":"proposer","title":"","description":"","properties":{"applicant":{"$ref":"#/definitions/singleLineTextEntry","id":"applicant","title":"Name and surname of main applicant","description":"Name and surname of main applicant","minLength":2,"maxLength":100,"default":"","x-guidance":"

Please provide the name and surname of the main applicant. The main applicant is considered as the individual responsible for the project and the person authorized to act on behalf of other applicants (where applicable).

","enum":[],"examples":[],"items":{}},"type":{"$ref":"#/definitions/dropDownSingleSelect","id":"type","title":"Are you delivering this project as an individual or as an entity (whether formally incorporated or not)","description":"Are you delivering this project as an individual or as an entity (whether formally incorporated or not)","default":"Individual","x-guidance":"

Please select from one of the following:

  1. Individual
  2. Entity (Incorporated)
  3. Entity (Not Incorporated)
","enum":["Individual","Entity (Incorporated)","Entity (Not Incorporated)"],"examples":[],"items":{}},"coproposers":{"$ref":"#/definitions/singleLineTextEntryList","id":"coproposers","title":"Co-proposers and additional applicants","description":"Co-proposers and additional applicants","default":"","x-guidance":"

List any persons who are submitting the proposal jointly with the main applicant. Make sure you have confirmed approval/awareness with these individuals/accounts before adding them. If there is more than one proposer, identify the lead person who is authorized to act on behalf of other co-proposers. IMPORTANT A maximum of 6 (six) proposals can be led or co-proposed by the same applicant or enterprise. Please, reference Fund 14 rules for added detail.

","enum":[],"maxItems":5,"minItems":0,"examples":[],"items":{}}},"required":["applicant","type"],"x-order":["applicant","type","coproposers"],"dependencies":{},"if":{},"then":{},"open_source":{}},"title":{"$ref":"#/definitions/section","id":"title","title":"proposal setup","description":"Proposal title","properties":{"title":{"$ref":"#/definitions/singleLineTextEntry","id":"title","title":"Proposal Title","description":"

Proposal title

Please note we suggest you use no more than 60 characters for your proposal title so that it can be easily viewed in the voting app.

","minLength":1,"maxLength":60,"default":"","x-guidance":"

The title should clearly express what the proposal is about. Voters can see the title in the voting app, even without opening the proposal, so a clear, unambiguous, and concise title is very important.

","enum":[],"examples":[],"items":{}}},"required":["title"],"x-order":[],"dependencies":{},"if":{},"then":{},"open_source":{}}},"required":["title","proposer"],"x-order":["title","proposer"]},"summary":{"$ref":"#/definitions/segment","id":"summary","title":"Proposal Summary","description":"Key information about your proposal","properties":{"budget":{"$ref":"#/definitions/section","id":"budget","title":"Budget Information","description":"","properties":{"requestedFunds":{"$ref":"#/definitions/tokenValueCardanoADA","id":"requestedFunds","title":"Requested funds in ADA","description":"The amount of funding requested for your proposal","default":"","x-guidance":"

There is a minimum and a maximum amount of funding that can be requested in a single Catalyst proposal. These are outlined below per each category:

Minimum Funding Amount per proposal:

Cardano Open: A15,000

Cardano Uses Cases: A15,000

Cardano Partners: A500,000

Maximum Funding Amount per proposal:

Cardano Open:

  • Developers (technical): A200,000
  • Ecosystem (non-technical): A100,000

Cardano Uses Cases:

  • Concept A150,000
  • Product: A500,000

Cardano Partners:

  • Enterprise R&D A2,000,000
  • Growth & Acceleration: A2,000,000
","enum":[],"minimum":15000,"maximum":2000000,"examples":[],"items":{}}},"required":["requestedFunds"],"x-order":["requestedFunds"],"dependencies":{},"if":{},"then":{},"open_source":{}},"time":{"$ref":"#/definitions/section","id":"time","title":"","description":"","properties":{"duration":{"$ref":"#/definitions/durationInMonths","id":"duration","title":"Project Duration in Months","description":"Specify the expected duration of your project. Projects must be completable within 2-12 months.","default":"","x-guidance":"

Minimum 2 months-Maximum 12 months. The scope of your funding request and this project is expected to produce the deliverables you specify in the proposal within 2-12 months If you believe your project will take longer than 12 months, consider reducing the project's scope so that it becomes achievable within 12 months If your project completes earlier than scheduled so long as you have submitted your PoAs and Project Close-out report and video then your project can be closed out.

","enum":[],"minimum":2,"maximum":12,"examples":[],"items":{}}},"required":["duration"],"x-order":[],"dependencies":{},"if":{},"then":{},"open_source":{}},"translation":{"$ref":"#/definitions/section","id":"translation","title":"Translation Information","description":"Information about the proposal's language and translation status","properties":{"isTranslated":{"$ref":"#/definitions/yesNoChoice","id":"isTranslated","title":"Auto-translated Status","description":"Indicate if your proposal has been auto-translated into English from another language","default":"","x-guidance":"

Tick YES if your proposal has been auto-translated into English from another language so readers are reminded that your proposal has been translated, and that they should be tolerant of any language imperfections. Tick NO if your proposal has not been auto-translated into English from another language

","enum":[],"examples":[],"items":{}},"originalLanguage":{"$ref":"#/definitions/singleLineTextEntry","id":"originalLanguage","title":"Original Language","description":"If auto-translated, specify the original language of your proposal","default":"","x-guidance":"","enum":["Arabic","Chinese","French","German","Indonesian","Italian","Japanese","Korean","Portuguese","Russian","Spanish","Turkish","Vietnamese","Other"],"examples":[],"items":{}},"originalDocumentLink":{"$ref":"#/definitions/singleLineHttpsURLEntry","id":"originalDocumentLink","title":"Original Document Link","description":"Provide a link to the original proposal document in its original language","default":"","x-guidance":"","enum":[],"examples":[],"items":{}}},"required":["isTranslated"],"x-order":[],"dependencies":{},"if":{"properties":{"isTranslated":{"const":true}}},"then":{"required":["originalLanguage","originalDocumentLink"],"properties":{"originalLanguage":{"description":"Original language is required when the proposal is translated"},"originalDocumentLink":{"description":"Link to the original document is required when the proposal is translated"}}},"open_source":{}},"problem":{"$ref":"#/definitions/section","id":"problem","title":"Problem Statement","description":"Define the problem your proposal aims to solve","properties":{"statement":{"$ref":"#/definitions/multiLineTextEntry","id":"statement","title":"Problem Description","description":"Clearly define the problem you aim to solve. This will be visible in the Catalyst voting app.","minLength":10,"maxLength":200,"default":"","x-guidance":"

Ensure you present a well-defined problem. What is the core issue that you hope to fix? Remember: the reader might not recognize the problem unless you state it clearly. This answer will be displayed on the Catalyst voting app, so voters will see it even if they don't open your proposal to read it in detail.

","enum":[],"examples":[],"items":{}},"impact":{"$ref":"#/definitions/multiSelect","id":"impact","title":"Impact Areas","description":"Select the areas that will be most impacted by solving this problem","default":"","x-guidance":"","enum":[],"maxItems":3,"minItems":1,"examples":[],"items":{"$ref":"#/definitions/singleLineTextEntry","enum":["Technical Infrastructure","User Experience","Developer Tooling","Community Growth","Economic Sustainability","Interoperability","Security","Scalability","Education","Adoption"]}}},"required":["statement","impact"],"x-order":[],"dependencies":{},"if":{},"then":{},"open_source":{}},"solution":{"$ref":"#/definitions/section","id":"solution","title":"Solution Overview","description":"Describe your proposed solution to the problem","properties":{"summary":{"$ref":"#/definitions/multiLineTextEntry","id":"summary","title":"Solution Summary","description":"Briefly describe your solution. Focus on what you will do or create to solve the problem.","minLength":10,"maxLength":200,"default":"","x-guidance":"

Focus on what you are going to do, or make, or change, to solve the problem. So not 'There should be a way to....' but 'We will make a Clearly state how the solution addresses the specific problem you have identified - connect the 'why' and the 'how' This answer will be displayed on the Catalyst voting app, so voters will see it even if they do not open your proposal and read it in detail.

","enum":[],"examples":[],"items":{}},"approach":{"$ref":"#/definitions/multiLineTextEntry","id":"approach","title":"Technical Approach","description":"Outline the technical approach or methodology you will use","maxLength":500,"default":"","x-guidance":"","enum":[],"examples":[],"items":{}},"innovationAspects":{"$ref":"#/definitions/singleLineTextEntryList","id":"innovationAspects","title":"Innovation Aspects","description":"Key innovative aspects of your solution","default":"","x-guidance":"","enum":[],"maxItems":5,"minItems":1,"examples":[],"items":{}}},"required":["summary","approach"],"x-order":[],"dependencies":{},"if":{},"then":{},"open_source":{}},"supportingLinks":{"$ref":"#/definitions/section","id":"supportingLinks","title":"Supporting Documentation","description":"Additional resources and documentation for your proposal","properties":{"mainRepository":{"$ref":"#/definitions/singleLineHttpsURLEntry","id":"mainRepository","title":"Main Code Repository","description":"Primary repository where the project's code will be hosted","default":"","x-guidance":"","enum":[],"examples":[],"items":{}},"documentation":{"$ref":"#/definitions/singleLineHttpsURLEntry","id":"documentation","title":"Documentation URL","description":"Main documentation site or resource for the project","default":"","x-guidance":"","enum":[],"examples":[],"items":{}},"other":{"$ref":"#/definitions/singleLineHttpsURLEntryList","id":"other","title":"Resource Links","description":"Links to any other relevant documentation, code repositories, or marketing materials. All links must use HTTPS.","default":"","x-guidance":"","enum":[],"maxItems":5,"minItems":0,"examples":[],"items":{}}},"required":[],"x-order":[],"dependencies":{},"if":{},"then":{},"open_source":{}},"dependencies":{"$ref":"#/definitions/section","id":"dependencies","title":"Project Dependencies","description":"External dependencies and requirements for project success","properties":{"details":{"$ref":"#/definitions/nestedQuestionsList","id":"details","title":"Dependency Details","description":"List and describe each dependency","default":"","x-guidance":"","enum":[],"maxItems":10,"minItems":0,"examples":[],"items":{"$ref":"#/definitions/nestedQuestions","properties":{"name":{"$ref":"#/definitions/singleLineTextEntry","title":"Dependency Name","description":"Name of the organization, technology, or resource","maxLength":100},"type":{"$ref":"#/definitions/dropDownSingleSelect","title":"Dependency Type","description":"Type of dependency","enum":["Technical","Organizational","Legal","Financial","Other"]},"description":{"$ref":"#/definitions/multiLineTextEntry","title":"Description","description":"Explain why this dependency is essential and how it affects your project","maxLength":500},"mitigationPlan":{"$ref":"#/definitions/multiLineTextEntry","title":"Mitigation Plan","description":"How will you handle potential issues with this dependency","maxLength":300}},"required":["name","type","description"]}}},"required":[],"x-order":[],"dependencies":{},"if":{},"then":{},"open_source":{}},"open_source":{"$ref":"#/definitions/section","id":"open_source","title":"Project Open Source","description":"Will your project's output be fully open source? Open source refers to something people can modify and share because its design is publicly accessible.","properties":{"source_code":{"$ref":"#/definitions/spdxLicenseOrURL","id":"source_code","title":"","description":"","default":"","x-guidance":"","enum":[],"examples":[],"items":{}},"documentation":{"$ref":"#/definitions/spdxLicenseOrURL","id":"documentation","title":"","description":"","default":"","x-guidance":"","enum":[],"examples":[],"items":{}},"note":{"$ref":"#/definitions/multiLineTextEntry","id":"note","title":"More Information","description":"Please provide here more information on the open source status of your project outputs","maxLength":500,"default":"","x-guidance":"

If you did not answer PROPRIETARY to the above questions, the project should be open source available throughout the entire lifecycle of the project with a declared open-source repository. Please indicate here the type of license you intend to use for open source and provide any further information you feel is relevant to the open source status of your project outputs If only certain elements of your code will be open source please clarify which elements will be open source here. If you answered NO to the above question, please give further details as to why your projects outputs will not be open source METADATA

","enum":[],"examples":[],"items":{}}},"required":["source_code","documentation"],"x-order":["source_code","documentation","note"],"dependencies":{},"if":{},"then":{},"open_source":{}}},"required":[],"x-order":["budget","time","translation","problem","solution","supportingLinks","dependencies","open_source"]},"horizons":{"$ref":"#/definitions/segment","id":"horizons","title":"Horizons","description":"","properties":{"theme":{"$ref":"#/definitions/section","id":"theme","title":"Horizons","description":"Long-term vision and categorization of your project","properties":{"grouped_tag":{"$ref":"#/definitions/singleGroupedTagSelector","id":"grouped_tag","title":"","description":"","default":"","x-guidance":"","enum":[],"examples":[],"items":{}}},"required":[],"x-order":["theme"],"dependencies":{},"if":{},"then":{},"open_source":{}}},"required":[],"x-order":["theme"]},"details":{"$ref":"#/definitions/segment","id":"details","title":"Your Project and Solution","description":"","properties":{"solution":{"$ref":"#/definitions/section","id":"solution","title":"Solution","description":"

How you write this section will depend on what type of proposal you are writing. You might want to include details on:


  • How do you perceive the problem you are solving?
  • What are your reasons for approaching it in the way that you have?
  • Who will your project engage?
  • How will you demonstrate or prove your impact?


Explain what is unique about your solution, who will benefit, and why this is important to Cardano.

","properties":{"solution":{"$ref":"#/definitions/multiLineTextEntryMarkdown","id":"solution","title":"","description":"","minLength":1,"maxLength":10240,"default":"","x-guidance":"","enum":[],"examples":["Our solution involves developing a decentralized education platform that will..."],"items":{}}},"required":[],"x-order":[],"dependencies":{},"if":{},"then":{},"open_source":{}},"impact":{"$ref":"#/definitions/section","id":"impact","title":"Impact","description":"

Please include here a description of how you intend to measure impact (whether quantitative or qualitative) and how and with whom you will share your outputs:


  • In what way will the success of your project bring value to the Cardano Community? 
  • How will you measure this impact? 
  • How will you share the outputs and opportunities that result from your project?
","properties":{"impact":{"$ref":"#/definitions/multiLineTextEntryMarkdown","id":"impact","title":"","description":"","minLength":1,"maxLength":10240,"default":"","x-guidance":"","enum":[],"examples":[],"items":{}}},"required":[],"x-order":[],"dependencies":{},"if":{},"then":{},"open_source":{}},"feasibility":{"$ref":"#/definitions/section","id":"feasibility","title":"Capabilities & Feasibility","description":"

Please describe your existing capabilities that demonstrate how and why you believe you’re best suited to deliver this project?

Please include the steps or processes that demonstrate that you can be trusted to manage funds properly.

","properties":{"feasibility":{"$ref":"#/definitions/multiLineTextEntryMarkdown","id":"feasibility","title":"","description":"","minLength":1,"maxLength":10240,"default":"","x-guidance":"","enum":[],"examples":[],"items":{}}},"required":[],"x-order":[],"dependencies":{},"if":{},"then":{},"open_source":{}}},"required":[],"x-order":["solution","impact","feasibility"]},"milestones":{"$ref":"#/definitions/segment","id":"milestones","title":"Milestones","description":"","properties":{"milestones":{"$ref":"#/definitions/section","id":"milestones","title":"Project Milestones","description":"

Each milestone must declare:

  • A: Milestone outputs
  • B: Acceptance criteria
  • C: Evidence of completion

Requirements:

  • For Grant Amounts up to 75k ada: minimum 3 milestones (2 + final)
  • For Grant Amounts 75k-150k ada: minimum 4 milestones (3 + final)
  • The final milestone must include Project Close-out Report and Video
","properties":{"milestone_list":{"$ref":"","id":"milestone_list","title":"Milestones","description":"What are the key milestones you need to achieve in order to complete your project successfully?","default":"","x-guidance":"

Milestone Requirements:

  • For Grant Amounts of up to 75k ada: at least 2 milestones, plus the final one including Project Close-out Report and Video, must be included (3 milestones in total)
  • For Grant Amounts over 75k ada up to 150k ada: at least 3 milestones, plus the final one including Project Close-out Report and Video, must be included (4 milestones in total)
  • For Grant Amounts over 150k ada up to 300k ada: at least 4 milestones, plus the final one including Project Close-out Report and Video, must be included (5 milestones in total)
  • For Grant Amounts exceeding 300k ada: at least 5 milestones, plus the final one including Project Close-out Report and Video, must be included (6 milestones in total)
","enum":[],"maxItems":6,"minItems":3,"examples":[],"items":{"type":"object","required":["title","outputs","acceptance_criteria","evidence","delivery_month","cost"],"properties":{"title":{"$ref":"#/definitions/singleLineTextEntry","title":"Milestone Title","description":"A clear, concise title for this milestone","maxLength":100},"outputs":{"$ref":"#/definitions/multiLineTextEntryMarkdown","title":"Milestone Outputs","description":"What will be delivered in this milestone","maxLength":1000},"acceptance_criteria":{"$ref":"#/definitions/multiLineTextEntryMarkdown","title":"Acceptance Criteria","description":"Specific conditions that must be met","maxLength":1000},"evidence":{"$ref":"#/definitions/multiLineTextEntryMarkdown","title":"Evidence of Completion","description":"How you will demonstrate achievement","maxLength":1000},"delivery_month":{"$ref":"#/definitions/durationInMonths","title":"Delivery Month","description":"The month when this milestone will be delivered","minimum":1,"maximum":12},"cost":{"$ref":"#/definitions/tokenValueCardanoADA","title":"Cost in ADA","description":"The cost of this milestone in ADA"},"progress":{"$ref":"#/definitions/dropDownSingleSelect","title":"Progress Status","description":"Current status of the milestone","enum":["Not Started","In Progress","Completed","Delayed"],"default":"Not Started"}}}}},"required":["milestone_list"],"x-order":[],"dependencies":{},"if":{},"then":{},"open_source":{}}},"required":[],"x-order":["milestones"]},"pitch":{"$ref":"#/definitions/segment","id":"pitch","title":"Final Pitch","description":"","properties":{"team":{"$ref":"#/definitions/section","id":"team","title":"Team","description":"","properties":{"who":{"$ref":"#/definitions/multiLineTextEntryMarkdown","id":"who","title":"Who is in the project team and what are their roles?","description":"

List your team, their Linkedin profiles (or similar) and state what aspect of the proposal’s work each team member will undertake.


If you are planning to recruit additional team members, please state what specific skills you will be looking for in the people you recruit, so readers can see that you understand what skills will be needed to complete the project.


You are expected to have already engaged the relevant members of the organizations referenced so you understand if they are willing and/or have capacity to support the project. If you have not taken any steps to engage with your team yet, it is likely that the resources will not be available if you are approved for funding, which can jeopardize the project before it has even begun. The Catalyst team cannot help with this, meaning you are expected to have understood the requirements and engaged the necessary people before submitting a proposal.


Have you engaged anyone on any of the technical group channels (eg Discord or Telegram), or do you have a direct line of communications with the people and resources required?


Important: Catalyst funding is not anonymous, and some level of ‘proof of life’ verifications will take place before initial funding is released. Also remember that your proposal will be publicly available, so make sure to obtain any consent required before including confidential or third party information.


All Project Participants must disclose their role and scope of services across any submitted proposals, even if they are not in the lead or co-proposer role, such as an implementer, vendor, service provider, etc. Failure to disclose this information may lead to disqualification from the current grant round.

","minLength":1,"maxLength":10240,"default":"","x-guidance":"","enum":[],"examples":[],"items":{}}},"required":[],"x-order":[],"dependencies":{},"if":{},"then":{},"open_source":{}},"budget":{"$ref":"#/definitions/section","id":"budget","title":"Budget & Costs","description":"","properties":{"costs":{"$ref":"#/definitions/multiLineTextEntryMarkdown","id":"costs","title":"Please provide a cost breakdown of the proposed work and resources","description":"

Make sure every element mentioned in your plan reflects its cost. It may be helpful to refer to your plan and timeline, list all the resources you will need at each stage, and what they cost.


Here, provide a clear description of any third party product or service you will be using. This could be hardware, software licenses, professional services (legal, accounting, code auditing, etc) but does not need to include the use of contracted programmers and developers.


The exact budget elements you include will depend on what type of work you are doing, and you might need to give less detail for a small, low-budget proposal. If the cost of the project will exceed the funding request, please provide information about alternative sources of funding.


Consider including budget elements for publicity / marketing / promotion / community engagement; project management; documentation; and reporting back to the community. Most proposals need these, but many proposers forget to include them.


It is the project team’s responsibility to properly manage the funds provided. Make sure to reference Fund Rules to understand eligibility around costs.

","minLength":1,"maxLength":10240,"default":"","x-guidance":"","enum":[],"examples":[],"items":{}}},"required":[],"x-order":[],"dependencies":{},"if":{},"then":{},"open_source":{}},"value":{"$ref":"#/definitions/section","id":"value","title":"Value for Money","description":"","properties":{"note":{"$ref":"#/definitions/multiLineTextEntryMarkdown","id":"note","title":"How does the cost of the project represent value for money for the Cardano ecosystem?","description":"

Use the response to provide the context about the costs you listed previously, particularly if they are high.


It may be helpful to include some brief information on how you have decided on the costs of the project. 


For instance, can you justify with supporting evidence that costs are proportional to the average wage in your country, or typical freelance rates in your industry? Is there anything else that helps to support how the project represents value for money?

","minLength":1,"maxLength":10240,"default":"","x-guidance":"","enum":[],"examples":[],"items":{}}},"required":[],"x-order":[],"dependencies":{},"if":{},"then":{},"open_source":{}}},"required":[],"x-order":["team","budget","value"]},"agreements":{"$ref":"#/definitions/segment","id":"agreements","title":"Acknowledgements","description":"","properties":{"mandatory":{"$ref":"#/definitions/section","id":"mandatory","title":"Mandatory","description":"","properties":{"fund_rules":{"$ref":"#/definitions/agreementConfirmation","id":"fund_rules","title":"Fund Rules:","description":"

By submitting a proposal to Project Catalyst Fund14, I confirm that I have read and agree to be bound by the Fund Rules.

","default":"","x-guidance":"","enum":[],"examples":[],"items":{}},"terms_and_conditions":{"$ref":"#/definitions/agreementConfirmation","id":"terms_and_conditions","title":"Terms and Conditions:","description":"

By submitting a proposal to Project Catalyst Fund14, I confirm that I have read and agree to be bound by the Project Catalyst Terms and Conditions.

","default":"","x-guidance":"","enum":[],"examples":[],"items":{}},"privacy_policy":{"$ref":"#/definitions/agreementConfirmation","id":"privacy_policy","title":"Privacy Policy: ","description":"

I acknowledge and agree that any data I share in connection with my participation in Project Catalyst Fund14 will be collected, stored, used and processed in accordance with the Catalyst FC’s Privacy Policy.

","default":"","x-guidance":"","enum":[],"examples":[],"items":{}}},"required":["fund_rules","terms_and_conditions","privacy_policy"],"x-order":["fund_rules","terms_and_conditions","privacy_policy"],"dependencies":{},"if":{},"then":{},"open_source":{}}},"required":[],"x-order":["mandatory"]}},"x-order":["setup","summary","horizons","details","milestones","pitch","agreements"]} \ No newline at end of file diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/definitions_dto.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/definitions_dto.dart index 88eb5d653f7..97a26fd2a35 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/definitions_dto.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/definitions_dto.dart @@ -1,4 +1,4 @@ -import 'package:catalyst_voices_models/src/proposal_schema/definitions.dart'; +import 'package:catalyst_voices_models/catalyst_voices_models.dart'; import 'package:json_annotation/json_annotation.dart'; part 'definitions_dto.g.dart'; @@ -62,7 +62,23 @@ class DefinitionsDto { segment.toModel(), section.toModel(), singleLineTextEntry.toModel(), + multiLineTextEntry.toModel(), + multiLineTextEntryMarkdown.toModel(), + dropDownSingleSelect.toModel(), + multiSelect.toModel(), + singleLineTextEntryList.toModel(), + multiLineTextEntryListMarkdown.toModel(), + singleLineHttpsURLEntryList.toModel(), + nestedQuestionsList.toModel(), + nestedQuestions.toModel(), + singleGroupedTagSelector.toModel(), + tagGroup.toModel(), + tagSelection.toModel(), + tokenValueCardanoAda.toModel(), durationInMonths.toModel(), + yesNoChoice.toModel(), + agreementConfirmation.toModel(), + spdxLicenceOrUrl.toModel(), ]; } @@ -164,6 +180,15 @@ class SingleLineHttpsURLEntryDto { _$SingleLineHttpsURLEntryDtoFromJson(json); Map toJson() => _$SingleLineHttpsURLEntryDtoToJson(this); + + SingleLineHttpsURLEntryDefinition toModel() { + return SingleLineHttpsURLEntryDefinition( + type: DefinitionsObjectType.fromString(type), + note: note, + format: DefinitionsFormat.fromString(format), + pattern: pattern, + ); + } } @JsonSerializable() @@ -185,6 +210,16 @@ class MultiLineTextEntryDto { _$MultiLineTextEntryDtoFromJson(json); Map toJson() => _$MultiLineTextEntryDtoToJson(this); + + MultiLineTextEntryDefinition toModel() { + return MultiLineTextEntryDefinition( + type: DefinitionsObjectType.fromString(type), + note: note, + contentMediaType: + DefinitionsContentMediaType.fromString(contentMediaType), + pattern: pattern, + ); + } } @JsonSerializable() @@ -206,6 +241,16 @@ class MultiLineTextEntryMarkdownDto { _$MultiLineTextEntryMarkdownDtoFromJson(json); Map toJson() => _$MultiLineTextEntryMarkdownDtoToJson(this); + + MultiLineTextEntryMarkdownDefinition toModel() { + return MultiLineTextEntryMarkdownDefinition( + type: DefinitionsObjectType.fromString(type), + note: note, + contentMediaType: + DefinitionsContentMediaType.fromString(contentMediaType), + pattern: pattern, + ); + } } @JsonSerializable() @@ -229,6 +274,17 @@ class DropDownSingleSelectDto { _$DropDownSingleSelectDtoFromJson(json); Map toJson() => _$DropDownSingleSelectDtoToJson(this); + + DropDownSingleSelectDefinition toModel() { + return DropDownSingleSelectDefinition( + type: DefinitionsObjectType.fromString(type), + note: note, + contentMediaType: + DefinitionsContentMediaType.fromString(contentMediaType), + pattern: pattern, + format: DefinitionsFormat.fromString(format), + ); + } } @JsonSerializable() @@ -250,6 +306,15 @@ class MultiSelectDto { _$MultiSelectDtoFromJson(json); Map toJson() => _$MultiSelectDtoToJson(this); + + MultiSelectDefinition toModel() { + return MultiSelectDefinition( + type: DefinitionsObjectType.fromString(type), + note: note, + format: DefinitionsFormat.fromString(format), + uniqueItems: uniqueItems, + ); + } } @JsonSerializable() @@ -258,7 +323,7 @@ class SingleLineTextEntryListDto { final String format; final bool uniqueItems; @JsonKey(name: 'default') - final List defaultValue; + final List defaultValue; final Map items; @JsonKey(name: 'x-note') final String note; @@ -276,6 +341,16 @@ class SingleLineTextEntryListDto { _$SingleLineTextEntryListDtoFromJson(json); Map toJson() => _$SingleLineTextEntryListDtoToJson(this); + + SingleLineTextEntryListDefinition toModel() => + SingleLineTextEntryListDefinition( + type: DefinitionsObjectType.fromString(type), + note: note, + format: DefinitionsFormat.fromString(format), + uniqueItems: uniqueItems, + defaultValues: defaultValue, + items: items, + ); } @JsonSerializable() @@ -305,6 +380,16 @@ class MultiLineTextEntryListMarkdownDto { Map toJson() => _$MultiLineTextEntryListMarkdownDtoToJson(this); + + MultiLineTextEntryListMarkdownDefinition toModel() => + MultiLineTextEntryListMarkdownDefinition( + type: DefinitionsObjectType.fromString(type), + note: note, + format: DefinitionsFormat.fromString(format), + uniqueItems: uniqueItems, + defaultValue: defaultValue, + items: items, + ); } @JsonSerializable() @@ -331,6 +416,16 @@ class SingleLineHttpsURLEntryListDto { _$SingleLineHttpsURLEntryListDtoFromJson(json); Map toJson() => _$SingleLineHttpsURLEntryListDtoToJson(this); + + SingleLineHttpsURLEntryListDefinition toModel() => + SingleLineHttpsURLEntryListDefinition( + type: DefinitionsObjectType.fromString(type), + note: note, + format: DefinitionsFormat.fromString(format), + uniqueItems: uniqueItems, + defaultValue: defaultValue, + items: items, + ); } @JsonSerializable() @@ -355,6 +450,14 @@ class NestedQuestionsListDto { _$NestedQuestionsListDtoFromJson(json); Map toJson() => _$NestedQuestionsListDtoToJson(this); + + NestedQuestionsListDefinition toModel() => NestedQuestionsListDefinition( + type: DefinitionsObjectType.fromString(type), + note: note, + format: DefinitionsFormat.fromString(format), + uniqueItems: uniqueItems, + defaultValue: defaultValue, + ); } @JsonSerializable() @@ -376,6 +479,15 @@ class NestedQuestionsDto { _$NestedQuestionsDtoFromJson(json); Map toJson() => _$NestedQuestionsDtoToJson(this); + + NestedQuestionsDefinition toModel() { + return NestedQuestionsDefinition( + type: DefinitionsObjectType.fromString(type), + note: note, + format: DefinitionsFormat.fromString(format), + additionalProperties: additionalProperties, + ); + } } @JsonSerializable() @@ -397,6 +509,15 @@ class SingleGroupedTagSelectorDto { _$SingleGroupedTagSelectorDtoFromJson(json); Map toJson() => _$SingleGroupedTagSelectorDtoToJson(this); + + SingleGroupedTagSelectorDefinition toModel() { + return SingleGroupedTagSelectorDefinition( + type: DefinitionsObjectType.fromString(type), + note: note, + format: DefinitionsFormat.fromString(format), + additionalProperties: additionalProperties, + ); + } } @JsonSerializable() @@ -418,18 +539,29 @@ class TagGroupDto { _$TagGroupDtoFromJson(json); Map toJson() => _$TagGroupDtoToJson(this); + + TagGroupDefinition toModel() { + return TagGroupDefinition( + type: DefinitionsObjectType.fromString(type), + note: note, + format: DefinitionsFormat.fromString(format), + pattern: pattern, + ); + } } @JsonSerializable() class TagSelectionDto { final String type; final String format; + final String pattern; @JsonKey(name: 'x-note') final String note; const TagSelectionDto({ required this.type, required this.format, + required this.pattern, required this.note, }); @@ -437,6 +569,15 @@ class TagSelectionDto { _$TagSelectionDtoFromJson(json); Map toJson() => _$TagSelectionDtoToJson(this); + + TagSelectionDefinition toModel() { + return TagSelectionDefinition( + type: DefinitionsObjectType.fromString(type), + note: note, + format: DefinitionsFormat.fromString(format), + pattern: pattern, + ); + } } @JsonSerializable() @@ -456,6 +597,12 @@ class TokenValueCardanoAdaDto { _$TokenValueCardanoAdaDtoFromJson(json); Map toJson() => _$TokenValueCardanoAdaDtoToJson(this); + + TokenValueCardanoADADefinition toModel() => TokenValueCardanoADADefinition( + type: DefinitionsObjectType.fromString(type), + note: note, + format: DefinitionsFormat.fromString(format), + ); } @JsonSerializable() @@ -505,6 +652,13 @@ class YesNoChoiceDto { _$YesNoChoiceDtoFromJson(json); Map toJson() => _$YesNoChoiceDtoToJson(this); + + YesNoChoiceDefinition toModel() => YesNoChoiceDefinition( + type: DefinitionsObjectType.fromString(type), + note: note, + format: DefinitionsFormat.fromString(format), + defaultValue: defaultValue, + ); } @JsonSerializable() @@ -530,6 +684,14 @@ class AgreementConfirmationDto { _$AgreementConfirmationDtoFromJson(json); Map toJson() => _$AgreementConfirmationDtoToJson(this); + + AgreementConfirmationDefinition toModel() => AgreementConfirmationDefinition( + type: DefinitionsObjectType.fromString(type), + note: note, + format: DefinitionsFormat.fromString(format), + defaultValue: defaultValue, + constValue: constValue, + ); } @JsonSerializable() @@ -553,4 +715,13 @@ class SPDXLicenceOrUrlDto { _$SPDXLicenceOrUrlDtoFromJson(json); Map toJson() => _$SPDXLicenceOrUrlDtoToJson(this); + + SPDXLicenceOrUrlDefinition toModel() => SPDXLicenceOrUrlDefinition( + type: DefinitionsObjectType.fromString(type), + note: note, + format: DefinitionsFormat.fromString(format), + pattern: pattern, + contentMediaType: + DefinitionsContentMediaType.fromString(contentMediaType), + ); } diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/schema_dto.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/schema_dto.dart index 7a7400402fe..be3ecda48d5 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/schema_dto.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/schema_dto.dart @@ -17,13 +17,19 @@ class SchemaDto extends Equatable { final DefinitionsDto definitions; final String type; final bool additionalProperties; - @JsonKey(toJson: _toJsonProperties, fromJson: _fromJsonProperties) - final List properties; + @JsonKey( + toJson: _toJsonProperties, + fromJson: _fromJsonProperties, + name: 'properties', + ) + final List segments; @JsonKey(name: 'x-order') final List order; @JsonKey(includeToJson: false) final String propertiesSchema; + static late Map orderMap; + const SchemaDto({ required this.schema, required this.id, @@ -32,7 +38,7 @@ class SchemaDto extends Equatable { required this.definitions, this.type = 'object', this.additionalProperties = false, - required this.properties, + required this.segments, required this.order, required this.propertiesSchema, }); @@ -48,15 +54,19 @@ class SchemaDto extends Equatable { Map toJson() => _$SchemaDtoToJson(this); Schema toModel() { - final properties = - this.properties.map((e) => e.toModel(definitions.definitions)).toList(); + orderMap = {for (var i = 0; i < order.length; i++) order[i]: i}; + final sortedProperties = List.from(this.segments)..sort(); + final segments = sortedProperties + .where((e) => e.id.contains('segment')) + .map((e) => e.toModel(definitions.definitions)) + .toList(); return Schema( schema: schema, title: title, description: description, type: DefinitionsObjectType.fromString(type), additionalProperties: false, - segments: properties, + segments: segments, order: order, propertiesSchema: propertiesSchema, ); @@ -70,35 +80,40 @@ class SchemaDto extends Equatable { definitions, type, additionalProperties, - properties, + segments, order, ]; static Map _toJsonProperties( - List properties, + List segments, ) { final map = {}; - for (final property in properties) { + for (final property in segments) { map[property.id] = property.toJson(); } return map; } static List _fromJsonProperties(Map json) { - final listOfProperties = json.convertMapToListWithIds(); - return listOfProperties.map(SchemaSegmentDto.fromJson).toList(); + final listOfSegments = json.convertMapToListWithIds(); + return listOfSegments.map(SchemaSegmentDto.fromJson).toList(); } } @JsonSerializable() -class SchemaSegmentDto extends Equatable { +class SchemaSegmentDto extends Equatable + implements Comparable { @JsonKey(name: r'$ref') final String ref; final String id; final String title; final String description; - @JsonKey(toJson: _toJsonProperties, fromJson: _fromJsonProperties) - final List properties; + @JsonKey( + toJson: _toJsonProperties, + fromJson: _fromJsonProperties, + name: 'properties', + ) + final List sections; final List required; @JsonKey(name: 'x-order') final List order; @@ -110,7 +125,7 @@ class SchemaSegmentDto extends Equatable { required this.id, this.title = '', this.description = '', - required this.properties, + required this.sections, this.required = const [], this.order = const [], }); @@ -122,7 +137,7 @@ class SchemaSegmentDto extends Equatable { SchemaSegment toModel(List definitions) { orderMap = {for (var i = 0; i < order.length; i++) order[i]: i}; - final sortedProperties = List.from(properties)..sort(); + final sortedProperties = List.from(this.sections)..sort(); final sections = sortedProperties .where((element) => element.ref.contains('section')) .map((e) => e.toModel(definitions, isRequired: required.contains(e.id))) @@ -142,24 +157,31 @@ class SchemaSegmentDto extends Equatable { id, title, description, - properties, + sections, required, order, ]; static Map _toJsonProperties( - List properties, + List sections, ) { final map = {}; - for (final property in properties) { + for (final property in sections) { map[property.id] = property.toJson(); } return map; } static List _fromJsonProperties(Map json) { - final listOfProperties = json.convertMapToListWithIds(); - return listOfProperties.map(SchemaSectionDto.fromJson).toList(); + final listOfSections = json.convertMapToListWithIds(); + return listOfSections.map(SchemaSectionDto.fromJson).toList(); + } + + @override + int compareTo(SchemaSegmentDto other) { + final thisIndex = SchemaDto.orderMap[id] ?? double.maxFinite.toInt(); + final otherIndex = SchemaDto.orderMap[other.id] ?? double.maxFinite.toInt(); + return thisIndex.compareTo(otherIndex); } } @@ -171,8 +193,12 @@ class SchemaSectionDto extends Equatable final String id; final String title; final String description; - @JsonKey(toJson: _toJsonProperties, fromJson: _fromJsonProperties) - final List properties; + @JsonKey( + toJson: _toJsonProperties, + fromJson: _fromJsonProperties, + name: 'properties', + ) + final List elements; final List required; @JsonKey(name: 'x-order') final List order; @@ -190,7 +216,7 @@ class SchemaSectionDto extends Equatable required this.id, this.title = '', this.description = '', - required this.properties, + required this.elements, this.required = const [], this.order = const [], this.dependencies = const {}, @@ -209,9 +235,9 @@ class SchemaSectionDto extends Equatable required bool isRequired, }) { orderMap = {for (var i = 0; i < order.length; i++) order[i]: i}; - final sortedProperties = List.from(properties)..sort(); - final elements = sortedProperties - // .where((element) => element.ref.contains('section')) + final sortedElements = List.from(this.elements)..sort(); + final elements = sortedElements + .where((element) => DefinitionsType.isKnownType(element.ref)) .map((e) => e.toModel(definitions)) .toList(); return SchemaSection( @@ -230,7 +256,7 @@ class SchemaSectionDto extends Equatable id, title, description, - properties, + elements, required, order, dependencies, @@ -314,22 +340,24 @@ class SchemaElementDto extends Equatable Map toJson() => _$SchemaElementDtoToJson(this); - SchemaElement toModel(List definitions) => SchemaElement( - ref: definitions.getDefinition(ref), - id: id, - title: title, - description: description, - minLength: minLength, - maxLength: maxLength, - defaultValue: defaultValue, - guidance: guidance, - enumValues: enumValues, - maxItems: maxItems, - minItems: minItems, - minimum: minimum, - maximum: maximum, - examples: examples, - ); + SchemaElement toModel(List definitions) { + return SchemaElement( + ref: definitions.getDefinition(ref), + id: id, + title: title, + description: description, + minLength: minLength, + maxLength: maxLength, + defaultValue: defaultValue, + guidance: guidance, + enumValues: enumValues, + maxItems: maxItems, + minItems: minItems, + minimum: minimum, + maximum: maximum, + examples: examples, + ); + } @override List get props => [ diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/test/assets/0ce8ab38-9258-4fbc-a62e-7faa6e58318f.schema.json b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/assets/0ce8ab38-9258-4fbc-a62e-7faa6e58318f.schema.json similarity index 100% rename from catalyst_voices/packages/internal/catalyst_voices_models/test/assets/0ce8ab38-9258-4fbc-a62e-7faa6e58318f.schema.json rename to catalyst_voices/packages/internal/catalyst_voices_repositories/test/assets/0ce8ab38-9258-4fbc-a62e-7faa6e58318f.schema.json diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/test/assets/generic_proposal copy.json b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/assets/generic_proposal copy.json similarity index 100% rename from catalyst_voices/packages/internal/catalyst_voices_models/test/assets/generic_proposal copy.json rename to catalyst_voices/packages/internal/catalyst_voices_repositories/test/assets/generic_proposal copy.json diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/test/assets/generic_proposal.json b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/assets/generic_proposal.json similarity index 100% rename from catalyst_voices/packages/internal/catalyst_voices_models/test/assets/generic_proposal.json rename to catalyst_voices/packages/internal/catalyst_voices_repositories/test/assets/generic_proposal.json diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/test/proposal/helpers/read_json.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/helpers/read_json.dart similarity index 93% rename from catalyst_voices/packages/internal/catalyst_voices_models/test/proposal/helpers/read_json.dart rename to catalyst_voices/packages/internal/catalyst_voices_repositories/test/helpers/read_json.dart index 982db98a6ba..94013b434ab 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_models/test/proposal/helpers/read_json.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/helpers/read_json.dart @@ -6,5 +6,6 @@ String readJson(String name) { if (dir.endsWith('/test')) { dir = dir.replaceAll('/test', ''); } + print(dir); return File('$dir/$name').readAsStringSync(); } diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/proposal/proposal_test.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/proposal/proposal_test.dart new file mode 100644 index 00000000000..3e6394e20db --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/proposal/proposal_test.dart @@ -0,0 +1,48 @@ +import 'dart:convert'; + +import 'package:catalyst_voices_repositories/src/dto/schema_dto.dart'; +import 'package:test/test.dart'; + +import '../../helpers/read_json.dart'; + +void main() { + const schemaPath = + 'test/assets/0ce8ab38-9258-4fbc-a62e-7faa6e58318f.schema.json'; + + late Map schemaJson; + + setUpAll(() { + schemaJson = json.decode(readJson(schemaPath)) as Map; + }); + + test('X-order of segments is kept in model class', () async { + final schemaDto = SchemaDto.fromJson(schemaJson); + + final schema = schemaDto.toModel(); + + if (schemaDto.order.length != schema.segments.length) { + return; + } + for (var i = 0; i < schema.segments.length; i++) { + expect(schema.segments[i].id, schemaDto.order[i]); + } + }); + + test('X-order of section is kept in model class', () { + final schemaDto = SchemaDto.fromJson(schemaJson); + final schema = schemaDto.toModel(); + + for (var i = 0; i < schema.segments.length; i++) { + if (schemaDto.segments[i].order.length != + schema.segments[i].sections.length) { + continue; + } + for (var j = 0; j < schema.segments[i].sections.length; j++) { + expect( + schema.segments[i].sections[j].id, + schemaDto.segments[i].order[j], + ); + } + } + }); +} From e5f765ceda9405bea9710f7bf82aa6e4444436fa Mon Sep 17 00:00:00 2001 From: Ryszard Schossler Date: Wed, 18 Dec 2024 15:00:20 +0100 Subject: [PATCH 08/18] fix: delete unused property from element class --- .config/dictionaries/project.dic | 3 +++ .../lib/src/proposal_schema/schema.dart | 4 ---- .../lib/src/dto/schema_dto.dart | 7 ++----- .../0ce8ab38-9258-4fbc-a62e-7faa6e58318f.schema.json | 4 +--- .../test/helpers/read_json.dart | 1 - 5 files changed, 6 insertions(+), 13 deletions(-) diff --git a/.config/dictionaries/project.dic b/.config/dictionaries/project.dic index 9c91a6abac4..044eb6c3833 100644 --- a/.config/dictionaries/project.dic +++ b/.config/dictionaries/project.dic @@ -52,12 +52,14 @@ chrono ciphertext ciphertexts CIPs +CNFT COCOAPODS codegen codepoints collabs commitlog concatcp +coproposers COSE coti coverallsapp @@ -111,6 +113,7 @@ gethostname Gitbook gmtime gradlew +Hackathons headful headlessui HIDPI diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/schema.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/schema.dart index 6ad49deccc5..c80d27b00af 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/schema.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/schema.dart @@ -70,9 +70,6 @@ class SchemaElement { final int? minItems; final int? minimum; final int? maximum; - // Sample JSON values associated with a particular schema, - // for the purpose of illustrating usage. - final List examples; const SchemaElement({ required this.ref, @@ -88,6 +85,5 @@ class SchemaElement { this.minItems, this.minimum, this.maximum, - this.examples = const [], }); } diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/schema_dto.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/schema_dto.dart index be3ecda48d5..491a8504fe1 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/schema_dto.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/schema_dto.dart @@ -314,8 +314,8 @@ class SchemaElementDto extends Equatable final int? minimum; @JsonKey(includeIfNull: false) final int? maximum; - final List examples; - final Map items; // TODO(ryszard-shossler): return to this + // TODO(ryszard-schossler): return to this + final Map items; const SchemaElementDto({ this.ref = '', @@ -331,7 +331,6 @@ class SchemaElementDto extends Equatable required this.minItems, required this.minimum, required this.maximum, - this.examples = const [], this.items = const {}, }); @@ -355,7 +354,6 @@ class SchemaElementDto extends Equatable minItems: minItems, minimum: minimum, maximum: maximum, - examples: examples, ); } @@ -374,7 +372,6 @@ class SchemaElementDto extends Equatable minItems, minimum, maximum, - examples, ]; @override diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/assets/0ce8ab38-9258-4fbc-a62e-7faa6e58318f.schema.json b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/assets/0ce8ab38-9258-4fbc-a62e-7faa6e58318f.schema.json index d92a2281bc1..5f15a790ecd 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/assets/0ce8ab38-9258-4fbc-a62e-7faa6e58318f.schema.json +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/assets/0ce8ab38-9258-4fbc-a62e-7faa6e58318f.schema.json @@ -842,9 +842,7 @@ "$ref": "#/definitions/multiLineTextEntryMarkdown", "minLength": 1, "maxLength": 10240, - "examples": [ - "Our solution involves developing a decentralized education platform that will..." - ] + "x-guidance": "Our solution involves developing a decentralized education platform that will..." } } }, diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/helpers/read_json.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/helpers/read_json.dart index 94013b434ab..982db98a6ba 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/helpers/read_json.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/helpers/read_json.dart @@ -6,6 +6,5 @@ String readJson(String name) { if (dir.endsWith('/test')) { dir = dir.replaceAll('/test', ''); } - print(dir); return File('$dir/$name').readAsStringSync(); } From f696fb4ece1c1e4ca711decf9739af6f1835f16c Mon Sep 17 00:00:00 2001 From: Ryszard Schossler Date: Thu, 19 Dec 2024 11:46:04 +0100 Subject: [PATCH 09/18] feat: creating generic_proposal.json --- .../lib/src/catalyst_voices_models.dart | 1 + .../lib/src/proposal_schema/definitions.dart | 6 +-- .../lib/src/proposal_schema/schema.dart | 4 -- .../lib/src/dto/definitions_dto.dart | 1 + .../lib/src/dto/schema_dto.dart | 7 +--- ...38-9258-4fbc-a62e-7faa6e58318f.schema.json | 39 +++++++++---------- 6 files changed, 25 insertions(+), 33 deletions(-) diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/catalyst_voices_models.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/catalyst_voices_models.dart index c1af5e088cd..052a7062817 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/catalyst_voices_models.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/catalyst_voices_models.dart @@ -16,6 +16,7 @@ export 'proposal/proposal.dart'; export 'proposal/proposal_section.dart'; export 'proposal/proposal_template.dart'; export 'proposal_schema/definitions.dart'; +export 'proposal_schema/proposal_builder.dart'; export 'proposal_schema/schema.dart'; export 'registration/registration.dart'; export 'seed_phrase.dart'; diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/definitions.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/definitions.dart index f2389cbaffc..0909e2380e8 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/definitions.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/definitions.dart @@ -67,16 +67,16 @@ enum DefinitionsFormat { } enum DefinitionsType { - section, segment, + section, singleLineTextEntry, - singleLineHttpsURLEntry, multiLineTextEntry, multiLineTextEntryMarkdown, dropDownSingleSelect, multiSelect, singleLineTextEntryList, multiLineTextEntryListMarkdown, + singleLineHttpsURLEntry, singleLineHttpsURLEntryList, nestedQuestionsList, nestedQuestions, @@ -107,7 +107,7 @@ enum DefinitionsType { durationInMonths => DurationInMonthsDefinition, singleLineHttpsURLEntry => SingleLineHttpsURLEntryDefinition, multiLineTextEntry => MultiLineTextEntryDefinition, - multiLineTextEntryMarkdown => MultiLineTextEntryListMarkdownDefinition, + multiLineTextEntryMarkdown => MultiLineTextEntryMarkdownDefinition, dropDownSingleSelect => DropDownSingleSelectDefinition, multiSelect => MultiSelectDefinition, singleLineTextEntryList => SingleLineTextEntryListDefinition, diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/schema.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/schema.dart index c80d27b00af..e982ae0fac6 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/schema.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/schema.dart @@ -4,8 +4,6 @@ class Schema { final String schema; final String title; final String description; - final DefinitionsObjectType type; - final bool additionalProperties; final List segments; final List order; final String propertiesSchema; @@ -14,8 +12,6 @@ class Schema { required this.schema, required this.title, required this.description, - required this.type, - required this.additionalProperties, required this.segments, required this.order, required this.propertiesSchema, diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/definitions_dto.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/definitions_dto.dart index 97a26fd2a35..b087a3b8a10 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/definitions_dto.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/definitions_dto.dart @@ -68,6 +68,7 @@ class DefinitionsDto { multiSelect.toModel(), singleLineTextEntryList.toModel(), multiLineTextEntryListMarkdown.toModel(), + singleLineHttpsURLEntry.toModel(), singleLineHttpsURLEntryList.toModel(), nestedQuestionsList.toModel(), nestedQuestions.toModel(), diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/schema_dto.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/schema_dto.dart index 491a8504fe1..373d4f50b28 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/schema_dto.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/schema_dto.dart @@ -57,15 +57,13 @@ class SchemaDto extends Equatable { orderMap = {for (var i = 0; i < order.length; i++) order[i]: i}; final sortedProperties = List.from(this.segments)..sort(); final segments = sortedProperties - .where((e) => e.id.contains('segment')) + .where((e) => e.ref.contains('segment')) .map((e) => e.toModel(definitions.definitions)) .toList(); return Schema( schema: schema, title: title, description: description, - type: DefinitionsObjectType.fromString(type), - additionalProperties: false, segments: segments, order: order, propertiesSchema: propertiesSchema, @@ -202,7 +200,6 @@ class SchemaSectionDto extends Equatable final List required; @JsonKey(name: 'x-order') final List order; - final Map dependencies; // Return to this @JsonKey(name: 'if') final Map ifs; final Map then; // Return to this @@ -219,7 +216,6 @@ class SchemaSectionDto extends Equatable required this.elements, this.required = const [], this.order = const [], - this.dependencies = const {}, this.ifs = const {}, this.then = const {}, this.openSource = const {}, @@ -259,7 +255,6 @@ class SchemaSectionDto extends Equatable elements, required, order, - dependencies, ifs, then, ]; diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/assets/0ce8ab38-9258-4fbc-a62e-7faa6e58318f.schema.json b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/assets/0ce8ab38-9258-4fbc-a62e-7faa6e58318f.schema.json index 5f15a790ecd..fbf5d568942 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/assets/0ce8ab38-9258-4fbc-a62e-7faa6e58318f.schema.json +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/assets/0ce8ab38-9258-4fbc-a62e-7faa6e58318f.schema.json @@ -186,6 +186,24 @@ "title": "proposal setup", "description": "Proposal title", "properties": { + "title": { + "$ref": "#/definitions/section", + "title": "proposal setup", + "description": "Proposal title", + "properties": { + "title": { + "$ref": "#/definitions/singleLineTextEntry", + "title": "Proposal Title", + "description": "

Proposal title

Please note we suggest you use no more than 60 characters for your proposal title so that it can be easily viewed in the voting app.

", + "minLength": 1, + "maxLength": 60, + "x-guidance": "

The title should clearly express what the proposal is about. Voters can see the title in the voting app, even without opening the proposal, so a clear, unambiguous, and concise title is very important.

" + } + }, + "required": [ + "title" + ] + }, "proposer": { "$ref": "#/definitions/section", "properties": { @@ -227,24 +245,6 @@ "type", "coproposers" ] - }, - "title": { - "$ref": "#/definitions/section", - "title": "proposal setup", - "description": "Proposal title", - "properties": { - "title": { - "$ref": "#/definitions/singleLineTextEntry", - "title": "Proposal Title", - "description": "

Proposal title

Please note we suggest you use no more than 60 characters for your proposal title so that it can be easily viewed in the voting app.

", - "minLength": 1, - "maxLength": 60, - "x-guidance": "

The title should clearly express what the proposal is about. Voters can see the title in the voting app, even without opening the proposal, so a clear, unambiguous, and concise title is very important.

" - } - }, - "required": [ - "title" - ] } }, "required": [ @@ -841,8 +841,7 @@ "solution": { "$ref": "#/definitions/multiLineTextEntryMarkdown", "minLength": 1, - "maxLength": 10240, - "x-guidance": "Our solution involves developing a decentralized education platform that will..." + "maxLength": 10240 } } }, From 2ad36ca62434d97fe9b0fdd101317c9d2df71612 Mon Sep 17 00:00:00 2001 From: Ryszard Schossler Date: Thu, 19 Dec 2024 14:28:02 +0100 Subject: [PATCH 10/18] test: adding unit tests --- .../schema_definition/schema_definition.dart | 34 ++++ .../lib/src/proposal_schema/definitions.dart | 164 +++++++++++------- .../lib/src/dto/definitions_dto.dart | 2 +- .../lib/src/dto/schema_dto.dart | 4 +- .../test/helpers/read_json.dart | 1 + .../test/src/proposal/definitions_test.dart | 36 ++++ .../test/src/proposal/proposal_test.dart | 10 ++ 7 files changed, 184 insertions(+), 67 deletions(-) create mode 100644 catalyst_voices/apps/voices/lib/widgets/schema_definition/schema_definition.dart create mode 100644 catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/proposal/definitions_test.dart diff --git a/catalyst_voices/apps/voices/lib/widgets/schema_definition/schema_definition.dart b/catalyst_voices/apps/voices/lib/widgets/schema_definition/schema_definition.dart new file mode 100644 index 00000000000..388bfc9a529 --- /dev/null +++ b/catalyst_voices/apps/voices/lib/widgets/schema_definition/schema_definition.dart @@ -0,0 +1,34 @@ +import 'package:catalyst_voices_models/catalyst_voices_models.dart'; +import 'package:flutter/material.dart'; + +class SchemaDefinition extends StatelessWidget { + final BaseDefinition definition; + const SchemaDefinition({super.key, required this.definition}); + + @override + Widget build(BuildContext context) { + return switch (definition) { + SegmentDefinition() => throw UnimplementedError(), + SectionDefinition() => throw UnimplementedError(), + SingleLineTextEntryDefinition() => throw UnimplementedError(), + SingleLineHttpsURLEntryDefinition() => throw UnimplementedError(), + MultiLineTextEntryDefinition() => throw UnimplementedError(), + MultiLineTextEntryMarkdownDefinition() => throw UnimplementedError(), + DropDownSingleSelectDefinition() => throw UnimplementedError(), + MultiSelectDefinition() => throw UnimplementedError(), + SingleLineTextEntryListDefinition() => throw UnimplementedError(), + MultiLineTextEntryListMarkdownDefinition() => throw UnimplementedError(), + SingleLineHttpsURLEntryListDefinition() => throw UnimplementedError(), + NestedQuestionsListDefinition() => throw UnimplementedError(), + NestedQuestionsDefinition() => throw UnimplementedError(), + SingleGroupedTagSelectorDefinition() => throw UnimplementedError(), + TagGroupDefinition() => throw UnimplementedError(), + TagSelectionDefinition() => throw UnimplementedError(), + TokenValueCardanoADADefinition() => throw UnimplementedError(), + DurationInMonthsDefinition() => throw UnimplementedError(), + YesNoChoiceDefinition() => throw UnimplementedError(), + AgreementConfirmationDefinition() => throw UnimplementedError(), + SPDXLicenceOrUrlDefinition() => throw UnimplementedError(), + }; + } +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/definitions.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/definitions.dart index 0909e2380e8..43a36e13f2b 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/definitions.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/definitions.dart @@ -1,3 +1,5 @@ +import 'package:meta/meta.dart'; + enum DefinitionsObjectType { string, object, @@ -66,67 +68,67 @@ enum DefinitionsFormat { } } -enum DefinitionsType { - segment, - section, - singleLineTextEntry, - multiLineTextEntry, - multiLineTextEntryMarkdown, - dropDownSingleSelect, - multiSelect, - singleLineTextEntryList, - multiLineTextEntryListMarkdown, - singleLineHttpsURLEntry, - singleLineHttpsURLEntryList, - nestedQuestionsList, - nestedQuestions, - singleGroupedTagSelector, - tagGroup, - tagSelection, - tokenValueCardanoADA, - durationInMonths, - yesNoChoice, - agreementConfirmation, - spdxLicenseOrURL; - - const DefinitionsType(); - - static DefinitionsType fromString(String value) { - return values.byName(value); - } - - static bool isKnownType(String refPath) { - final ref = refPath.split('/').last; - return values.asNameMap()[ref] != null; - } - - Object get definitionType => switch (this) { - section => SectionDefinition, - segment => SegmentDefinition, - singleLineTextEntry => SingleLineTextEntryDefinition, - durationInMonths => DurationInMonthsDefinition, - singleLineHttpsURLEntry => SingleLineHttpsURLEntryDefinition, - multiLineTextEntry => MultiLineTextEntryDefinition, - multiLineTextEntryMarkdown => MultiLineTextEntryMarkdownDefinition, - dropDownSingleSelect => DropDownSingleSelectDefinition, - multiSelect => MultiSelectDefinition, - singleLineTextEntryList => SingleLineTextEntryListDefinition, - multiLineTextEntryListMarkdown => - MultiLineTextEntryListMarkdownDefinition, - singleLineHttpsURLEntryList => SingleLineHttpsURLEntryListDefinition, - nestedQuestionsList => NestedQuestionsListDefinition, - nestedQuestions => NestedQuestionsDefinition, - singleGroupedTagSelector => SingleGroupedTagSelectorDefinition, - tagGroup => TagGroupDefinition, - tagSelection => TagSelectionDefinition, - tokenValueCardanoADA => TokenValueCardanoADADefinition, - yesNoChoice => YesNoChoiceDefinition, - agreementConfirmation => AgreementConfirmationDefinition, - spdxLicenseOrURL => SPDXLicenceOrUrlDefinition, - }; -} - -abstract class BaseDefinition { +// enum DefinitionsType { +// segment, +// section, +// singleLineTextEntry, +// multiLineTextEntry, +// multiLineTextEntryMarkdown, +// dropDownSingleSelect, +// multiSelect, +// singleLineTextEntryList, +// multiLineTextEntryListMarkdown, +// singleLineHttpsURLEntry, +// singleLineHttpsURLEntryList, +// nestedQuestionsList, +// nestedQuestions, +// singleGroupedTagSelector, +// tagGroup, +// tagSelection, +// tokenValueCardanoADA, +// durationInMonths, +// yesNoChoice, +// agreementConfirmation, +// spdxLicenseOrURL; + +// const DefinitionsType(); + +// static DefinitionsType fromString(String value) { +// return values.byName(value); +// } + +// static bool isKnownType(String refPath) { +// final ref = refPath.split('/').last; +// return values.asNameMap()[ref] != null; +// } + +// Object get definitionType => switch (this) { +// section => SectionDefinition, +// segment => SegmentDefinition, +// singleLineTextEntry => SingleLineTextEntryDefinition, +// durationInMonths => DurationInMonthsDefinition, +// singleLineHttpsURLEntry => SingleLineHttpsURLEntryDefinition, +// multiLineTextEntry => MultiLineTextEntryDefinition, +// multiLineTextEntryMarkdown => MultiLineTextEntryMarkdownDefinition, +// dropDownSingleSelect => DropDownSingleSelectDefinition, +// multiSelect => MultiSelectDefinition, +// singleLineTextEntryList => SingleLineTextEntryListDefinition, +// multiLineTextEntryListMarkdown => +// MultiLineTextEntryListMarkdownDefinition, +// singleLineHttpsURLEntryList => SingleLineHttpsURLEntryListDefinition, +// nestedQuestionsList => NestedQuestionsListDefinition, +// nestedQuestions => NestedQuestionsDefinition, +// singleGroupedTagSelector => SingleGroupedTagSelectorDefinition, +// tagGroup => TagGroupDefinition, +// tagSelection => TagSelectionDefinition, +// tokenValueCardanoADA => TokenValueCardanoADADefinition, +// yesNoChoice => YesNoChoiceDefinition, +// agreementConfirmation => AgreementConfirmationDefinition, +// spdxLicenseOrURL => SPDXLicenceOrUrlDefinition, +// }; +// } + +sealed class BaseDefinition { final DefinitionsObjectType type; final String note; @@ -134,13 +136,47 @@ abstract class BaseDefinition { required this.type, required this.note, }); + @visibleForTesting + static final Map refPathToDefinitionType = { + 'segment': SegmentDefinition, + 'section': SectionDefinition, + 'singleLineTextEntry': SingleLineTextEntryDefinition, + 'singleLineHttpsURLEntry': SingleLineHttpsURLEntryDefinition, + 'multiLineTextEntry': MultiLineTextEntryDefinition, + 'multiLineTextEntryMarkdown': MultiLineTextEntryMarkdownDefinition, + 'dropDownSingleSelect': DropDownSingleSelectDefinition, + 'multiSelect': MultiSelectDefinition, + 'singleLineTextEntryList': SingleLineTextEntryListDefinition, + 'multiLineTextEntryListMarkdown': MultiLineTextEntryListMarkdownDefinition, + 'singleLineHttpsURLEntryList': SingleLineHttpsURLEntryListDefinition, + 'nestedQuestionsList': NestedQuestionsListDefinition, + 'nestedQuestions': NestedQuestionsDefinition, + 'singleGroupedTagSelector': SingleGroupedTagSelectorDefinition, + 'tagGroup': TagGroupDefinition, + 'tagSelection': TagSelectionDefinition, + 'tokenValueCardanoADA': TokenValueCardanoADADefinition, + 'durationInMonths': DurationInMonthsDefinition, + 'yesNoChoice': YesNoChoiceDefinition, + 'agreementConfirmation': AgreementConfirmationDefinition, + 'spdxLicenseOrURL': SPDXLicenceOrUrlDefinition, + }; + + static Type typeFromRefPath(String refPath) { + final ref = refPath.split('/').last; + return refPathToDefinitionType[ref] ?? + (throw ArgumentError('Unknown refPath: $refPath')); + } + + static bool isKnownType(String refPath) { + final ref = refPath.split('/').last; + return refPathToDefinitionType[ref] != null; + } } extension BaseDefinitionListExt on List { BaseDefinition getDefinition(String refPath) { - final ref = refPath.split('/').last; - final definitionType = DefinitionsType.fromString(ref); - final classType = definitionType.definitionType; + final definitionType = BaseDefinition.typeFromRefPath(refPath); + final classType = definitionType; return firstWhere((e) => e.runtimeType == classType); } diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/definitions_dto.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/definitions_dto.dart index b087a3b8a10..db2d03d151b 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/definitions_dto.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/definitions_dto.dart @@ -58,7 +58,7 @@ class DefinitionsDto { Map toJson() => _$DefinitionsDtoToJson(this); - List get definitions => [ + List get definitionsModels => [ segment.toModel(), section.toModel(), singleLineTextEntry.toModel(), diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/schema_dto.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/schema_dto.dart index 373d4f50b28..9acc8ddf187 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/schema_dto.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/schema_dto.dart @@ -58,7 +58,7 @@ class SchemaDto extends Equatable { final sortedProperties = List.from(this.segments)..sort(); final segments = sortedProperties .where((e) => e.ref.contains('segment')) - .map((e) => e.toModel(definitions.definitions)) + .map((e) => e.toModel(definitions.definitionsModels)) .toList(); return Schema( schema: schema, @@ -233,7 +233,7 @@ class SchemaSectionDto extends Equatable orderMap = {for (var i = 0; i < order.length; i++) order[i]: i}; final sortedElements = List.from(this.elements)..sort(); final elements = sortedElements - .where((element) => DefinitionsType.isKnownType(element.ref)) + .where((element) => BaseDefinition.isKnownType(element.ref)) .map((e) => e.toModel(definitions)) .toList(); return SchemaSection( diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/helpers/read_json.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/helpers/read_json.dart index 982db98a6ba..94013b434ab 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/helpers/read_json.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/helpers/read_json.dart @@ -6,5 +6,6 @@ String readJson(String name) { if (dir.endsWith('/test')) { dir = dir.replaceAll('/test', ''); } + print(dir); return File('$dir/$name').readAsStringSync(); } diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/proposal/definitions_test.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/proposal/definitions_test.dart new file mode 100644 index 00000000000..54ac986d8b8 --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/proposal/definitions_test.dart @@ -0,0 +1,36 @@ +import 'dart:convert'; + +import 'package:catalyst_voices_models/catalyst_voices_models.dart'; +import 'package:catalyst_voices_repositories/src/dto/schema_dto.dart'; +import 'package:test/test.dart'; + +import '../../helpers/read_json.dart'; + +void main() { + const schemaPath = + 'test/assets/0ce8ab38-9258-4fbc-a62e-7faa6e58318f.schema.json'; + + late Map schemaJson; + + setUpAll(() { + schemaJson = json.decode(readJson(schemaPath)) as Map; + }); + test( + // ignore: lines_longer_than_80_chars + 'Check if all definition are in definition list inside DefinitionDto model', + () async { + final schemaDto = SchemaDto.fromJson(schemaJson); + final definitions = schemaDto.definitions.definitionsModels; + + for (final value in BaseDefinition.refPathToDefinitionType.values) { + final occurrences = + definitions.where((element) => element.runtimeType == value).length; + expect( + occurrences, + equals(1), + reason: 'Value $value appears $occurrences times in the list', + ); + } + }, + ); +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/proposal/proposal_test.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/proposal/proposal_test.dart index 3e6394e20db..a1896d191db 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/proposal/proposal_test.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/proposal/proposal_test.dart @@ -1,5 +1,6 @@ import 'dart:convert'; +import 'package:catalyst_voices_models/catalyst_voices_models.dart'; import 'package:catalyst_voices_repositories/src/dto/schema_dto.dart'; import 'package:test/test.dart'; @@ -45,4 +46,13 @@ void main() { } } }); + + test('Check if every segment has a SegmentDefinition as ref', () { + final schemaDto = SchemaDto.fromJson(schemaJson); + final schema = schemaDto.toModel(); + + for (final segment in schema.segments) { + expect(segment.ref, isA()); + } + }); } From 15fd551e19527efd9845bedb54d5892f4b07242e Mon Sep 17 00:00:00 2001 From: Ryszard Schossler Date: Fri, 20 Dec 2024 10:55:47 +0100 Subject: [PATCH 11/18] feat: range class for easier representation for max min values --- .../lib/src/proposal_schema/schema.dart | 13 +++++-------- .../lib/src/dto/schema_dto.dart | 6 ++---- .../test/helpers/read_json.dart | 1 - .../lib/src/catalyst_voices_shared.dart | 1 + .../catalyst_voices_shared/lib/src/range/range.dart | 13 +++++++++++++ 5 files changed, 21 insertions(+), 13 deletions(-) create mode 100644 catalyst_voices/packages/internal/catalyst_voices_shared/lib/src/range/range.dart diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/schema.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/schema.dart index e982ae0fac6..a3f536c2e8f 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/schema.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/schema.dart @@ -1,4 +1,5 @@ import 'package:catalyst_voices_models/src/proposal_schema/definitions.dart'; +import 'package:catalyst_voices_shared/catalyst_voices_shared.dart'; class Schema { final String schema; @@ -62,10 +63,8 @@ class SchemaElement { final String? defaultValue; final String guidance; final List enumValues; - final int? maxItems; - final int? minItems; - final int? minimum; - final int? maximum; + final Range? range; + final Range? itemsRange; const SchemaElement({ required this.ref, @@ -77,9 +76,7 @@ class SchemaElement { required this.defaultValue, required this.guidance, this.enumValues = const [], - this.maxItems, - this.minItems, - this.minimum, - this.maximum, + required this.range, + required this.itemsRange, }); } diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/schema_dto.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/schema_dto.dart index 9acc8ddf187..cbf915267f0 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/schema_dto.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/schema_dto.dart @@ -345,10 +345,8 @@ class SchemaElementDto extends Equatable defaultValue: defaultValue, guidance: guidance, enumValues: enumValues, - maxItems: maxItems, - minItems: minItems, - minimum: minimum, - maximum: maximum, + range: Range.createIntRange(min: minimum, max: maximum), + itemsRange: Range.createIntRange(min: minItems, max: maxItems), ); } diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/helpers/read_json.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/helpers/read_json.dart index 94013b434ab..982db98a6ba 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/helpers/read_json.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/helpers/read_json.dart @@ -6,6 +6,5 @@ String readJson(String name) { if (dir.endsWith('/test')) { dir = dir.replaceAll('/test', ''); } - print(dir); return File('$dir/$name').readAsStringSync(); } diff --git a/catalyst_voices/packages/internal/catalyst_voices_shared/lib/src/catalyst_voices_shared.dart b/catalyst_voices/packages/internal/catalyst_voices_shared/lib/src/catalyst_voices_shared.dart index 52804fec5dc..03659712b47 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_shared/lib/src/catalyst_voices_shared.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_shared/lib/src/catalyst_voices_shared.dart @@ -18,6 +18,7 @@ export 'keychain/vault_keychain_provider.dart'; export 'logging/logging_service.dart'; export 'platform/catalyst_platform.dart'; export 'platform_aware_builder/platform_aware_builder.dart'; +export 'range/range.dart'; export 'responsive/responsive_builder.dart'; export 'responsive/responsive_child.dart'; export 'responsive/responsive_padding.dart'; diff --git a/catalyst_voices/packages/internal/catalyst_voices_shared/lib/src/range/range.dart b/catalyst_voices/packages/internal/catalyst_voices_shared/lib/src/range/range.dart new file mode 100644 index 00000000000..667644805c2 --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_shared/lib/src/range/range.dart @@ -0,0 +1,13 @@ +class Range { + final T min; + final T max; + + const Range({required this.min, required this.max}); + + static Range? createIntRange({int? min, int? max}) { + if (min == null || max == null) { + return null; + } + return Range(min: min, max: max); + } +} From 5ed4e8c8cb07e73fbc3e50191f744b5fc791aa73 Mon Sep 17 00:00:00 2001 From: Ryszard Schossler Date: Fri, 20 Dec 2024 12:19:16 +0100 Subject: [PATCH 12/18] feat: adding proper from/to Json for proposal_builder class --- .../src/proposal_schema/proposal_builder.dart | 49 ---- .../lib/generated/api/client_index.dart | 1 - .../lib/src/dto/proposal_builder_dto.dart | 213 ++++++++++++++++++ .../src/proposal/proposal_builder_test.dart | 49 ++++ .../definitions_test.dart | 0 .../schema_test.dart} | 0 .../lib/src/extension/map_to_list_ext.dart | 14 ++ 7 files changed, 276 insertions(+), 50 deletions(-) create mode 100644 catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/proposal_builder_dto.dart create mode 100644 catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/proposal/proposal_builder_test.dart rename catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/{proposal => schema}/definitions_test.dart (100%) rename catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/{proposal/proposal_test.dart => schema/schema_test.dart} (100%) diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/proposal_builder.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/proposal_builder.dart index e9e2ea3db62..05c7365568b 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/proposal_builder.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/proposal_builder.dart @@ -1,9 +1,6 @@ import 'package:catalyst_voices_models/src/proposal_schema/schema.dart'; import 'package:json_annotation/json_annotation.dart'; -part 'proposal_builder.g.dart'; - -@JsonSerializable() class ProposalBuilder { final String schema; final List segments; @@ -40,20 +37,8 @@ class ProposalBuilder { .toList(), ); } - - factory ProposalBuilder.fromJson(Map json) => - _$ProposalBuilderFromJson(json); - - Map toJson() { - final sections = {}..addAll({r'$schema': schema}); - for (final section in segments) { - sections.addAll(section.toJson()); - } - return sections; - } } -@JsonSerializable() class ProposalBuilderSegment { final String id; final List sections; @@ -62,19 +47,6 @@ class ProposalBuilderSegment { required this.id, required this.sections, }); - - factory ProposalBuilderSegment.fromJson(Map json) => - _$ProposalBuilderSegmentFromJson(json); - - Map toJson() { - final sections = {}; - for (final section in this.sections) { - sections.addAll(section.toJson()); - } - return { - id: sections, - }; - } } @JsonSerializable() @@ -86,22 +58,8 @@ class ProposalBuilderSection { required this.id, required this.elements, }); - - factory ProposalBuilderSection.fromJson(Map json) => - _$ProposalBuilderSectionFromJson(json); - - Map toJson() { - final map = {}; - for (final element in elements) { - map.addAll(element.toJson()); - } - return { - id: map, - }; - } } -@JsonSerializable() class ProposalBuilderElement { final String id; final dynamic value; @@ -110,11 +68,4 @@ class ProposalBuilderElement { required this.id, required this.value, }); - - factory ProposalBuilderElement.fromJson(Map json) => - _$ProposalBuilderElementFromJson(json); - - Map toJson() => { - id: value, - }; } diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/generated/api/client_index.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/generated/api/client_index.dart index 098d50371d2..ab84c6e02bb 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/generated/api/client_index.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/generated/api/client_index.dart @@ -1,2 +1 @@ -export 'cat_gateway.swagger.dart' show CatGateway; export 'vit.swagger.dart' show Vit; diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/proposal_builder_dto.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/proposal_builder_dto.dart new file mode 100644 index 00000000000..24025d05219 --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/proposal_builder_dto.dart @@ -0,0 +1,213 @@ +import 'package:catalyst_voices_models/catalyst_voices_models.dart'; +import 'package:catalyst_voices_shared/catalyst_voices_shared.dart'; +import 'package:json_annotation/json_annotation.dart'; + +part 'proposal_builder_dto.g.dart'; + +@JsonSerializable() +class ProposalBuilderDto { + @JsonKey(name: r'$schema') + final String schema; + @JsonKey(fromJson: _fromJsonSegments, toJson: _toJsonSegments) + final List segments; + const ProposalBuilderDto({ + required this.schema, + required this.segments, + }); + + factory ProposalBuilderDto.fromJson(Map json) { + json['segments'] = Map.from(json)..remove(r'$schema'); + return _$ProposalBuilderDtoFromJson(json); + } + + factory ProposalBuilderDto.fromModel(ProposalBuilder model) { + return ProposalBuilderDto( + schema: model.schema, + segments: + model.segments.map(ProposalBuilderSegmentDto.fromModel).toList(), + ); + } + + Map toJson() { + final segments = {}..addAll({r'$schema': schema}); + for (final segment in this.segments) { + segments.addAll(segment.toJson()); + } + return segments; + } + + ProposalBuilder toModel() { + return ProposalBuilder( + schema: schema, + segments: segments.map((e) => e.toModel()).toList(), + ); + } + + static Map _toJsonSegments( + List segments, + ) { + final map = {}; + for (final segment in segments) { + map[segment.id] = segment.toJson(); + } + return map; + } + + static List _fromJsonSegments( + Map json, + ) { + final listOfSegments = json.convertMapToListWithIds(); + return listOfSegments.map(ProposalBuilderSegmentDto.fromJson).toList(); + } +} + +@JsonSerializable() +class ProposalBuilderSegmentDto { + final String id; + @JsonKey(fromJson: _fromJsonSections, toJson: _toJsonSections) + final List sections; + + const ProposalBuilderSegmentDto({ + required this.id, + required this.sections, + }); + + factory ProposalBuilderSegmentDto.fromJson(Map json) { + json['sections'] = Map.from(json)..remove('id'); + return _$ProposalBuilderSegmentDtoFromJson(json); + } + + factory ProposalBuilderSegmentDto.fromModel(ProposalBuilderSegment model) { + return ProposalBuilderSegmentDto( + id: model.id, + sections: + model.sections.map(ProposalBuilderSectionDto.fromModel).toList(), + ); + } + + Map toJson() { + final sections = {}; + for (final section in this.sections) { + sections.addAll(section.toJson()); + } + return { + id: sections, + }; + } + + ProposalBuilderSegment toModel() { + return ProposalBuilderSegment( + id: id, + sections: sections.map((e) => e.toModel()).toList(), + ); + } + + static Map _toJsonSections( + List sections, + ) { + final map = {}; + for (final section in sections) { + map[section.id] = section.toJson(); + } + return map; + } + + static List _fromJsonSections( + Map json, + ) { + final listOfSections = json.convertMapToListWithIds(); + return listOfSections.map(ProposalBuilderSectionDto.fromJson).toList(); + } +} + +@JsonSerializable() +class ProposalBuilderSectionDto { + final String id; + @JsonKey(fromJson: _fromJsonElements, toJson: _toJsonElements) + final List elements; + + ProposalBuilderSectionDto({ + required this.id, + required this.elements, + }); + + factory ProposalBuilderSectionDto.fromJson(Map json) { + json['elements'] = Map.from(json)..remove('id'); + return _$ProposalBuilderSectionDtoFromJson(json); + } + + factory ProposalBuilderSectionDto.fromModel(ProposalBuilderSection model) { + return ProposalBuilderSectionDto( + id: model.id, + elements: + model.elements.map(ProposalBuilderElementDto.fromModel).toList(), + ); + } + + Map toJson() { + final map = {}; + for (final element in elements) { + map.addAll(element.toJson()); + } + return { + id: map, + }; + } + + ProposalBuilderSection toModel() { + return ProposalBuilderSection( + id: id, + elements: elements.map((e) => e.toModel()).toList(), + ); + } + + static Map _toJsonElements( + List elements, + ) { + final map = {}; + for (final element in elements) { + map[element.id] = element.value; + } + return map; + } + + static List _fromJsonElements( + Map json, + ) { + final listOfElements = json.convertMapToListWithIdsAndValues(); + return listOfElements.map(ProposalBuilderElementDto.fromJson).toList(); + } +} + +@JsonSerializable() +class ProposalBuilderElementDto { + final String id; + final dynamic value; + + const ProposalBuilderElementDto({ + required this.id, + required this.value, + }); + + factory ProposalBuilderElementDto.fromJson(Map json) { + return _$ProposalBuilderElementDtoFromJson(json); + } + + factory ProposalBuilderElementDto.fromModel(ProposalBuilderElement model) { + return ProposalBuilderElementDto( + id: model.id, + value: model.value, + ); + } + + Map toJson() => { + id: value, + }; + + ProposalBuilderElement toModel() { + return ProposalBuilderElement( + id: id, + value: value, + ); + } +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/proposal/proposal_builder_test.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/proposal/proposal_builder_test.dart new file mode 100644 index 00000000000..1e36fca1c8c --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/proposal/proposal_builder_test.dart @@ -0,0 +1,49 @@ +import 'dart:convert'; + +import 'package:catalyst_voices_models/catalyst_voices_models.dart'; +import 'package:catalyst_voices_repositories/src/dto/proposal_builder_dto.dart'; +import 'package:catalyst_voices_repositories/src/dto/schema_dto.dart'; +import 'package:test/test.dart'; + +import '../../helpers/read_json.dart'; + +void main() { + const schemaPath = + 'test/assets/0ce8ab38-9258-4fbc-a62e-7faa6e58318f.schema.json'; + + late Map schemaJson; + + setUpAll(() { + schemaJson = json.decode(readJson(schemaPath)) as Map; + }); + + test('Converts segments list into object for JSON', () { + final schemaDto = SchemaDto.fromJson(schemaJson); + final schema = schemaDto.toModel(); + + final proposalBuilder = ProposalBuilder.build(schema); + final proposalBuilderDto = ProposalBuilderDto.fromModel(proposalBuilder); + final proposalBuilderJson = proposalBuilderDto.toJson(); + + for (final segment in proposalBuilderDto.segments) { + expect(proposalBuilderJson[segment.id], isA>()); + } + }); + + test('Converts object from JSON into List of segments', () { + final schemaDto = SchemaDto.fromJson(schemaJson); + final schema = schemaDto.toModel(); + + final proposalBuilder = ProposalBuilder.build(schema); + final proposalBuilderDto = ProposalBuilderDto.fromModel(proposalBuilder); + + final proposalBuilderJson = proposalBuilderDto.toJson(); + final proposalBuilderDtoFromJson = + ProposalBuilderDto.fromJson(proposalBuilderJson); + + expect( + proposalBuilderDtoFromJson.segments.length, + proposalBuilderDto.segments.length, + ); + }); +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/proposal/definitions_test.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/schema/definitions_test.dart similarity index 100% rename from catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/proposal/definitions_test.dart rename to catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/schema/definitions_test.dart diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/proposal/proposal_test.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/schema/schema_test.dart similarity index 100% rename from catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/proposal/proposal_test.dart rename to catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/schema/schema_test.dart diff --git a/catalyst_voices/packages/internal/catalyst_voices_shared/lib/src/extension/map_to_list_ext.dart b/catalyst_voices/packages/internal/catalyst_voices_shared/lib/src/extension/map_to_list_ext.dart index 19390355db9..a0e3f8e76f2 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_shared/lib/src/extension/map_to_list_ext.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_shared/lib/src/extension/map_to_list_ext.dart @@ -11,4 +11,18 @@ extension MapToListExt on Map { return list; } + + List> convertMapToListWithIdsAndValues() { + final list = >[]; + + for (final entry in entries) { + if (entry.key == r'$schema') continue; + final value = {}; + value['id'] = entry.key; + value['value'] = entry.value; + list.add(value); + } + + return list; + } } From 41f56b3d85c8185a1df3cfc3318cad47ffb8940b Mon Sep 17 00:00:00 2001 From: Ryszard Schossler Date: Fri, 20 Dec 2024 14:07:09 +0100 Subject: [PATCH 13/18] feat: change name of the files to make it more generic -document- --- .../document_definition.dart} | 2 +- .../lib/src/catalyst_voices_models.dart | 6 +- .../document_builder.dart} | 36 ++-- .../document_definitions.dart} | 186 ++++++------------ .../document_schema.dart} | 30 +-- ...der_dto.dart => document_builder_dto.dart} | 96 ++++----- ...dto.dart => document_definitions_dto.dart} | 98 ++++----- ...hema_dto.dart => document_schema_dto.dart} | 135 +++++++------ .../document_builder_test.dart} | 18 +- .../document_definitions_test.dart} | 7 +- .../document_schema_test.dart} | 8 +- 11 files changed, 287 insertions(+), 335 deletions(-) rename catalyst_voices/apps/voices/lib/widgets/{schema_definition/schema_definition.dart => document_builder/document_definition.dart} (97%) rename catalyst_voices/packages/internal/catalyst_voices_models/lib/src/{proposal_schema/proposal_builder.dart => document_builder/document_builder.dart} (56%) rename catalyst_voices/packages/internal/catalyst_voices_models/lib/src/{proposal_schema/definitions.dart => document_builder/document_definitions.dart} (56%) rename catalyst_voices/packages/internal/catalyst_voices_models/lib/src/{proposal_schema/schema.dart => document_builder/document_schema.dart} (71%) rename catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/{proposal_builder_dto.dart => document_builder_dto.dart} (59%) rename catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/{definitions_dto.dart => document_definitions_dto.dart} (85%) rename catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/{schema_dto.dart => document_schema_dto.dart} (66%) rename catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/{proposal/proposal_builder_test.dart => document_builder/document_builder_test.dart} (65%) rename catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/{schema/definitions_test.dart => document_builder/document_definitions_test.dart} (79%) rename catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/{schema/schema_test.dart => document_builder/document_schema_test.dart} (84%) diff --git a/catalyst_voices/apps/voices/lib/widgets/schema_definition/schema_definition.dart b/catalyst_voices/apps/voices/lib/widgets/document_builder/document_definition.dart similarity index 97% rename from catalyst_voices/apps/voices/lib/widgets/schema_definition/schema_definition.dart rename to catalyst_voices/apps/voices/lib/widgets/document_builder/document_definition.dart index 388bfc9a529..fe7398b2233 100644 --- a/catalyst_voices/apps/voices/lib/widgets/schema_definition/schema_definition.dart +++ b/catalyst_voices/apps/voices/lib/widgets/document_builder/document_definition.dart @@ -2,7 +2,7 @@ import 'package:catalyst_voices_models/catalyst_voices_models.dart'; import 'package:flutter/material.dart'; class SchemaDefinition extends StatelessWidget { - final BaseDefinition definition; + final BaseDocumentDefinition definition; const SchemaDefinition({super.key, required this.definition}); @override diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/catalyst_voices_models.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/catalyst_voices_models.dart index 052a7062817..91852ca68f3 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/catalyst_voices_models.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/catalyst_voices_models.dart @@ -7,6 +7,9 @@ export 'campaign/campaign_category.dart'; export 'campaign/campaign_publish.dart'; export 'campaign/campaign_section.dart'; export 'crypto/lock_factor.dart'; +export 'document_builder/document_builder.dart'; +export 'document_builder/document_definitions.dart'; +export 'document_builder/document_schema.dart'; export 'errors/errors.dart'; export 'file/voices_file.dart'; export 'markdown_data.dart'; @@ -15,9 +18,6 @@ export 'proposal/guidance.dart'; export 'proposal/proposal.dart'; export 'proposal/proposal_section.dart'; export 'proposal/proposal_template.dart'; -export 'proposal_schema/definitions.dart'; -export 'proposal_schema/proposal_builder.dart'; -export 'proposal_schema/schema.dart'; export 'registration/registration.dart'; export 'seed_phrase.dart'; export 'space.dart'; diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/proposal_builder.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/document_builder/document_builder.dart similarity index 56% rename from catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/proposal_builder.dart rename to catalyst_voices/packages/internal/catalyst_voices_models/lib/src/document_builder/document_builder.dart index 05c7365568b..fae7414c379 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/proposal_builder.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/document_builder/document_builder.dart @@ -1,29 +1,28 @@ -import 'package:catalyst_voices_models/src/proposal_schema/schema.dart'; -import 'package:json_annotation/json_annotation.dart'; +import 'package:catalyst_voices_models/src/document_builder/document_schema.dart'; -class ProposalBuilder { +class DocumentBuilder { final String schema; - final List segments; + final List segments; - const ProposalBuilder({ + const DocumentBuilder({ required this.schema, required this.segments, }); - factory ProposalBuilder.build(Schema proposalSchema) { - return ProposalBuilder( + factory DocumentBuilder.build(DocumentSchema proposalSchema) { + return DocumentBuilder( schema: proposalSchema.propertiesSchema, segments: proposalSchema.segments .map( - (element) => ProposalBuilderSegment( + (element) => DocumentBuilderSegment( id: element.id, sections: element.sections .map( - (element) => ProposalBuilderSection( + (element) => DocumentBuilderSection( id: element.id, elements: element.elements .map( - (e) => ProposalBuilderElement( + (e) => DocumentBuilderElement( id: e.id, value: e.ref.type.getDefaultValue, ), @@ -39,32 +38,31 @@ class ProposalBuilder { } } -class ProposalBuilderSegment { +class DocumentBuilderSegment { final String id; - final List sections; + final List sections; - const ProposalBuilderSegment({ + const DocumentBuilderSegment({ required this.id, required this.sections, }); } -@JsonSerializable() -class ProposalBuilderSection { +class DocumentBuilderSection { final String id; - final List elements; + final List elements; - const ProposalBuilderSection({ + const DocumentBuilderSection({ required this.id, required this.elements, }); } -class ProposalBuilderElement { +class DocumentBuilderElement { final String id; final dynamic value; - const ProposalBuilderElement({ + const DocumentBuilderElement({ required this.id, required this.value, }); diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/definitions.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/document_builder/document_definitions.dart similarity index 56% rename from catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/definitions.dart rename to catalyst_voices/packages/internal/catalyst_voices_models/lib/src/document_builder/document_definitions.dart index 43a36e13f2b..6cc9f4c4dc6 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/definitions.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/document_builder/document_definitions.dart @@ -1,6 +1,6 @@ import 'package:meta/meta.dart'; -enum DefinitionsObjectType { +enum DocumentDefinitionsObjectType { string, object, integer, @@ -8,11 +8,11 @@ enum DefinitionsObjectType { array, unknown; - const DefinitionsObjectType(); + const DocumentDefinitionsObjectType(); - static DefinitionsObjectType fromString(String value) { - return DefinitionsObjectType.values.asNameMap()[value] ?? - DefinitionsObjectType.unknown; + static DocumentDefinitionsObjectType fromString(String value) { + return DocumentDefinitionsObjectType.values.asNameMap()[value] ?? + DocumentDefinitionsObjectType.unknown; } dynamic get getDefaultValue => switch (this) { @@ -25,22 +25,22 @@ enum DefinitionsObjectType { }; } -enum DefinitionsContentMediaType { +enum DocumentDefinitionsContentMediaType { textPlain('text/plain'), markdown('text/markdown'), unknown('unknown'); final String value; - const DefinitionsContentMediaType(this.value); + const DocumentDefinitionsContentMediaType(this.value); - static DefinitionsContentMediaType fromString(String value) { - return DefinitionsContentMediaType.values.asNameMap()[value] ?? - DefinitionsContentMediaType.unknown; + static DocumentDefinitionsContentMediaType fromString(String value) { + return DocumentDefinitionsContentMediaType.values.asNameMap()[value] ?? + DocumentDefinitionsContentMediaType.unknown; } } -enum DefinitionsFormat { +enum DocumentDefinitionsFormat { path, uri, dropDownSingleSelect, @@ -60,79 +60,19 @@ enum DefinitionsFormat { spdxLicenseOrURL, unknown; - const DefinitionsFormat(); + const DocumentDefinitionsFormat(); - static DefinitionsFormat fromString(String value) { - return DefinitionsFormat.values.asNameMap()[value] ?? - DefinitionsFormat.unknown; + static DocumentDefinitionsFormat fromString(String value) { + return DocumentDefinitionsFormat.values.asNameMap()[value] ?? + DocumentDefinitionsFormat.unknown; } } -// enum DefinitionsType { -// segment, -// section, -// singleLineTextEntry, -// multiLineTextEntry, -// multiLineTextEntryMarkdown, -// dropDownSingleSelect, -// multiSelect, -// singleLineTextEntryList, -// multiLineTextEntryListMarkdown, -// singleLineHttpsURLEntry, -// singleLineHttpsURLEntryList, -// nestedQuestionsList, -// nestedQuestions, -// singleGroupedTagSelector, -// tagGroup, -// tagSelection, -// tokenValueCardanoADA, -// durationInMonths, -// yesNoChoice, -// agreementConfirmation, -// spdxLicenseOrURL; - -// const DefinitionsType(); - -// static DefinitionsType fromString(String value) { -// return values.byName(value); -// } - -// static bool isKnownType(String refPath) { -// final ref = refPath.split('/').last; -// return values.asNameMap()[ref] != null; -// } - -// Object get definitionType => switch (this) { -// section => SectionDefinition, -// segment => SegmentDefinition, -// singleLineTextEntry => SingleLineTextEntryDefinition, -// durationInMonths => DurationInMonthsDefinition, -// singleLineHttpsURLEntry => SingleLineHttpsURLEntryDefinition, -// multiLineTextEntry => MultiLineTextEntryDefinition, -// multiLineTextEntryMarkdown => MultiLineTextEntryMarkdownDefinition, -// dropDownSingleSelect => DropDownSingleSelectDefinition, -// multiSelect => MultiSelectDefinition, -// singleLineTextEntryList => SingleLineTextEntryListDefinition, -// multiLineTextEntryListMarkdown => -// MultiLineTextEntryListMarkdownDefinition, -// singleLineHttpsURLEntryList => SingleLineHttpsURLEntryListDefinition, -// nestedQuestionsList => NestedQuestionsListDefinition, -// nestedQuestions => NestedQuestionsDefinition, -// singleGroupedTagSelector => SingleGroupedTagSelectorDefinition, -// tagGroup => TagGroupDefinition, -// tagSelection => TagSelectionDefinition, -// tokenValueCardanoADA => TokenValueCardanoADADefinition, -// yesNoChoice => YesNoChoiceDefinition, -// agreementConfirmation => AgreementConfirmationDefinition, -// spdxLicenseOrURL => SPDXLicenceOrUrlDefinition, -// }; -// } - -sealed class BaseDefinition { - final DefinitionsObjectType type; +sealed class BaseDocumentDefinition { + final DocumentDefinitionsObjectType type; final String note; - const BaseDefinition({ + const BaseDocumentDefinition({ required this.type, required this.note, }); @@ -173,16 +113,16 @@ sealed class BaseDefinition { } } -extension BaseDefinitionListExt on List { - BaseDefinition getDefinition(String refPath) { - final definitionType = BaseDefinition.typeFromRefPath(refPath); +extension BaseDocumentDefinitionListExt on List { + BaseDocumentDefinition getDefinition(String refPath) { + final definitionType = BaseDocumentDefinition.typeFromRefPath(refPath); final classType = definitionType; return firstWhere((e) => e.runtimeType == classType); } } -class SegmentDefinition extends BaseDefinition { +class SegmentDefinition extends BaseDocumentDefinition { final bool additionalProperties; const SegmentDefinition({ @@ -192,7 +132,7 @@ class SegmentDefinition extends BaseDefinition { }); } -class SectionDefinition extends BaseDefinition { +class SectionDefinition extends BaseDocumentDefinition { final bool additionalProperties; const SectionDefinition({ @@ -202,8 +142,8 @@ class SectionDefinition extends BaseDefinition { }); } -class SingleLineTextEntryDefinition extends BaseDefinition { - final DefinitionsContentMediaType contentMediaType; +class SingleLineTextEntryDefinition extends BaseDocumentDefinition { + final DocumentDefinitionsContentMediaType contentMediaType; final String pattern; const SingleLineTextEntryDefinition({ @@ -214,8 +154,8 @@ class SingleLineTextEntryDefinition extends BaseDefinition { }); } -class SingleLineHttpsURLEntryDefinition extends BaseDefinition { - final DefinitionsFormat format; +class SingleLineHttpsURLEntryDefinition extends BaseDocumentDefinition { + final DocumentDefinitionsFormat format; final String pattern; const SingleLineHttpsURLEntryDefinition({ @@ -226,8 +166,8 @@ class SingleLineHttpsURLEntryDefinition extends BaseDefinition { }); } -class MultiLineTextEntryDefinition extends BaseDefinition { - final DefinitionsContentMediaType contentMediaType; +class MultiLineTextEntryDefinition extends BaseDocumentDefinition { + final DocumentDefinitionsContentMediaType contentMediaType; final String pattern; const MultiLineTextEntryDefinition({ @@ -238,8 +178,8 @@ class MultiLineTextEntryDefinition extends BaseDefinition { }); } -class MultiLineTextEntryMarkdownDefinition extends BaseDefinition { - final DefinitionsContentMediaType contentMediaType; +class MultiLineTextEntryMarkdownDefinition extends BaseDocumentDefinition { + final DocumentDefinitionsContentMediaType contentMediaType; final String pattern; const MultiLineTextEntryMarkdownDefinition({ @@ -250,9 +190,9 @@ class MultiLineTextEntryMarkdownDefinition extends BaseDefinition { }); } -class DropDownSingleSelectDefinition extends BaseDefinition { - final DefinitionsFormat format; - final DefinitionsContentMediaType contentMediaType; +class DropDownSingleSelectDefinition extends BaseDocumentDefinition { + final DocumentDefinitionsFormat format; + final DocumentDefinitionsContentMediaType contentMediaType; final String pattern; const DropDownSingleSelectDefinition({ @@ -264,8 +204,8 @@ class DropDownSingleSelectDefinition extends BaseDefinition { }); } -class MultiSelectDefinition extends BaseDefinition { - final DefinitionsFormat format; +class MultiSelectDefinition extends BaseDocumentDefinition { + final DocumentDefinitionsFormat format; final bool uniqueItems; const MultiSelectDefinition({ @@ -276,8 +216,8 @@ class MultiSelectDefinition extends BaseDefinition { }); } -class SingleLineTextEntryListDefinition extends BaseDefinition { - final DefinitionsFormat format; +class SingleLineTextEntryListDefinition extends BaseDocumentDefinition { + final DocumentDefinitionsFormat format; final bool uniqueItems; final List defaultValues; final Map items; @@ -292,8 +232,8 @@ class SingleLineTextEntryListDefinition extends BaseDefinition { }); } -class MultiLineTextEntryListMarkdownDefinition extends BaseDefinition { - final DefinitionsFormat format; +class MultiLineTextEntryListMarkdownDefinition extends BaseDocumentDefinition { + final DocumentDefinitionsFormat format; final bool uniqueItems; final List defaultValue; final Map items; @@ -308,8 +248,8 @@ class MultiLineTextEntryListMarkdownDefinition extends BaseDefinition { }); } -class SingleLineHttpsURLEntryListDefinition extends BaseDefinition { - final DefinitionsFormat format; +class SingleLineHttpsURLEntryListDefinition extends BaseDocumentDefinition { + final DocumentDefinitionsFormat format; final bool uniqueItems; final List defaultValue; final Map items; @@ -324,8 +264,8 @@ class SingleLineHttpsURLEntryListDefinition extends BaseDefinition { }); } -class NestedQuestionsListDefinition extends BaseDefinition { - final DefinitionsFormat format; +class NestedQuestionsListDefinition extends BaseDocumentDefinition { + final DocumentDefinitionsFormat format; final bool uniqueItems; final List defaultValue; @@ -338,8 +278,8 @@ class NestedQuestionsListDefinition extends BaseDefinition { }); } -class NestedQuestionsDefinition extends BaseDefinition { - final DefinitionsFormat format; +class NestedQuestionsDefinition extends BaseDocumentDefinition { + final DocumentDefinitionsFormat format; final bool additionalProperties; const NestedQuestionsDefinition({ required super.type, @@ -349,8 +289,8 @@ class NestedQuestionsDefinition extends BaseDefinition { }); } -class SingleGroupedTagSelectorDefinition extends BaseDefinition { - final DefinitionsFormat format; +class SingleGroupedTagSelectorDefinition extends BaseDocumentDefinition { + final DocumentDefinitionsFormat format; final bool additionalProperties; const SingleGroupedTagSelectorDefinition({ @@ -361,8 +301,8 @@ class SingleGroupedTagSelectorDefinition extends BaseDefinition { }); } -class TagGroupDefinition extends BaseDefinition { - final DefinitionsFormat format; +class TagGroupDefinition extends BaseDocumentDefinition { + final DocumentDefinitionsFormat format; final String pattern; const TagGroupDefinition({ @@ -373,8 +313,8 @@ class TagGroupDefinition extends BaseDefinition { }); } -class TagSelectionDefinition extends BaseDefinition { - final DefinitionsFormat format; +class TagSelectionDefinition extends BaseDocumentDefinition { + final DocumentDefinitionsFormat format; final String pattern; const TagSelectionDefinition({ @@ -385,8 +325,8 @@ class TagSelectionDefinition extends BaseDefinition { }); } -class TokenValueCardanoADADefinition extends BaseDefinition { - final DefinitionsFormat format; +class TokenValueCardanoADADefinition extends BaseDocumentDefinition { + final DocumentDefinitionsFormat format; const TokenValueCardanoADADefinition({ required super.type, @@ -395,8 +335,8 @@ class TokenValueCardanoADADefinition extends BaseDefinition { }); } -class DurationInMonthsDefinition extends BaseDefinition { - final DefinitionsFormat format; +class DurationInMonthsDefinition extends BaseDocumentDefinition { + final DocumentDefinitionsFormat format; const DurationInMonthsDefinition({ required super.type, @@ -405,8 +345,8 @@ class DurationInMonthsDefinition extends BaseDefinition { }); } -class YesNoChoiceDefinition extends BaseDefinition { - final DefinitionsFormat format; +class YesNoChoiceDefinition extends BaseDocumentDefinition { + final DocumentDefinitionsFormat format; final bool defaultValue; const YesNoChoiceDefinition({ @@ -417,8 +357,8 @@ class YesNoChoiceDefinition extends BaseDefinition { }); } -class AgreementConfirmationDefinition extends BaseDefinition { - final DefinitionsFormat format; +class AgreementConfirmationDefinition extends BaseDocumentDefinition { + final DocumentDefinitionsFormat format; final bool defaultValue; final bool constValue; @@ -431,10 +371,10 @@ class AgreementConfirmationDefinition extends BaseDefinition { }); } -class SPDXLicenceOrUrlDefinition extends BaseDefinition { - final DefinitionsFormat format; +class SPDXLicenceOrUrlDefinition extends BaseDocumentDefinition { + final DocumentDefinitionsFormat format; final String pattern; - final DefinitionsContentMediaType contentMediaType; + final DocumentDefinitionsContentMediaType contentMediaType; const SPDXLicenceOrUrlDefinition({ required super.type, diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/schema.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/document_builder/document_schema.dart similarity index 71% rename from catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/schema.dart rename to catalyst_voices/packages/internal/catalyst_voices_models/lib/src/document_builder/document_schema.dart index a3f536c2e8f..55488e173a4 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/proposal_schema/schema.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/document_builder/document_schema.dart @@ -1,15 +1,15 @@ -import 'package:catalyst_voices_models/src/proposal_schema/definitions.dart'; +import 'package:catalyst_voices_models/src/document_builder/document_definitions.dart'; import 'package:catalyst_voices_shared/catalyst_voices_shared.dart'; -class Schema { +class DocumentSchema { final String schema; final String title; final String description; - final List segments; + final List segments; final List order; final String propertiesSchema; - const Schema({ + const DocumentSchema({ required this.schema, required this.title, required this.description, @@ -19,14 +19,14 @@ class Schema { }); } -class SchemaSegment { - final BaseDefinition ref; +class DocumentSchemaSegment { + final BaseDocumentDefinition ref; final String id; final String title; final String description; - final List sections; + final List sections; - const SchemaSegment({ + const DocumentSchemaSegment({ required this.ref, required this.id, required this.title, @@ -35,15 +35,15 @@ class SchemaSegment { }); } -class SchemaSection { - final BaseDefinition ref; +class DocumentSchemaSection { + final BaseDocumentDefinition ref; final String id; final String title; final String description; - final List elements; + final List elements; final bool isRequired; - const SchemaSection({ + const DocumentSchemaSection({ required this.ref, required this.id, required this.title, @@ -53,8 +53,8 @@ class SchemaSection { }); } -class SchemaElement { - final BaseDefinition ref; +class DocumentSchemaElement { + final BaseDocumentDefinition ref; final String id; final String title; final String description; @@ -66,7 +66,7 @@ class SchemaElement { final Range? range; final Range? itemsRange; - const SchemaElement({ + const DocumentSchemaElement({ required this.ref, required this.id, required this.title, diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/proposal_builder_dto.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/document_builder_dto.dart similarity index 59% rename from catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/proposal_builder_dto.dart rename to catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/document_builder_dto.dart index 24025d05219..abf66f62347 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/proposal_builder_dto.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/document_builder_dto.dart @@ -2,29 +2,29 @@ import 'package:catalyst_voices_models/catalyst_voices_models.dart'; import 'package:catalyst_voices_shared/catalyst_voices_shared.dart'; import 'package:json_annotation/json_annotation.dart'; -part 'proposal_builder_dto.g.dart'; +part 'document_builder_dto.g.dart'; @JsonSerializable() -class ProposalBuilderDto { +class DocumentBuilderDto { @JsonKey(name: r'$schema') final String schema; @JsonKey(fromJson: _fromJsonSegments, toJson: _toJsonSegments) - final List segments; - const ProposalBuilderDto({ + final List segments; + const DocumentBuilderDto({ required this.schema, required this.segments, }); - factory ProposalBuilderDto.fromJson(Map json) { + factory DocumentBuilderDto.fromJson(Map json) { json['segments'] = Map.from(json)..remove(r'$schema'); - return _$ProposalBuilderDtoFromJson(json); + return _$DocumentBuilderDtoFromJson(json); } - factory ProposalBuilderDto.fromModel(ProposalBuilder model) { - return ProposalBuilderDto( + factory DocumentBuilderDto.fromModel(DocumentBuilder model) { + return DocumentBuilderDto( schema: model.schema, segments: - model.segments.map(ProposalBuilderSegmentDto.fromModel).toList(), + model.segments.map(DocumentBuilderSegmentDto.fromModel).toList(), ); } @@ -36,15 +36,15 @@ class ProposalBuilderDto { return segments; } - ProposalBuilder toModel() { - return ProposalBuilder( + DocumentBuilder toModel() { + return DocumentBuilder( schema: schema, segments: segments.map((e) => e.toModel()).toList(), ); } static Map _toJsonSegments( - List segments, + List segments, ) { final map = {}; for (final segment in segments) { @@ -53,35 +53,35 @@ class ProposalBuilderDto { return map; } - static List _fromJsonSegments( + static List _fromJsonSegments( Map json, ) { final listOfSegments = json.convertMapToListWithIds(); - return listOfSegments.map(ProposalBuilderSegmentDto.fromJson).toList(); + return listOfSegments.map(DocumentBuilderSegmentDto.fromJson).toList(); } } @JsonSerializable() -class ProposalBuilderSegmentDto { +class DocumentBuilderSegmentDto { final String id; @JsonKey(fromJson: _fromJsonSections, toJson: _toJsonSections) - final List sections; + final List sections; - const ProposalBuilderSegmentDto({ + const DocumentBuilderSegmentDto({ required this.id, required this.sections, }); - factory ProposalBuilderSegmentDto.fromJson(Map json) { + factory DocumentBuilderSegmentDto.fromJson(Map json) { json['sections'] = Map.from(json)..remove('id'); - return _$ProposalBuilderSegmentDtoFromJson(json); + return _$DocumentBuilderSegmentDtoFromJson(json); } - factory ProposalBuilderSegmentDto.fromModel(ProposalBuilderSegment model) { - return ProposalBuilderSegmentDto( + factory DocumentBuilderSegmentDto.fromModel(DocumentBuilderSegment model) { + return DocumentBuilderSegmentDto( id: model.id, sections: - model.sections.map(ProposalBuilderSectionDto.fromModel).toList(), + model.sections.map(DocumentBuilderSectionDto.fromModel).toList(), ); } @@ -95,15 +95,15 @@ class ProposalBuilderSegmentDto { }; } - ProposalBuilderSegment toModel() { - return ProposalBuilderSegment( + DocumentBuilderSegment toModel() { + return DocumentBuilderSegment( id: id, sections: sections.map((e) => e.toModel()).toList(), ); } static Map _toJsonSections( - List sections, + List sections, ) { final map = {}; for (final section in sections) { @@ -112,35 +112,35 @@ class ProposalBuilderSegmentDto { return map; } - static List _fromJsonSections( + static List _fromJsonSections( Map json, ) { final listOfSections = json.convertMapToListWithIds(); - return listOfSections.map(ProposalBuilderSectionDto.fromJson).toList(); + return listOfSections.map(DocumentBuilderSectionDto.fromJson).toList(); } } @JsonSerializable() -class ProposalBuilderSectionDto { +class DocumentBuilderSectionDto { final String id; @JsonKey(fromJson: _fromJsonElements, toJson: _toJsonElements) - final List elements; + final List elements; - ProposalBuilderSectionDto({ + DocumentBuilderSectionDto({ required this.id, required this.elements, }); - factory ProposalBuilderSectionDto.fromJson(Map json) { + factory DocumentBuilderSectionDto.fromJson(Map json) { json['elements'] = Map.from(json)..remove('id'); - return _$ProposalBuilderSectionDtoFromJson(json); + return _$DocumentBuilderSectionDtoFromJson(json); } - factory ProposalBuilderSectionDto.fromModel(ProposalBuilderSection model) { - return ProposalBuilderSectionDto( + factory DocumentBuilderSectionDto.fromModel(DocumentBuilderSection model) { + return DocumentBuilderSectionDto( id: model.id, elements: - model.elements.map(ProposalBuilderElementDto.fromModel).toList(), + model.elements.map(DocumentBuilderElementDto.fromModel).toList(), ); } @@ -154,15 +154,15 @@ class ProposalBuilderSectionDto { }; } - ProposalBuilderSection toModel() { - return ProposalBuilderSection( + DocumentBuilderSection toModel() { + return DocumentBuilderSection( id: id, elements: elements.map((e) => e.toModel()).toList(), ); } static Map _toJsonElements( - List elements, + List elements, ) { final map = {}; for (final element in elements) { @@ -171,30 +171,30 @@ class ProposalBuilderSectionDto { return map; } - static List _fromJsonElements( + static List _fromJsonElements( Map json, ) { final listOfElements = json.convertMapToListWithIdsAndValues(); - return listOfElements.map(ProposalBuilderElementDto.fromJson).toList(); + return listOfElements.map(DocumentBuilderElementDto.fromJson).toList(); } } @JsonSerializable() -class ProposalBuilderElementDto { +class DocumentBuilderElementDto { final String id; final dynamic value; - const ProposalBuilderElementDto({ + const DocumentBuilderElementDto({ required this.id, required this.value, }); - factory ProposalBuilderElementDto.fromJson(Map json) { - return _$ProposalBuilderElementDtoFromJson(json); + factory DocumentBuilderElementDto.fromJson(Map json) { + return _$DocumentBuilderElementDtoFromJson(json); } - factory ProposalBuilderElementDto.fromModel(ProposalBuilderElement model) { - return ProposalBuilderElementDto( + factory DocumentBuilderElementDto.fromModel(DocumentBuilderElement model) { + return DocumentBuilderElementDto( id: model.id, value: model.value, ); @@ -204,8 +204,8 @@ class ProposalBuilderElementDto { id: value, }; - ProposalBuilderElement toModel() { - return ProposalBuilderElement( + DocumentBuilderElement toModel() { + return DocumentBuilderElement( id: id, value: value, ); diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/definitions_dto.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/document_definitions_dto.dart similarity index 85% rename from catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/definitions_dto.dart rename to catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/document_definitions_dto.dart index db2d03d151b..a01c02ed5fb 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/definitions_dto.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/document_definitions_dto.dart @@ -1,10 +1,10 @@ import 'package:catalyst_voices_models/catalyst_voices_models.dart'; import 'package:json_annotation/json_annotation.dart'; -part 'definitions_dto.g.dart'; +part 'document_definitions_dto.g.dart'; @JsonSerializable() -class DefinitionsDto { +class DocumentDefinitionsDto { final SegmentDto segment; final SectionDto section; final SingleLineTextEntryDto singleLineTextEntry; @@ -29,7 +29,7 @@ class DefinitionsDto { @JsonKey(name: 'spdxLicenseOrURL') final SPDXLicenceOrUrlDto spdxLicenceOrUrl; - const DefinitionsDto({ + const DocumentDefinitionsDto({ required this.segment, required this.section, required this.singleLineTextEntry, @@ -53,12 +53,12 @@ class DefinitionsDto { required this.spdxLicenceOrUrl, }); - factory DefinitionsDto.fromJson(Map json) => - _$DefinitionsDtoFromJson(json); + factory DocumentDefinitionsDto.fromJson(Map json) => + _$DocumentDefinitionsDtoFromJson(json); - Map toJson() => _$DefinitionsDtoToJson(this); + Map toJson() => _$DocumentDefinitionsDtoToJson(this); - List get definitionsModels => [ + List get definitionsModels => [ segment.toModel(), section.toModel(), singleLineTextEntry.toModel(), @@ -102,7 +102,7 @@ class SegmentDto { Map toJson() => _$SegmentDtoToJson(this); SegmentDefinition toModel() => SegmentDefinition( - type: DefinitionsObjectType.fromString(type), + type: DocumentDefinitionsObjectType.fromString(type), note: note, additionalProperties: additionalProperties, ); @@ -127,7 +127,7 @@ class SectionDto { Map toJson() => _$SectionDtoToJson(this); SectionDefinition toModel() => SectionDefinition( - type: DefinitionsObjectType.fromString(type), + type: DocumentDefinitionsObjectType.fromString(type), note: note, additionalProperties: additionalProperties, ); @@ -154,10 +154,10 @@ class SingleLineTextEntryDto { Map toJson() => _$SingleLineTextEntryDtoToJson(this); SingleLineTextEntryDefinition toModel() => SingleLineTextEntryDefinition( - type: DefinitionsObjectType.fromString(type), + type: DocumentDefinitionsObjectType.fromString(type), note: note, contentMediaType: - DefinitionsContentMediaType.fromString(contentMediaType), + DocumentDefinitionsContentMediaType.fromString(contentMediaType), pattern: pattern, ); } @@ -184,9 +184,9 @@ class SingleLineHttpsURLEntryDto { SingleLineHttpsURLEntryDefinition toModel() { return SingleLineHttpsURLEntryDefinition( - type: DefinitionsObjectType.fromString(type), + type: DocumentDefinitionsObjectType.fromString(type), note: note, - format: DefinitionsFormat.fromString(format), + format: DocumentDefinitionsFormat.fromString(format), pattern: pattern, ); } @@ -214,10 +214,10 @@ class MultiLineTextEntryDto { MultiLineTextEntryDefinition toModel() { return MultiLineTextEntryDefinition( - type: DefinitionsObjectType.fromString(type), + type: DocumentDefinitionsObjectType.fromString(type), note: note, contentMediaType: - DefinitionsContentMediaType.fromString(contentMediaType), + DocumentDefinitionsContentMediaType.fromString(contentMediaType), pattern: pattern, ); } @@ -245,10 +245,10 @@ class MultiLineTextEntryMarkdownDto { MultiLineTextEntryMarkdownDefinition toModel() { return MultiLineTextEntryMarkdownDefinition( - type: DefinitionsObjectType.fromString(type), + type: DocumentDefinitionsObjectType.fromString(type), note: note, contentMediaType: - DefinitionsContentMediaType.fromString(contentMediaType), + DocumentDefinitionsContentMediaType.fromString(contentMediaType), pattern: pattern, ); } @@ -278,12 +278,12 @@ class DropDownSingleSelectDto { DropDownSingleSelectDefinition toModel() { return DropDownSingleSelectDefinition( - type: DefinitionsObjectType.fromString(type), + type: DocumentDefinitionsObjectType.fromString(type), note: note, contentMediaType: - DefinitionsContentMediaType.fromString(contentMediaType), + DocumentDefinitionsContentMediaType.fromString(contentMediaType), pattern: pattern, - format: DefinitionsFormat.fromString(format), + format: DocumentDefinitionsFormat.fromString(format), ); } } @@ -310,9 +310,9 @@ class MultiSelectDto { MultiSelectDefinition toModel() { return MultiSelectDefinition( - type: DefinitionsObjectType.fromString(type), + type: DocumentDefinitionsObjectType.fromString(type), note: note, - format: DefinitionsFormat.fromString(format), + format: DocumentDefinitionsFormat.fromString(format), uniqueItems: uniqueItems, ); } @@ -345,9 +345,9 @@ class SingleLineTextEntryListDto { SingleLineTextEntryListDefinition toModel() => SingleLineTextEntryListDefinition( - type: DefinitionsObjectType.fromString(type), + type: DocumentDefinitionsObjectType.fromString(type), note: note, - format: DefinitionsFormat.fromString(format), + format: DocumentDefinitionsFormat.fromString(format), uniqueItems: uniqueItems, defaultValues: defaultValue, items: items, @@ -384,9 +384,9 @@ class MultiLineTextEntryListMarkdownDto { MultiLineTextEntryListMarkdownDefinition toModel() => MultiLineTextEntryListMarkdownDefinition( - type: DefinitionsObjectType.fromString(type), + type: DocumentDefinitionsObjectType.fromString(type), note: note, - format: DefinitionsFormat.fromString(format), + format: DocumentDefinitionsFormat.fromString(format), uniqueItems: uniqueItems, defaultValue: defaultValue, items: items, @@ -420,9 +420,9 @@ class SingleLineHttpsURLEntryListDto { SingleLineHttpsURLEntryListDefinition toModel() => SingleLineHttpsURLEntryListDefinition( - type: DefinitionsObjectType.fromString(type), + type: DocumentDefinitionsObjectType.fromString(type), note: note, - format: DefinitionsFormat.fromString(format), + format: DocumentDefinitionsFormat.fromString(format), uniqueItems: uniqueItems, defaultValue: defaultValue, items: items, @@ -453,9 +453,9 @@ class NestedQuestionsListDto { Map toJson() => _$NestedQuestionsListDtoToJson(this); NestedQuestionsListDefinition toModel() => NestedQuestionsListDefinition( - type: DefinitionsObjectType.fromString(type), + type: DocumentDefinitionsObjectType.fromString(type), note: note, - format: DefinitionsFormat.fromString(format), + format: DocumentDefinitionsFormat.fromString(format), uniqueItems: uniqueItems, defaultValue: defaultValue, ); @@ -483,9 +483,9 @@ class NestedQuestionsDto { NestedQuestionsDefinition toModel() { return NestedQuestionsDefinition( - type: DefinitionsObjectType.fromString(type), + type: DocumentDefinitionsObjectType.fromString(type), note: note, - format: DefinitionsFormat.fromString(format), + format: DocumentDefinitionsFormat.fromString(format), additionalProperties: additionalProperties, ); } @@ -513,9 +513,9 @@ class SingleGroupedTagSelectorDto { SingleGroupedTagSelectorDefinition toModel() { return SingleGroupedTagSelectorDefinition( - type: DefinitionsObjectType.fromString(type), + type: DocumentDefinitionsObjectType.fromString(type), note: note, - format: DefinitionsFormat.fromString(format), + format: DocumentDefinitionsFormat.fromString(format), additionalProperties: additionalProperties, ); } @@ -543,9 +543,9 @@ class TagGroupDto { TagGroupDefinition toModel() { return TagGroupDefinition( - type: DefinitionsObjectType.fromString(type), + type: DocumentDefinitionsObjectType.fromString(type), note: note, - format: DefinitionsFormat.fromString(format), + format: DocumentDefinitionsFormat.fromString(format), pattern: pattern, ); } @@ -573,9 +573,9 @@ class TagSelectionDto { TagSelectionDefinition toModel() { return TagSelectionDefinition( - type: DefinitionsObjectType.fromString(type), + type: DocumentDefinitionsObjectType.fromString(type), note: note, - format: DefinitionsFormat.fromString(format), + format: DocumentDefinitionsFormat.fromString(format), pattern: pattern, ); } @@ -600,9 +600,9 @@ class TokenValueCardanoAdaDto { Map toJson() => _$TokenValueCardanoAdaDtoToJson(this); TokenValueCardanoADADefinition toModel() => TokenValueCardanoADADefinition( - type: DefinitionsObjectType.fromString(type), + type: DocumentDefinitionsObjectType.fromString(type), note: note, - format: DefinitionsFormat.fromString(format), + format: DocumentDefinitionsFormat.fromString(format), ); } @@ -626,9 +626,9 @@ class DurationInMonthsDto { DurationInMonthsDefinition toModel() { return DurationInMonthsDefinition( - type: DefinitionsObjectType.fromString(type), + type: DocumentDefinitionsObjectType.fromString(type), note: note, - format: DefinitionsFormat.fromString(format), + format: DocumentDefinitionsFormat.fromString(format), ); } } @@ -655,9 +655,9 @@ class YesNoChoiceDto { Map toJson() => _$YesNoChoiceDtoToJson(this); YesNoChoiceDefinition toModel() => YesNoChoiceDefinition( - type: DefinitionsObjectType.fromString(type), + type: DocumentDefinitionsObjectType.fromString(type), note: note, - format: DefinitionsFormat.fromString(format), + format: DocumentDefinitionsFormat.fromString(format), defaultValue: defaultValue, ); } @@ -687,9 +687,9 @@ class AgreementConfirmationDto { Map toJson() => _$AgreementConfirmationDtoToJson(this); AgreementConfirmationDefinition toModel() => AgreementConfirmationDefinition( - type: DefinitionsObjectType.fromString(type), + type: DocumentDefinitionsObjectType.fromString(type), note: note, - format: DefinitionsFormat.fromString(format), + format: DocumentDefinitionsFormat.fromString(format), defaultValue: defaultValue, constValue: constValue, ); @@ -718,11 +718,11 @@ class SPDXLicenceOrUrlDto { Map toJson() => _$SPDXLicenceOrUrlDtoToJson(this); SPDXLicenceOrUrlDefinition toModel() => SPDXLicenceOrUrlDefinition( - type: DefinitionsObjectType.fromString(type), + type: DocumentDefinitionsObjectType.fromString(type), note: note, - format: DefinitionsFormat.fromString(format), + format: DocumentDefinitionsFormat.fromString(format), pattern: pattern, contentMediaType: - DefinitionsContentMediaType.fromString(contentMediaType), + DocumentDefinitionsContentMediaType.fromString(contentMediaType), ); } diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/schema_dto.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/document_schema_dto.dart similarity index 66% rename from catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/schema_dto.dart rename to catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/document_schema_dto.dart index cbf915267f0..1a098fd52ab 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/schema_dto.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/document_schema_dto.dart @@ -1,20 +1,20 @@ import 'package:catalyst_voices_models/catalyst_voices_models.dart'; -import 'package:catalyst_voices_repositories/src/dto/definitions_dto.dart'; +import 'package:catalyst_voices_repositories/src/dto/document_definitions_dto.dart'; import 'package:catalyst_voices_shared/catalyst_voices_shared.dart'; import 'package:equatable/equatable.dart'; import 'package:json_annotation/json_annotation.dart'; -part 'schema_dto.g.dart'; +part 'document_schema_dto.g.dart'; @JsonSerializable() -class SchemaDto extends Equatable { +class DocumentSchemaDto extends Equatable { @JsonKey(name: r'$schema') final String schema; @JsonKey(name: r'$id') final String id; final String title; final String description; - final DefinitionsDto definitions; + final DocumentDefinitionsDto definitions; final String type; final bool additionalProperties; @JsonKey( @@ -22,7 +22,7 @@ class SchemaDto extends Equatable { fromJson: _fromJsonProperties, name: 'properties', ) - final List segments; + final List segments; @JsonKey(name: 'x-order') final List order; @JsonKey(includeToJson: false) @@ -30,7 +30,7 @@ class SchemaDto extends Equatable { static late Map orderMap; - const SchemaDto({ + const DocumentSchemaDto({ required this.schema, required this.id, required this.title, @@ -43,24 +43,25 @@ class SchemaDto extends Equatable { required this.propertiesSchema, }); - factory SchemaDto.fromJson(Map json) { + factory DocumentSchemaDto.fromJson(Map json) { final segmentsMap = json['properties'] as Map; - json['propertiesSchema'] = + json['propertiesDocumentSchema'] = (segmentsMap[r'$schema'] as Map)['const']; - return _$SchemaDtoFromJson(json); + return _$DocumentSchemaDtoFromJson(json); } - Map toJson() => _$SchemaDtoToJson(this); + Map toJson() => _$DocumentSchemaDtoToJson(this); - Schema toModel() { + DocumentSchema toModel() { orderMap = {for (var i = 0; i < order.length; i++) order[i]: i}; - final sortedProperties = List.from(this.segments)..sort(); + final sortedProperties = List.from(this.segments) + ..sort(); final segments = sortedProperties .where((e) => e.ref.contains('segment')) .map((e) => e.toModel(definitions.definitionsModels)) .toList(); - return Schema( + return DocumentSchema( schema: schema, title: title, description: description, @@ -83,7 +84,7 @@ class SchemaDto extends Equatable { ]; static Map _toJsonProperties( - List segments, + List segments, ) { final map = {}; for (final property in segments) { @@ -92,15 +93,17 @@ class SchemaDto extends Equatable { return map; } - static List _fromJsonProperties(Map json) { + static List _fromJsonProperties( + Map json, + ) { final listOfSegments = json.convertMapToListWithIds(); - return listOfSegments.map(SchemaSegmentDto.fromJson).toList(); + return listOfSegments.map(DocumentSchemaSegmentDto.fromJson).toList(); } } @JsonSerializable() -class SchemaSegmentDto extends Equatable - implements Comparable { +class DocumentSchemaSegmentDto extends Equatable + implements Comparable { @JsonKey(name: r'$ref') final String ref; final String id; @@ -111,14 +114,14 @@ class SchemaSegmentDto extends Equatable fromJson: _fromJsonProperties, name: 'properties', ) - final List sections; + final List sections; final List required; @JsonKey(name: 'x-order') final List order; static late Map orderMap; - const SchemaSegmentDto({ + const DocumentSchemaSegmentDto({ required this.ref, required this.id, this.title = '', @@ -128,19 +131,20 @@ class SchemaSegmentDto extends Equatable this.order = const [], }); - factory SchemaSegmentDto.fromJson(Map json) => - _$SchemaSegmentDtoFromJson(json); + factory DocumentSchemaSegmentDto.fromJson(Map json) => + _$DocumentSchemaSegmentDtoFromJson(json); - Map toJson() => _$SchemaSegmentDtoToJson(this); + Map toJson() => _$DocumentSchemaSegmentDtoToJson(this); - SchemaSegment toModel(List definitions) { + DocumentSchemaSegment toModel(List definitions) { orderMap = {for (var i = 0; i < order.length; i++) order[i]: i}; - final sortedProperties = List.from(this.sections)..sort(); + final sortedProperties = List.from(this.sections) + ..sort(); final sections = sortedProperties .where((element) => element.ref.contains('section')) .map((e) => e.toModel(definitions, isRequired: required.contains(e.id))) .toList(); - return SchemaSegment( + return DocumentSchemaSegment( ref: definitions.getDefinition(ref), id: id, title: title, @@ -161,7 +165,7 @@ class SchemaSegmentDto extends Equatable ]; static Map _toJsonProperties( - List sections, + List sections, ) { final map = {}; for (final property in sections) { @@ -170,22 +174,26 @@ class SchemaSegmentDto extends Equatable return map; } - static List _fromJsonProperties(Map json) { + static List _fromJsonProperties( + Map json, + ) { final listOfSections = json.convertMapToListWithIds(); - return listOfSections.map(SchemaSectionDto.fromJson).toList(); + return listOfSections.map(DocumentSchemaSectionDto.fromJson).toList(); } @override - int compareTo(SchemaSegmentDto other) { - final thisIndex = SchemaDto.orderMap[id] ?? double.maxFinite.toInt(); - final otherIndex = SchemaDto.orderMap[other.id] ?? double.maxFinite.toInt(); + int compareTo(DocumentSchemaSegmentDto other) { + final thisIndex = + DocumentSchemaDto.orderMap[id] ?? double.maxFinite.toInt(); + final otherIndex = + DocumentSchemaDto.orderMap[other.id] ?? double.maxFinite.toInt(); return thisIndex.compareTo(otherIndex); } } @JsonSerializable() -class SchemaSectionDto extends Equatable - implements Comparable { +class DocumentSchemaSectionDto extends Equatable + implements Comparable { @JsonKey(name: r'$ref') final String ref; final String id; @@ -196,7 +204,7 @@ class SchemaSectionDto extends Equatable fromJson: _fromJsonProperties, name: 'properties', ) - final List elements; + final List elements; final List required; @JsonKey(name: 'x-order') final List order; @@ -208,7 +216,7 @@ class SchemaSectionDto extends Equatable static late Map orderMap; - const SchemaSectionDto({ + const DocumentSchemaSectionDto({ required this.ref, required this.id, this.title = '', @@ -221,22 +229,23 @@ class SchemaSectionDto extends Equatable this.openSource = const {}, }); - factory SchemaSectionDto.fromJson(Map json) => - _$SchemaSectionDtoFromJson(json); + factory DocumentSchemaSectionDto.fromJson(Map json) => + _$DocumentSchemaSectionDtoFromJson(json); - Map toJson() => _$SchemaSectionDtoToJson(this); + Map toJson() => _$DocumentSchemaSectionDtoToJson(this); - SchemaSection toModel( - List definitions, { + DocumentSchemaSection toModel( + List definitions, { required bool isRequired, }) { orderMap = {for (var i = 0; i < order.length; i++) order[i]: i}; - final sortedElements = List.from(this.elements)..sort(); + final sortedElements = List.from(this.elements) + ..sort(); final elements = sortedElements - .where((element) => BaseDefinition.isKnownType(element.ref)) + .where((element) => BaseDocumentDefinition.isKnownType(element.ref)) .map((e) => e.toModel(definitions)) .toList(); - return SchemaSection( + return DocumentSchemaSection( ref: definitions.getDefinition(ref), id: id, title: title, @@ -260,7 +269,7 @@ class SchemaSectionDto extends Equatable ]; static Map _toJsonProperties( - List properties, + List properties, ) { final map = {}; for (final property in properties) { @@ -269,23 +278,26 @@ class SchemaSectionDto extends Equatable return map; } - static List _fromJsonProperties(Map json) { + static List _fromJsonProperties( + Map json, + ) { final listOfProperties = json.convertMapToListWithIds(); - return listOfProperties.map(SchemaElementDto.fromJson).toList(); + return listOfProperties.map(DocumentSchemaElementDto.fromJson).toList(); } @override - int compareTo(SchemaSectionDto other) { - final thisIndex = SchemaSegmentDto.orderMap[id] ?? double.maxFinite.toInt(); + int compareTo(DocumentSchemaSectionDto other) { + final thisIndex = + DocumentSchemaSegmentDto.orderMap[id] ?? double.maxFinite.toInt(); final otherIndex = - SchemaSegmentDto.orderMap[other.id] ?? double.maxFinite.toInt(); + DocumentSchemaSegmentDto.orderMap[other.id] ?? double.maxFinite.toInt(); return thisIndex.compareTo(otherIndex); } } @JsonSerializable() -class SchemaElementDto extends Equatable - implements Comparable { +class DocumentSchemaElementDto extends Equatable + implements Comparable { @JsonKey(name: r'$ref') final String ref; final String id; @@ -312,7 +324,7 @@ class SchemaElementDto extends Equatable // TODO(ryszard-schossler): return to this final Map items; - const SchemaElementDto({ + const DocumentSchemaElementDto({ this.ref = '', required this.id, this.title = '', @@ -329,13 +341,13 @@ class SchemaElementDto extends Equatable this.items = const {}, }); - factory SchemaElementDto.fromJson(Map json) => - _$SchemaElementDtoFromJson(json); + factory DocumentSchemaElementDto.fromJson(Map json) => + _$DocumentSchemaElementDtoFromJson(json); - Map toJson() => _$SchemaElementDtoToJson(this); + Map toJson() => _$DocumentSchemaElementDtoToJson(this); - SchemaElement toModel(List definitions) { - return SchemaElement( + DocumentSchemaElement toModel(List definitions) { + return DocumentSchemaElement( ref: definitions.getDefinition(ref), id: id, title: title, @@ -368,10 +380,11 @@ class SchemaElementDto extends Equatable ]; @override - int compareTo(SchemaElementDto other) { - final thisIndex = SchemaSectionDto.orderMap[id] ?? double.maxFinite.toInt(); + int compareTo(DocumentSchemaElementDto other) { + final thisIndex = + DocumentSchemaSectionDto.orderMap[id] ?? double.maxFinite.toInt(); final otherIndex = - SchemaSectionDto.orderMap[other.id] ?? double.maxFinite.toInt(); + DocumentSchemaSectionDto.orderMap[other.id] ?? double.maxFinite.toInt(); return thisIndex.compareTo(otherIndex); } } diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/proposal/proposal_builder_test.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/document_builder/document_builder_test.dart similarity index 65% rename from catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/proposal/proposal_builder_test.dart rename to catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/document_builder/document_builder_test.dart index 1e36fca1c8c..3a73ea05d39 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/proposal/proposal_builder_test.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/document_builder/document_builder_test.dart @@ -1,8 +1,8 @@ import 'dart:convert'; import 'package:catalyst_voices_models/catalyst_voices_models.dart'; -import 'package:catalyst_voices_repositories/src/dto/proposal_builder_dto.dart'; -import 'package:catalyst_voices_repositories/src/dto/schema_dto.dart'; +import 'package:catalyst_voices_repositories/src/dto/document_builder_dto.dart'; +import 'package:catalyst_voices_repositories/src/dto/document_schema_dto.dart'; import 'package:test/test.dart'; import '../../helpers/read_json.dart'; @@ -18,11 +18,11 @@ void main() { }); test('Converts segments list into object for JSON', () { - final schemaDto = SchemaDto.fromJson(schemaJson); + final schemaDto = DocumentSchemaDto.fromJson(schemaJson); final schema = schemaDto.toModel(); - final proposalBuilder = ProposalBuilder.build(schema); - final proposalBuilderDto = ProposalBuilderDto.fromModel(proposalBuilder); + final proposalBuilder = DocumentBuilder.build(schema); + final proposalBuilderDto = DocumentBuilderDto.fromModel(proposalBuilder); final proposalBuilderJson = proposalBuilderDto.toJson(); for (final segment in proposalBuilderDto.segments) { @@ -31,15 +31,15 @@ void main() { }); test('Converts object from JSON into List of segments', () { - final schemaDto = SchemaDto.fromJson(schemaJson); + final schemaDto = DocumentSchemaDto.fromJson(schemaJson); final schema = schemaDto.toModel(); - final proposalBuilder = ProposalBuilder.build(schema); - final proposalBuilderDto = ProposalBuilderDto.fromModel(proposalBuilder); + final proposalBuilder = DocumentBuilder.build(schema); + final proposalBuilderDto = DocumentBuilderDto.fromModel(proposalBuilder); final proposalBuilderJson = proposalBuilderDto.toJson(); final proposalBuilderDtoFromJson = - ProposalBuilderDto.fromJson(proposalBuilderJson); + DocumentBuilderDto.fromJson(proposalBuilderJson); expect( proposalBuilderDtoFromJson.segments.length, diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/schema/definitions_test.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/document_builder/document_definitions_test.dart similarity index 79% rename from catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/schema/definitions_test.dart rename to catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/document_builder/document_definitions_test.dart index 54ac986d8b8..b586fc8ac06 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/schema/definitions_test.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/document_builder/document_definitions_test.dart @@ -1,7 +1,7 @@ import 'dart:convert'; import 'package:catalyst_voices_models/catalyst_voices_models.dart'; -import 'package:catalyst_voices_repositories/src/dto/schema_dto.dart'; +import 'package:catalyst_voices_repositories/src/dto/document_schema_dto.dart'; import 'package:test/test.dart'; import '../../helpers/read_json.dart'; @@ -19,10 +19,11 @@ void main() { // ignore: lines_longer_than_80_chars 'Check if all definition are in definition list inside DefinitionDto model', () async { - final schemaDto = SchemaDto.fromJson(schemaJson); + final schemaDto = DocumentSchemaDto.fromJson(schemaJson); final definitions = schemaDto.definitions.definitionsModels; - for (final value in BaseDefinition.refPathToDefinitionType.values) { + for (final value + in BaseDocumentDefinition.refPathToDefinitionType.values) { final occurrences = definitions.where((element) => element.runtimeType == value).length; expect( diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/schema/schema_test.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/document_builder/document_schema_test.dart similarity index 84% rename from catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/schema/schema_test.dart rename to catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/document_builder/document_schema_test.dart index a1896d191db..de5e7fb3a90 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/schema/schema_test.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/document_builder/document_schema_test.dart @@ -1,7 +1,7 @@ import 'dart:convert'; import 'package:catalyst_voices_models/catalyst_voices_models.dart'; -import 'package:catalyst_voices_repositories/src/dto/schema_dto.dart'; +import 'package:catalyst_voices_repositories/src/dto/document_schema_dto.dart'; import 'package:test/test.dart'; import '../../helpers/read_json.dart'; @@ -17,7 +17,7 @@ void main() { }); test('X-order of segments is kept in model class', () async { - final schemaDto = SchemaDto.fromJson(schemaJson); + final schemaDto = DocumentSchemaDto.fromJson(schemaJson); final schema = schemaDto.toModel(); @@ -30,7 +30,7 @@ void main() { }); test('X-order of section is kept in model class', () { - final schemaDto = SchemaDto.fromJson(schemaJson); + final schemaDto = DocumentSchemaDto.fromJson(schemaJson); final schema = schemaDto.toModel(); for (var i = 0; i < schema.segments.length; i++) { @@ -48,7 +48,7 @@ void main() { }); test('Check if every segment has a SegmentDefinition as ref', () { - final schemaDto = SchemaDto.fromJson(schemaJson); + final schemaDto = DocumentSchemaDto.fromJson(schemaJson); final schema = schemaDto.toModel(); for (final segment in schema.segments) { From b32655817e6750223fdd31a67d3ff9602e4bc5a0 Mon Sep 17 00:00:00 2001 From: Ryszard Schossler Date: Fri, 20 Dec 2024 14:27:28 +0100 Subject: [PATCH 14/18] feat: change name of the document property widget --- .../{document_definition.dart => document_property.dart} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename catalyst_voices/apps/voices/lib/widgets/document_builder/{document_definition.dart => document_property.dart} (93%) diff --git a/catalyst_voices/apps/voices/lib/widgets/document_builder/document_definition.dart b/catalyst_voices/apps/voices/lib/widgets/document_builder/document_property.dart similarity index 93% rename from catalyst_voices/apps/voices/lib/widgets/document_builder/document_definition.dart rename to catalyst_voices/apps/voices/lib/widgets/document_builder/document_property.dart index fe7398b2233..672c9f2ab97 100644 --- a/catalyst_voices/apps/voices/lib/widgets/document_builder/document_definition.dart +++ b/catalyst_voices/apps/voices/lib/widgets/document_builder/document_property.dart @@ -1,9 +1,9 @@ import 'package:catalyst_voices_models/catalyst_voices_models.dart'; import 'package:flutter/material.dart'; -class SchemaDefinition extends StatelessWidget { +class DocumentPropertyWidget extends StatelessWidget { final BaseDocumentDefinition definition; - const SchemaDefinition({super.key, required this.definition}); + const DocumentPropertyWidget({super.key, required this.definition}); @override Widget build(BuildContext context) { From e5e89d24e4cd0d42075477e2f699e23e6797a88d Mon Sep 17 00:00:00 2001 From: Ryszard Schossler Date: Fri, 20 Dec 2024 16:59:45 +0100 Subject: [PATCH 15/18] feat: adding equatable for classes --- .../document_builder/document_builder.dart | 21 +- .../document_definitions.dart | 227 ++++++++++++++-- .../src/document_builder/document_schema.dart | 55 +++- .../lib/src/dto/document_builder_dto.dart | 23 +- .../lib/src/dto/document_definitions_dto.dart | 244 ++++++++++++++++-- .../lib/src/dto/document_schema_dto.dart | 8 +- .../test/assets/generic_proposal copy.json | 138 ---------- .../document_definitions_test.dart | 14 + .../lib/src/range/range.dart | 9 +- .../catalyst_voices_shared/pubspec.yaml | 1 + 10 files changed, 532 insertions(+), 208 deletions(-) delete mode 100644 catalyst_voices/packages/internal/catalyst_voices_repositories/test/assets/generic_proposal copy.json diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/document_builder/document_builder.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/document_builder/document_builder.dart index fae7414c379..2b4eb0cad06 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/document_builder/document_builder.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/document_builder/document_builder.dart @@ -1,6 +1,7 @@ import 'package:catalyst_voices_models/src/document_builder/document_schema.dart'; +import 'package:equatable/equatable.dart'; -class DocumentBuilder { +class DocumentBuilder extends Equatable { final String schema; final List segments; @@ -36,9 +37,12 @@ class DocumentBuilder { .toList(), ); } + + @override + List get props => [schema, segments]; } -class DocumentBuilderSegment { +class DocumentBuilderSegment extends Equatable { final String id; final List sections; @@ -46,9 +50,12 @@ class DocumentBuilderSegment { required this.id, required this.sections, }); + + @override + List get props => [id, sections]; } -class DocumentBuilderSection { +class DocumentBuilderSection extends Equatable { final String id; final List elements; @@ -56,9 +63,12 @@ class DocumentBuilderSection { required this.id, required this.elements, }); + + @override + List get props => [id, elements]; } -class DocumentBuilderElement { +class DocumentBuilderElement extends Equatable { final String id; final dynamic value; @@ -66,4 +76,7 @@ class DocumentBuilderElement { required this.id, required this.value, }); + + @override + List get props => [id, value]; } diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/document_builder/document_definitions.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/document_builder/document_definitions.dart index 6cc9f4c4dc6..f2c20cf8bdb 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/document_builder/document_definitions.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/document_builder/document_definitions.dart @@ -1,3 +1,5 @@ +import 'package:collection/collection.dart'; +import 'package:equatable/equatable.dart'; import 'package:meta/meta.dart'; enum DocumentDefinitionsObjectType { @@ -30,45 +32,49 @@ enum DocumentDefinitionsContentMediaType { markdown('text/markdown'), unknown('unknown'); - final String value; + final String schemaValue; - const DocumentDefinitionsContentMediaType(this.value); + const DocumentDefinitionsContentMediaType(this.schemaValue); static DocumentDefinitionsContentMediaType fromString(String value) { - return DocumentDefinitionsContentMediaType.values.asNameMap()[value] ?? + return DocumentDefinitionsContentMediaType.values + .firstWhereOrNull((e) => e.schemaValue.toLowerCase() == value) ?? DocumentDefinitionsContentMediaType.unknown; } } enum DocumentDefinitionsFormat { - path, - uri, - dropDownSingleSelect, - multiSelect, - singleLineTextEntryList, - singleLineTextEntryListMarkdown, - singleLineHttpsURLEntryList, - nestedQuestionsList, - nestedQuestions, - singleGroupedTagSelector, - tagGroup, - tagSelection, - tokenValueCardanoADA, - datetimeDurationMonths, - yesNoChoice, - agreementConfirmation, - spdxLicenseOrURL, - unknown; + path('path'), + uri('uri'), + dropDownSingleSelect('dropDownSingleSelect'), + multiSelect('multiSelect'), + singleLineTextEntryList('singleLineTextEntryList'), + singleLineTextEntryListMarkdown('singleLineTextEntryListMarkdown'), + singleLineHttpsURLEntryList('singleLineHttpsURLEntryList'), + nestedQuestionsList('nestedQuestionsList'), + nestedQuestions('nestedQuestions'), + singleGroupedTagSelector('singleGroupedTagSelector'), + tagGroup('tagGroup'), + tagSelection('tagSelection'), + tokenCardanoADA('token:cardano:ada'), + durationInMonths('datetime:duration:months'), + yesNoChoice('yesNoChoice'), + agreementConfirmation('agreementConfirmation'), + spdxLicenseOrURL('spdxLicenseOrURL'), + unknown('unknown'); - const DocumentDefinitionsFormat(); + final String value; + + const DocumentDefinitionsFormat(this.value); static DocumentDefinitionsFormat fromString(String value) { - return DocumentDefinitionsFormat.values.asNameMap()[value] ?? + return DocumentDefinitionsFormat.values + .firstWhereOrNull((e) => e.value.toLowerCase() == value) ?? DocumentDefinitionsFormat.unknown; } } -sealed class BaseDocumentDefinition { +sealed class BaseDocumentDefinition extends Equatable { final DocumentDefinitionsObjectType type; final String note; @@ -130,6 +136,13 @@ class SegmentDefinition extends BaseDocumentDefinition { required super.note, required this.additionalProperties, }); + + @override + List get props => [ + type, + note, + additionalProperties, + ]; } class SectionDefinition extends BaseDocumentDefinition { @@ -140,6 +153,13 @@ class SectionDefinition extends BaseDocumentDefinition { required super.note, required this.additionalProperties, }); + + @override + List get props => [ + additionalProperties, + type, + note, + ]; } class SingleLineTextEntryDefinition extends BaseDocumentDefinition { @@ -152,6 +172,14 @@ class SingleLineTextEntryDefinition extends BaseDocumentDefinition { required this.contentMediaType, required this.pattern, }); + + @override + List get props => [ + contentMediaType, + pattern, + type, + note, + ]; } class SingleLineHttpsURLEntryDefinition extends BaseDocumentDefinition { @@ -164,6 +192,14 @@ class SingleLineHttpsURLEntryDefinition extends BaseDocumentDefinition { required this.format, required this.pattern, }); + + @override + List get props => [ + format, + pattern, + type, + note, + ]; } class MultiLineTextEntryDefinition extends BaseDocumentDefinition { @@ -176,6 +212,14 @@ class MultiLineTextEntryDefinition extends BaseDocumentDefinition { required this.contentMediaType, required this.pattern, }); + + @override + List get props => [ + contentMediaType, + pattern, + type, + note, + ]; } class MultiLineTextEntryMarkdownDefinition extends BaseDocumentDefinition { @@ -188,6 +232,14 @@ class MultiLineTextEntryMarkdownDefinition extends BaseDocumentDefinition { required this.contentMediaType, required this.pattern, }); + + @override + List get props => [ + contentMediaType, + pattern, + type, + note, + ]; } class DropDownSingleSelectDefinition extends BaseDocumentDefinition { @@ -202,6 +254,15 @@ class DropDownSingleSelectDefinition extends BaseDocumentDefinition { required this.contentMediaType, required this.pattern, }); + + @override + List get props => [ + format, + contentMediaType, + pattern, + type, + note, + ]; } class MultiSelectDefinition extends BaseDocumentDefinition { @@ -214,6 +275,14 @@ class MultiSelectDefinition extends BaseDocumentDefinition { required this.format, required this.uniqueItems, }); + + @override + List get props => [ + format, + uniqueItems, + type, + note, + ]; } class SingleLineTextEntryListDefinition extends BaseDocumentDefinition { @@ -230,6 +299,16 @@ class SingleLineTextEntryListDefinition extends BaseDocumentDefinition { required this.defaultValues, required this.items, }); + + @override + List get props => [ + format, + uniqueItems, + type, + note, + defaultValues, + items, + ]; } class MultiLineTextEntryListMarkdownDefinition extends BaseDocumentDefinition { @@ -246,6 +325,16 @@ class MultiLineTextEntryListMarkdownDefinition extends BaseDocumentDefinition { required this.defaultValue, required this.items, }); + + @override + List get props => [ + format, + uniqueItems, + type, + note, + defaultValue, + items, + ]; } class SingleLineHttpsURLEntryListDefinition extends BaseDocumentDefinition { @@ -262,6 +351,16 @@ class SingleLineHttpsURLEntryListDefinition extends BaseDocumentDefinition { required this.defaultValue, required this.items, }); + + @override + List get props => [ + format, + uniqueItems, + type, + note, + defaultValue, + items, + ]; } class NestedQuestionsListDefinition extends BaseDocumentDefinition { @@ -276,6 +375,15 @@ class NestedQuestionsListDefinition extends BaseDocumentDefinition { required this.uniqueItems, required this.defaultValue, }); + + @override + List get props => [ + format, + uniqueItems, + type, + note, + defaultValue, + ]; } class NestedQuestionsDefinition extends BaseDocumentDefinition { @@ -287,6 +395,14 @@ class NestedQuestionsDefinition extends BaseDocumentDefinition { required this.format, required this.additionalProperties, }); + + @override + List get props => [ + format, + additionalProperties, + type, + note, + ]; } class SingleGroupedTagSelectorDefinition extends BaseDocumentDefinition { @@ -299,6 +415,14 @@ class SingleGroupedTagSelectorDefinition extends BaseDocumentDefinition { required this.format, required this.additionalProperties, }); + + @override + List get props => [ + format, + additionalProperties, + type, + note, + ]; } class TagGroupDefinition extends BaseDocumentDefinition { @@ -311,6 +435,14 @@ class TagGroupDefinition extends BaseDocumentDefinition { required this.format, required this.pattern, }); + + @override + List get props => [ + format, + pattern, + type, + note, + ]; } class TagSelectionDefinition extends BaseDocumentDefinition { @@ -323,6 +455,14 @@ class TagSelectionDefinition extends BaseDocumentDefinition { required this.format, required this.pattern, }); + + @override + List get props => [ + format, + pattern, + type, + note, + ]; } class TokenValueCardanoADADefinition extends BaseDocumentDefinition { @@ -333,6 +473,13 @@ class TokenValueCardanoADADefinition extends BaseDocumentDefinition { required super.note, required this.format, }); + + @override + List get props => [ + format, + type, + note, + ]; } class DurationInMonthsDefinition extends BaseDocumentDefinition { @@ -343,6 +490,13 @@ class DurationInMonthsDefinition extends BaseDocumentDefinition { required super.note, required this.format, }); + + @override + List get props => [ + type, + note, + format, + ]; } class YesNoChoiceDefinition extends BaseDocumentDefinition { @@ -355,6 +509,14 @@ class YesNoChoiceDefinition extends BaseDocumentDefinition { required this.format, required this.defaultValue, }); + + @override + List get props => [ + format, + defaultValue, + type, + note, + ]; } class AgreementConfirmationDefinition extends BaseDocumentDefinition { @@ -369,6 +531,15 @@ class AgreementConfirmationDefinition extends BaseDocumentDefinition { required this.defaultValue, required this.constValue, }); + + @override + List get props => [ + format, + defaultValue, + constValue, + type, + note, + ]; } class SPDXLicenceOrUrlDefinition extends BaseDocumentDefinition { @@ -383,4 +554,12 @@ class SPDXLicenceOrUrlDefinition extends BaseDocumentDefinition { required this.pattern, required this.contentMediaType, }); + + @override + List get props => [ + format, + pattern, + type, + note, + ]; } diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/document_builder/document_schema.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/document_builder/document_schema.dart index 55488e173a4..53e64c7d217 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/document_builder/document_schema.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/document_builder/document_schema.dart @@ -1,7 +1,8 @@ import 'package:catalyst_voices_models/src/document_builder/document_definitions.dart'; import 'package:catalyst_voices_shared/catalyst_voices_shared.dart'; +import 'package:equatable/equatable.dart'; -class DocumentSchema { +class DocumentSchema extends Equatable { final String schema; final String title; final String description; @@ -17,9 +18,19 @@ class DocumentSchema { required this.order, required this.propertiesSchema, }); + + @override + List get props => [ + schema, + title, + description, + segments, + order, + propertiesSchema, + ]; } -class DocumentSchemaSegment { +class DocumentSchemaSegment extends Equatable { final BaseDocumentDefinition ref; final String id; final String title; @@ -33,9 +44,17 @@ class DocumentSchemaSegment { required this.description, required this.sections, }); + + @override + List get props => [ + id, + title, + description, + sections, + ]; } -class DocumentSchemaSection { +class DocumentSchemaSection extends Equatable { final BaseDocumentDefinition ref; final String id; final String title; @@ -51,15 +70,24 @@ class DocumentSchemaSection { required this.elements, required this.isRequired, }); + + @override + List get props => [ + ref, + id, + title, + description, + elements, + isRequired, + ]; } -class DocumentSchemaElement { +class DocumentSchemaElement extends Equatable { final BaseDocumentDefinition ref; final String id; final String title; final String description; - final int? minLength; - final int? maxLength; + final String? defaultValue; final String guidance; final List enumValues; @@ -71,12 +99,23 @@ class DocumentSchemaElement { required this.id, required this.title, required this.description, - this.minLength, - this.maxLength, required this.defaultValue, required this.guidance, this.enumValues = const [], required this.range, required this.itemsRange, }); + + @override + List get props => [ + ref, + id, + title, + description, + defaultValue, + guidance, + enumValues, + range, + itemsRange, + ]; } diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/document_builder_dto.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/document_builder_dto.dart index abf66f62347..58c596390e8 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/document_builder_dto.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/document_builder_dto.dart @@ -1,11 +1,12 @@ import 'package:catalyst_voices_models/catalyst_voices_models.dart'; import 'package:catalyst_voices_shared/catalyst_voices_shared.dart'; +import 'package:equatable/equatable.dart'; import 'package:json_annotation/json_annotation.dart'; part 'document_builder_dto.g.dart'; @JsonSerializable() -class DocumentBuilderDto { +class DocumentBuilderDto extends Equatable { @JsonKey(name: r'$schema') final String schema; @JsonKey(fromJson: _fromJsonSegments, toJson: _toJsonSegments) @@ -59,10 +60,13 @@ class DocumentBuilderDto { final listOfSegments = json.convertMapToListWithIds(); return listOfSegments.map(DocumentBuilderSegmentDto.fromJson).toList(); } + + @override + List get props => [schema, segments]; } @JsonSerializable() -class DocumentBuilderSegmentDto { +class DocumentBuilderSegmentDto extends Equatable { final String id; @JsonKey(fromJson: _fromJsonSections, toJson: _toJsonSections) final List sections; @@ -118,15 +122,18 @@ class DocumentBuilderSegmentDto { final listOfSections = json.convertMapToListWithIds(); return listOfSections.map(DocumentBuilderSectionDto.fromJson).toList(); } + + @override + List get props => [id, sections]; } @JsonSerializable() -class DocumentBuilderSectionDto { +class DocumentBuilderSectionDto extends Equatable { final String id; @JsonKey(fromJson: _fromJsonElements, toJson: _toJsonElements) final List elements; - DocumentBuilderSectionDto({ + const DocumentBuilderSectionDto({ required this.id, required this.elements, }); @@ -177,10 +184,13 @@ class DocumentBuilderSectionDto { final listOfElements = json.convertMapToListWithIdsAndValues(); return listOfElements.map(DocumentBuilderElementDto.fromJson).toList(); } + + @override + List get props => [id, elements]; } @JsonSerializable() -class DocumentBuilderElementDto { +class DocumentBuilderElementDto extends Equatable { final String id; final dynamic value; @@ -210,4 +220,7 @@ class DocumentBuilderElementDto { value: value, ); } + + @override + List get props => [id, value]; } diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/document_definitions_dto.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/document_definitions_dto.dart index a01c02ed5fb..9b8d064108a 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/document_definitions_dto.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/document_definitions_dto.dart @@ -1,10 +1,11 @@ import 'package:catalyst_voices_models/catalyst_voices_models.dart'; +import 'package:equatable/equatable.dart'; import 'package:json_annotation/json_annotation.dart'; part 'document_definitions_dto.g.dart'; @JsonSerializable() -class DocumentDefinitionsDto { +class DocumentDefinitionsDto extends Equatable { final SegmentDto segment; final SectionDto section; final SingleLineTextEntryDto singleLineTextEntry; @@ -81,10 +82,35 @@ class DocumentDefinitionsDto { agreementConfirmation.toModel(), spdxLicenceOrUrl.toModel(), ]; + + @override + List get props => [ + section, + segment, + singleLineTextEntry, + singleLineHttpsURLEntry, + multiLineTextEntry, + multiLineTextEntryMarkdown, + dropDownSingleSelect, + multiSelect, + singleLineTextEntryList, + multiLineTextEntryListMarkdown, + singleLineHttpsURLEntryList, + nestedQuestionsList, + nestedQuestions, + singleGroupedTagSelector, + tagGroup, + tagSelection, + tokenValueCardanoAda, + durationInMonths, + yesNoChoice, + agreementConfirmation, + spdxLicenceOrUrl, + ]; } @JsonSerializable() -class SegmentDto { +class SegmentDto extends Equatable { final String type; final bool additionalProperties; @JsonKey(name: 'x-note') @@ -106,10 +132,17 @@ class SegmentDto { note: note, additionalProperties: additionalProperties, ); + + @override + List get props => [ + type, + additionalProperties, + note, + ]; } @JsonSerializable() -class SectionDto { +class SectionDto extends Equatable { final String type; final bool additionalProperties; @JsonKey(name: 'x-note') @@ -131,10 +164,17 @@ class SectionDto { note: note, additionalProperties: additionalProperties, ); + + @override + List get props => [ + type, + additionalProperties, + note, + ]; } @JsonSerializable() -class SingleLineTextEntryDto { +class SingleLineTextEntryDto extends Equatable { final String type; final String contentMediaType; final String pattern; @@ -160,10 +200,18 @@ class SingleLineTextEntryDto { DocumentDefinitionsContentMediaType.fromString(contentMediaType), pattern: pattern, ); + + @override + List get props => [ + type, + contentMediaType, + pattern, + note, + ]; } @JsonSerializable() -class SingleLineHttpsURLEntryDto { +class SingleLineHttpsURLEntryDto extends Equatable { final String type; final String format; final String pattern; @@ -190,10 +238,18 @@ class SingleLineHttpsURLEntryDto { pattern: pattern, ); } + + @override + List get props => [ + type, + format, + pattern, + note, + ]; } @JsonSerializable() -class MultiLineTextEntryDto { +class MultiLineTextEntryDto extends Equatable { final String type; final String contentMediaType; final String pattern; @@ -221,10 +277,18 @@ class MultiLineTextEntryDto { pattern: pattern, ); } + + @override + List get props => [ + type, + contentMediaType, + pattern, + note, + ]; } @JsonSerializable() -class MultiLineTextEntryMarkdownDto { +class MultiLineTextEntryMarkdownDto extends Equatable { final String type; final String contentMediaType; final String pattern; @@ -252,10 +316,18 @@ class MultiLineTextEntryMarkdownDto { pattern: pattern, ); } + + @override + List get props => [ + type, + contentMediaType, + pattern, + note, + ]; } @JsonSerializable() -class DropDownSingleSelectDto { +class DropDownSingleSelectDto extends Equatable { final String type; final String contentMediaType; final String pattern; @@ -286,10 +358,19 @@ class DropDownSingleSelectDto { format: DocumentDefinitionsFormat.fromString(format), ); } + + @override + List get props => [ + type, + contentMediaType, + pattern, + format, + note, + ]; } @JsonSerializable() -class MultiSelectDto { +class MultiSelectDto extends Equatable { final String type; final bool uniqueItems; final String format; @@ -316,10 +397,18 @@ class MultiSelectDto { uniqueItems: uniqueItems, ); } + + @override + List get props => [ + type, + uniqueItems, + note, + format, + ]; } @JsonSerializable() -class SingleLineTextEntryListDto { +class SingleLineTextEntryListDto extends Equatable { final String type; final String format; final bool uniqueItems; @@ -352,10 +441,20 @@ class SingleLineTextEntryListDto { defaultValues: defaultValue, items: items, ); + + @override + List get props => [ + type, + note, + format, + uniqueItems, + defaultValue, + items, + ]; } @JsonSerializable() -class MultiLineTextEntryListMarkdownDto { +class MultiLineTextEntryListMarkdownDto extends Equatable { final String type; final String format; final bool uniqueItems; @@ -391,10 +490,20 @@ class MultiLineTextEntryListMarkdownDto { defaultValue: defaultValue, items: items, ); + + @override + List get props => [ + type, + note, + format, + uniqueItems, + defaultValue, + items, + ]; } @JsonSerializable() -class SingleLineHttpsURLEntryListDto { +class SingleLineHttpsURLEntryListDto extends Equatable { final String type; final String format; final bool uniqueItems; @@ -427,10 +536,20 @@ class SingleLineHttpsURLEntryListDto { defaultValue: defaultValue, items: items, ); + + @override + List get props => [ + type, + note, + format, + uniqueItems, + defaultValue, + items, + ]; } @JsonSerializable() -class NestedQuestionsListDto { +class NestedQuestionsListDto extends Equatable { final String type; final String format; final bool uniqueItems; @@ -459,10 +578,19 @@ class NestedQuestionsListDto { uniqueItems: uniqueItems, defaultValue: defaultValue, ); + + @override + List get props => [ + type, + note, + format, + uniqueItems, + defaultValue, + ]; } @JsonSerializable() -class NestedQuestionsDto { +class NestedQuestionsDto extends Equatable { final String type; final String format; final bool additionalProperties; @@ -489,10 +617,18 @@ class NestedQuestionsDto { additionalProperties: additionalProperties, ); } + + @override + List get props => [ + type, + format, + note, + additionalProperties, + ]; } @JsonSerializable() -class SingleGroupedTagSelectorDto { +class SingleGroupedTagSelectorDto extends Equatable { final String type; final String format; final bool additionalProperties; @@ -519,10 +655,18 @@ class SingleGroupedTagSelectorDto { additionalProperties: additionalProperties, ); } + + @override + List get props => [ + type, + format, + note, + additionalProperties, + ]; } @JsonSerializable() -class TagGroupDto { +class TagGroupDto extends Equatable { final String type; final String format; final String pattern; @@ -549,10 +693,18 @@ class TagGroupDto { pattern: pattern, ); } + + @override + List get props => [ + type, + format, + pattern, + note, + ]; } @JsonSerializable() -class TagSelectionDto { +class TagSelectionDto extends Equatable { final String type; final String format; final String pattern; @@ -579,10 +731,18 @@ class TagSelectionDto { pattern: pattern, ); } + + @override + List get props => [ + type, + format, + pattern, + note, + ]; } @JsonSerializable() -class TokenValueCardanoAdaDto { +class TokenValueCardanoAdaDto extends Equatable { final String type; final String format; @JsonKey(name: 'x-note') @@ -604,10 +764,17 @@ class TokenValueCardanoAdaDto { note: note, format: DocumentDefinitionsFormat.fromString(format), ); + + @override + List get props => [ + type, + note, + format, + ]; } @JsonSerializable() -class DurationInMonthsDto { +class DurationInMonthsDto extends Equatable { final String type; final String format; @JsonKey(name: 'x-note') @@ -631,10 +798,17 @@ class DurationInMonthsDto { format: DocumentDefinitionsFormat.fromString(format), ); } + + @override + List get props => [ + type, + format, + note, + ]; } @JsonSerializable() -class YesNoChoiceDto { +class YesNoChoiceDto extends Equatable { final String type; final String format; @JsonKey(name: 'default') @@ -660,10 +834,18 @@ class YesNoChoiceDto { format: DocumentDefinitionsFormat.fromString(format), defaultValue: defaultValue, ); + + @override + List get props => [ + type, + format, + note, + defaultValue, + ]; } @JsonSerializable() -class AgreementConfirmationDto { +class AgreementConfirmationDto extends Equatable { final String type; final String format; @JsonKey(name: 'default') @@ -693,10 +875,19 @@ class AgreementConfirmationDto { defaultValue: defaultValue, constValue: constValue, ); + + @override + List get props => [ + type, + format, + note, + defaultValue, + constValue, + ]; } @JsonSerializable() -class SPDXLicenceOrUrlDto { +class SPDXLicenceOrUrlDto extends Equatable { final String type; final String contentMediaType; final String pattern; @@ -725,4 +916,13 @@ class SPDXLicenceOrUrlDto { contentMediaType: DocumentDefinitionsContentMediaType.fromString(contentMediaType), ); + + @override + List get props => [ + type, + format, + note, + pattern, + contentMediaType, + ]; } diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/document_schema_dto.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/document_schema_dto.dart index 1a098fd52ab..418dfeb012f 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/document_schema_dto.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/document_schema_dto.dart @@ -45,7 +45,7 @@ class DocumentSchemaDto extends Equatable { factory DocumentSchemaDto.fromJson(Map json) { final segmentsMap = json['properties'] as Map; - json['propertiesDocumentSchema'] = + json['propertiesSchema'] = (segmentsMap[r'$schema'] as Map)['const']; return _$DocumentSchemaDtoFromJson(json); @@ -352,13 +352,11 @@ class DocumentSchemaElementDto extends Equatable id: id, title: title, description: description, - minLength: minLength, - maxLength: maxLength, defaultValue: defaultValue, guidance: guidance, enumValues: enumValues, - range: Range.createIntRange(min: minimum, max: maximum), - itemsRange: Range.createIntRange(min: minItems, max: maxItems), + range: Range.optionalRangeOf(min: minimum, max: maximum), + itemsRange: Range.optionalRangeOf(min: minItems, max: maxItems), ); } diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/assets/generic_proposal copy.json b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/assets/generic_proposal copy.json deleted file mode 100644 index e0100f00cc8..00000000000 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/assets/generic_proposal copy.json +++ /dev/null @@ -1,138 +0,0 @@ -{ - "$schema": "./0ce8ab38-9258-4fbc-a62e-7faa6e58318f.schema.json", - "setup": { - "title": { - "title": "Example Catalyst Proposal" - }, - "proposer": { - "applicant": "John Smith", - "type": "Individual", - "coproposers": [ - "Jane Doe", - "Bob Wilson" - ] - } - }, - "summary": { - "budget": { - "requestedFunds": 150000 - }, - "time": { - "duration": 6 - }, - "translation": { - "isTranslated": true, - "originalLanguage": "German", - "originalDocumentLink": "https://example.com/original-doc" - }, - "problem": { - "statement": "Current challenge in the Cardano ecosystem...", - "impact": [ - "Technical Infrastructure", - "Developer Tooling", - "Adoption" - ] - }, - "solution": { - "summary": "Our solution provides a comprehensive toolkit...", - "approach": "We will implement this solution using...", - "innovationAspects": [ - "Novel testing framework", - "Automated integration tools" - ] - }, - "supportingLinks": { - "mainRepository": "https://github.com/example/project", - "documentation": "https://docs.example.com", - "other": [ - "https://example.com/whitepaper", - "https://example.com/roadmap" - ] - }, - "dependencies": { - "details": [ - { - "name": "External API Service", - "type": "Technical", - "description": "Integration with third-party API service", - "mitigationPlan": "Build fallback mechanisms and maintain alternative providers" - } - ] - }, - "open_source": { - "source_code": "MIT", - "documentation": "MIT", - "note": "All project outputs will be open source under MIT license" - } - }, - "horizons": { - "theme": { - "grouped_tag": { - "group": "DeFi", - "tag": "Staking" - } - } - }, - "details": { - "solution": { - "solution": "Our solution involves developing a comprehensive toolkit that will enhance the Cardano developer experience..." - }, - "impact": { - "impact": "The project will significantly impact developer productivity by reducing development time and improving code quality..." - }, - "feasibility": { - "feasibility": "Our team has extensive experience in blockchain development and has successfully delivered similar projects..." - } - }, - "milestones": { - "milestones": { - "milestone_list": [ - { - "title": "Initial Setup and Planning", - "outputs": "Project infrastructure setup and detailed planning documents", - "acceptance_criteria": "- Development environment configured\n- Detailed project plan approved", - "evidence": "- GitHub repository setup\n- Documentation of infrastructure\n- Project planning documents", - "delivery_month": 1, - "cost": 30000, - "progress": "Not Started" - }, - { - "title": "Core Development", - "outputs": "Implementation of main features", - "acceptance_criteria": "- Core features implemented\n- Unit tests passing", - "evidence": "- Code repository\n- Test results\n- Technical documentation", - "delivery_month": 3, - "cost": 60000, - "progress": "Not Started" - }, - { - "title": "Final Release and Documentation", - "outputs": "Project completion, documentation, and Project Close-out Report and Video", - "acceptance_criteria": "- All features implemented and tested\n- Documentation complete\n- Close-out report and video delivered", - "evidence": "- Final release\n- Complete documentation\n- Close-out report and video", - "delivery_month": 6, - "cost": 60000, - "progress": "Not Started" - } - ] - } - }, - "pitch": { - "team": { - "who": "Our team consists of experienced blockchain developers with proven track records..." - }, - "budget": { - "costs": "Budget breakdown:\n- Development (70%): 105,000 ADA\n- Testing (15%): 22,500 ADA\n- Documentation (15%): 22,500 ADA" - }, - "value": { - "note": "This project provides excellent value for money by delivering essential developer tools..." - } - }, - "agreements": { - "mandatory": { - "fund_rules": true, - "terms_and_conditions": true, - "privacy_policy": true - } - } -} \ No newline at end of file diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/document_builder/document_definitions_test.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/document_builder/document_definitions_test.dart index b586fc8ac06..b2123c320f9 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/document_builder/document_definitions_test.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/document_builder/document_definitions_test.dart @@ -34,4 +34,18 @@ void main() { } }, ); + + test('Check if document definition media type is parse correctly', () { + final schemaDto = DocumentSchemaDto.fromJson(schemaJson); + final definitions = schemaDto.definitions.definitionsModels; + + final singleLineTextEntry = + definitions.getDefinition('#/definitions/singleLineTextEntry') + as SingleLineTextEntryDefinition; + + expect( + singleLineTextEntry.contentMediaType, + DocumentDefinitionsContentMediaType.textPlain, + ); + }); } diff --git a/catalyst_voices/packages/internal/catalyst_voices_shared/lib/src/range/range.dart b/catalyst_voices/packages/internal/catalyst_voices_shared/lib/src/range/range.dart index 667644805c2..ad17adab392 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_shared/lib/src/range/range.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_shared/lib/src/range/range.dart @@ -1,13 +1,18 @@ -class Range { +import 'package:equatable/equatable.dart'; + +class Range extends Equatable { final T min; final T max; const Range({required this.min, required this.max}); - static Range? createIntRange({int? min, int? max}) { + static Range? optionalRangeOf({T? min, T? max}) { if (min == null || max == null) { return null; } return Range(min: min, max: max); } + + @override + List get props => [min, max]; } diff --git a/catalyst_voices/packages/internal/catalyst_voices_shared/pubspec.yaml b/catalyst_voices/packages/internal/catalyst_voices_shared/pubspec.yaml index 66de050feea..56bdf864fa9 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_shared/pubspec.yaml +++ b/catalyst_voices/packages/internal/catalyst_voices_shared/pubspec.yaml @@ -15,6 +15,7 @@ dependencies: collection: ^1.18.0 convert: ^3.1.1 cryptography: ^2.7.0 + equatable: ^2.0.7 flutter: sdk: flutter flutter_secure_storage: ^9.2.2 From 010650599a7e2f66eb15f5d5e262e40ea7a41c91 Mon Sep 17 00:00:00 2001 From: Dominik Toton Date: Mon, 23 Dec 2024 11:09:51 +0100 Subject: [PATCH 16/18] chore: update chain follower --- catalyst-gateway/bin/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/catalyst-gateway/bin/Cargo.toml b/catalyst-gateway/bin/Cargo.toml index 4099bfb7bf0..3a04c07f233 100644 --- a/catalyst-gateway/bin/Cargo.toml +++ b/catalyst-gateway/bin/Cargo.toml @@ -15,7 +15,7 @@ repository.workspace = true workspace = true [dependencies] -cardano-chain-follower = { version = "0.0.5", git = "https://github.com/input-output-hk/catalyst-libs.git", tag = "cardano-chain-follower-v0.0.5" } +cardano-chain-follower = { version = "0.0.6", git = "https://github.com/input-output-hk/catalyst-libs.git", tag = "v0.0.10" } c509-certificate = { version = "0.0.3", git = "https://github.com/input-output-hk/catalyst-libs.git", tag = "v0.0.3" } pallas = { version = "0.30.1", git = "https://github.com/input-output-hk/catalyst-pallas.git", rev = "9b5183c8b90b90fe2cc319d986e933e9518957b3" } From 4d70b4a35e60447d7b2c07cc48dad8db51b762c3 Mon Sep 17 00:00:00 2001 From: Ryszard Schossler Date: Mon, 23 Dec 2024 11:32:25 +0100 Subject: [PATCH 17/18] feat: sortingBy order --- .../document_builder/document_builder.dart | 8 +- .../document_definitions.dart | 4 +- .../lib/generated/api/client_index.dart | 1 + .../lib/src/dto/document_builder_dto.dart | 1 + .../lib/src/dto/document_schema_dto.dart | 59 +++----------- .../document_builder_test.dart | 58 +++++++------- .../document_definitions_test.dart | 75 +++++++++--------- .../document_schema_test.dart | 78 ++++++++++--------- .../lib/src/catalyst_voices_shared.dart | 4 +- .../extension/document_list_sort_ext.dart | 13 ++++ .../extension/document_map_to_list_ext.dart} | 2 +- .../lib/src/document/identifiable.dart | 3 + 12 files changed, 150 insertions(+), 156 deletions(-) create mode 100644 catalyst_voices/packages/internal/catalyst_voices_shared/lib/src/document/extension/document_list_sort_ext.dart rename catalyst_voices/packages/internal/catalyst_voices_shared/lib/src/{extension/map_to_list_ext.dart => document/extension/document_map_to_list_ext.dart} (92%) create mode 100644 catalyst_voices/packages/internal/catalyst_voices_shared/lib/src/document/identifiable.dart diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/document_builder/document_builder.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/document_builder/document_builder.dart index 2b4eb0cad06..54ec501db8f 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/document_builder/document_builder.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/document_builder/document_builder.dart @@ -10,10 +10,10 @@ class DocumentBuilder extends Equatable { required this.segments, }); - factory DocumentBuilder.build(DocumentSchema proposalSchema) { + factory DocumentBuilder.build(DocumentSchema schema) { return DocumentBuilder( - schema: proposalSchema.propertiesSchema, - segments: proposalSchema.segments + schema: schema.propertiesSchema, + segments: schema.segments .map( (element) => DocumentBuilderSegment( id: element.id, @@ -25,7 +25,7 @@ class DocumentBuilder extends Equatable { .map( (e) => DocumentBuilderElement( id: e.id, - value: e.ref.type.getDefaultValue, + value: e.ref.type.defaultValue, ), ) .toList(), diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/document_builder/document_definitions.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/document_builder/document_definitions.dart index f2c20cf8bdb..6ac7baa15ab 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/document_builder/document_definitions.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/document_builder/document_definitions.dart @@ -17,7 +17,7 @@ enum DocumentDefinitionsObjectType { DocumentDefinitionsObjectType.unknown; } - dynamic get getDefaultValue => switch (this) { + dynamic get defaultValue => switch (this) { string => '', integer => 0, boolean => true, @@ -82,6 +82,7 @@ sealed class BaseDocumentDefinition extends Equatable { required this.type, required this.note, }); + @visibleForTesting static final Map refPathToDefinitionType = { 'segment': SegmentDefinition, @@ -389,6 +390,7 @@ class NestedQuestionsListDefinition extends BaseDocumentDefinition { class NestedQuestionsDefinition extends BaseDocumentDefinition { final DocumentDefinitionsFormat format; final bool additionalProperties; + const NestedQuestionsDefinition({ required super.type, required super.note, diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/generated/api/client_index.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/generated/api/client_index.dart index ab84c6e02bb..098d50371d2 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/generated/api/client_index.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/generated/api/client_index.dart @@ -1 +1,2 @@ +export 'cat_gateway.swagger.dart' show CatGateway; export 'vit.swagger.dart' show Vit; diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/document_builder_dto.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/document_builder_dto.dart index 58c596390e8..0c3fe59f955 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/document_builder_dto.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/document_builder_dto.dart @@ -11,6 +11,7 @@ class DocumentBuilderDto extends Equatable { final String schema; @JsonKey(fromJson: _fromJsonSegments, toJson: _toJsonSegments) final List segments; + const DocumentBuilderDto({ required this.schema, required this.segments, diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/document_schema_dto.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/document_schema_dto.dart index 418dfeb012f..6ad7a9d6542 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/document_schema_dto.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/lib/src/dto/document_schema_dto.dart @@ -7,9 +7,10 @@ import 'package:json_annotation/json_annotation.dart'; part 'document_schema_dto.g.dart'; @JsonSerializable() -class DocumentSchemaDto extends Equatable { +class DocumentSchemaDto extends Equatable implements Identifiable { @JsonKey(name: r'$schema') final String schema; + @override @JsonKey(name: r'$id') final String id; final String title; @@ -28,8 +29,6 @@ class DocumentSchemaDto extends Equatable { @JsonKey(includeToJson: false) final String propertiesSchema; - static late Map orderMap; - const DocumentSchemaDto({ required this.schema, required this.id, @@ -42,7 +41,6 @@ class DocumentSchemaDto extends Equatable { required this.order, required this.propertiesSchema, }); - factory DocumentSchemaDto.fromJson(Map json) { final segmentsMap = json['properties'] as Map; json['propertiesSchema'] = @@ -54,9 +52,8 @@ class DocumentSchemaDto extends Equatable { Map toJson() => _$DocumentSchemaDtoToJson(this); DocumentSchema toModel() { - orderMap = {for (var i = 0; i < order.length; i++) order[i]: i}; final sortedProperties = List.from(this.segments) - ..sort(); + ..sortByOrder(order); final segments = sortedProperties .where((e) => e.ref.contains('segment')) .map((e) => e.toModel(definitions.definitionsModels)) @@ -102,10 +99,10 @@ class DocumentSchemaDto extends Equatable { } @JsonSerializable() -class DocumentSchemaSegmentDto extends Equatable - implements Comparable { +class DocumentSchemaSegmentDto extends Equatable implements Identifiable { @JsonKey(name: r'$ref') final String ref; + @override final String id; final String title; final String description; @@ -119,8 +116,6 @@ class DocumentSchemaSegmentDto extends Equatable @JsonKey(name: 'x-order') final List order; - static late Map orderMap; - const DocumentSchemaSegmentDto({ required this.ref, required this.id, @@ -137,9 +132,9 @@ class DocumentSchemaSegmentDto extends Equatable Map toJson() => _$DocumentSchemaSegmentDtoToJson(this); DocumentSchemaSegment toModel(List definitions) { - orderMap = {for (var i = 0; i < order.length; i++) order[i]: i}; final sortedProperties = List.from(this.sections) - ..sort(); + ..sortByOrder(order); + final sections = sortedProperties .where((element) => element.ref.contains('section')) .map((e) => e.toModel(definitions, isRequired: required.contains(e.id))) @@ -180,22 +175,13 @@ class DocumentSchemaSegmentDto extends Equatable final listOfSections = json.convertMapToListWithIds(); return listOfSections.map(DocumentSchemaSectionDto.fromJson).toList(); } - - @override - int compareTo(DocumentSchemaSegmentDto other) { - final thisIndex = - DocumentSchemaDto.orderMap[id] ?? double.maxFinite.toInt(); - final otherIndex = - DocumentSchemaDto.orderMap[other.id] ?? double.maxFinite.toInt(); - return thisIndex.compareTo(otherIndex); - } } @JsonSerializable() -class DocumentSchemaSectionDto extends Equatable - implements Comparable { +class DocumentSchemaSectionDto extends Equatable implements Identifiable { @JsonKey(name: r'$ref') final String ref; + @override final String id; final String title; final String description; @@ -214,8 +200,6 @@ class DocumentSchemaSectionDto extends Equatable @JsonKey(name: 'open_source') final Map openSource; // Return to this - static late Map orderMap; - const DocumentSchemaSectionDto({ required this.ref, required this.id, @@ -238,9 +222,8 @@ class DocumentSchemaSectionDto extends Equatable List definitions, { required bool isRequired, }) { - orderMap = {for (var i = 0; i < order.length; i++) order[i]: i}; final sortedElements = List.from(this.elements) - ..sort(); + ..sortByOrder(order); final elements = sortedElements .where((element) => BaseDocumentDefinition.isKnownType(element.ref)) .map((e) => e.toModel(definitions)) @@ -284,22 +267,13 @@ class DocumentSchemaSectionDto extends Equatable final listOfProperties = json.convertMapToListWithIds(); return listOfProperties.map(DocumentSchemaElementDto.fromJson).toList(); } - - @override - int compareTo(DocumentSchemaSectionDto other) { - final thisIndex = - DocumentSchemaSegmentDto.orderMap[id] ?? double.maxFinite.toInt(); - final otherIndex = - DocumentSchemaSegmentDto.orderMap[other.id] ?? double.maxFinite.toInt(); - return thisIndex.compareTo(otherIndex); - } } @JsonSerializable() -class DocumentSchemaElementDto extends Equatable - implements Comparable { +class DocumentSchemaElementDto extends Equatable implements Identifiable { @JsonKey(name: r'$ref') final String ref; + @override final String id; final String title; final String description; @@ -376,13 +350,4 @@ class DocumentSchemaElementDto extends Equatable minimum, maximum, ]; - - @override - int compareTo(DocumentSchemaElementDto other) { - final thisIndex = - DocumentSchemaSectionDto.orderMap[id] ?? double.maxFinite.toInt(); - final otherIndex = - DocumentSchemaSectionDto.orderMap[other.id] ?? double.maxFinite.toInt(); - return thisIndex.compareTo(otherIndex); - } } diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/document_builder/document_builder_test.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/document_builder/document_builder_test.dart index 3a73ea05d39..d07c5b43bad 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/document_builder/document_builder_test.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/document_builder/document_builder_test.dart @@ -8,42 +8,44 @@ import 'package:test/test.dart'; import '../../helpers/read_json.dart'; void main() { - const schemaPath = - 'test/assets/0ce8ab38-9258-4fbc-a62e-7faa6e58318f.schema.json'; + group('DocumentBuilder', () { + const schemaPath = + 'test/assets/0ce8ab38-9258-4fbc-a62e-7faa6e58318f.schema.json'; - late Map schemaJson; + late Map schemaJson; - setUpAll(() { - schemaJson = json.decode(readJson(schemaPath)) as Map; - }); + setUpAll(() { + schemaJson = json.decode(readJson(schemaPath)) as Map; + }); - test('Converts segments list into object for JSON', () { - final schemaDto = DocumentSchemaDto.fromJson(schemaJson); - final schema = schemaDto.toModel(); + test('Converts segments list into object for JSON', () { + final schemaDto = DocumentSchemaDto.fromJson(schemaJson); + final schema = schemaDto.toModel(); - final proposalBuilder = DocumentBuilder.build(schema); - final proposalBuilderDto = DocumentBuilderDto.fromModel(proposalBuilder); - final proposalBuilderJson = proposalBuilderDto.toJson(); + final proposalBuilder = DocumentBuilder.build(schema); + final proposalBuilderDto = DocumentBuilderDto.fromModel(proposalBuilder); + final proposalBuilderJson = proposalBuilderDto.toJson(); - for (final segment in proposalBuilderDto.segments) { - expect(proposalBuilderJson[segment.id], isA>()); - } - }); + for (final segment in proposalBuilderDto.segments) { + expect(proposalBuilderJson[segment.id], isA>()); + } + }); - test('Converts object from JSON into List of segments', () { - final schemaDto = DocumentSchemaDto.fromJson(schemaJson); - final schema = schemaDto.toModel(); + test('Converts object from JSON into List of segments', () { + final schemaDto = DocumentSchemaDto.fromJson(schemaJson); + final schema = schemaDto.toModel(); - final proposalBuilder = DocumentBuilder.build(schema); - final proposalBuilderDto = DocumentBuilderDto.fromModel(proposalBuilder); + final proposalBuilder = DocumentBuilder.build(schema); + final proposalBuilderDto = DocumentBuilderDto.fromModel(proposalBuilder); - final proposalBuilderJson = proposalBuilderDto.toJson(); - final proposalBuilderDtoFromJson = - DocumentBuilderDto.fromJson(proposalBuilderJson); + final proposalBuilderJson = proposalBuilderDto.toJson(); + final proposalBuilderDtoFromJson = + DocumentBuilderDto.fromJson(proposalBuilderJson); - expect( - proposalBuilderDtoFromJson.segments.length, - proposalBuilderDto.segments.length, - ); + expect( + proposalBuilderDtoFromJson.segments.length, + proposalBuilderDto.segments.length, + ); + }); }); } diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/document_builder/document_definitions_test.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/document_builder/document_definitions_test.dart index b2123c320f9..02f357faad5 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/document_builder/document_definitions_test.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/document_builder/document_definitions_test.dart @@ -7,45 +7,48 @@ import 'package:test/test.dart'; import '../../helpers/read_json.dart'; void main() { - const schemaPath = - 'test/assets/0ce8ab38-9258-4fbc-a62e-7faa6e58318f.schema.json'; - - late Map schemaJson; + group('DocumentDefinitions', () { + const schemaPath = + 'test/assets/0ce8ab38-9258-4fbc-a62e-7faa6e58318f.schema.json'; + + late Map schemaJson; + + setUpAll(() { + schemaJson = json.decode(readJson(schemaPath)) as Map; + }); + test( + // ignore: lines_longer_than_80_chars + 'Check if all definition are in definition list inside DefinitionDto model', + () async { + final schemaDto = DocumentSchemaDto.fromJson(schemaJson); + final definitions = schemaDto.definitions.definitionsModels; + + for (final value + in BaseDocumentDefinition.refPathToDefinitionType.values) { + final occurrences = definitions + .where((element) => element.runtimeType == value) + .length; + expect( + occurrences, + equals(1), + reason: 'Value $value appears $occurrences times in the list', + ); + } + }, + ); - setUpAll(() { - schemaJson = json.decode(readJson(schemaPath)) as Map; - }); - test( - // ignore: lines_longer_than_80_chars - 'Check if all definition are in definition list inside DefinitionDto model', - () async { + test('Check if document definition media type is parse correctly', () { final schemaDto = DocumentSchemaDto.fromJson(schemaJson); final definitions = schemaDto.definitions.definitionsModels; - for (final value - in BaseDocumentDefinition.refPathToDefinitionType.values) { - final occurrences = - definitions.where((element) => element.runtimeType == value).length; - expect( - occurrences, - equals(1), - reason: 'Value $value appears $occurrences times in the list', - ); - } - }, - ); - - test('Check if document definition media type is parse correctly', () { - final schemaDto = DocumentSchemaDto.fromJson(schemaJson); - final definitions = schemaDto.definitions.definitionsModels; - - final singleLineTextEntry = - definitions.getDefinition('#/definitions/singleLineTextEntry') - as SingleLineTextEntryDefinition; - - expect( - singleLineTextEntry.contentMediaType, - DocumentDefinitionsContentMediaType.textPlain, - ); + final singleLineTextEntry = + definitions.getDefinition('#/definitions/singleLineTextEntry') + as SingleLineTextEntryDefinition; + + expect( + singleLineTextEntry.contentMediaType, + DocumentDefinitionsContentMediaType.textPlain, + ); + }); }); } diff --git a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/document_builder/document_schema_test.dart b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/document_builder/document_schema_test.dart index de5e7fb3a90..a5c7969d46a 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/document_builder/document_schema_test.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_repositories/test/src/document_builder/document_schema_test.dart @@ -7,52 +7,54 @@ import 'package:test/test.dart'; import '../../helpers/read_json.dart'; void main() { - const schemaPath = - 'test/assets/0ce8ab38-9258-4fbc-a62e-7faa6e58318f.schema.json'; + group('DocumentSchema', () { + const schemaPath = + 'test/assets/0ce8ab38-9258-4fbc-a62e-7faa6e58318f.schema.json'; - late Map schemaJson; + late Map schemaJson; - setUpAll(() { - schemaJson = json.decode(readJson(schemaPath)) as Map; - }); - - test('X-order of segments is kept in model class', () async { - final schemaDto = DocumentSchemaDto.fromJson(schemaJson); + setUpAll(() { + schemaJson = json.decode(readJson(schemaPath)) as Map; + }); - final schema = schemaDto.toModel(); - - if (schemaDto.order.length != schema.segments.length) { - return; - } - for (var i = 0; i < schema.segments.length; i++) { - expect(schema.segments[i].id, schemaDto.order[i]); - } - }); + test('X-order of segments is kept in model class', () async { + final schemaDto = DocumentSchemaDto.fromJson(schemaJson); - test('X-order of section is kept in model class', () { - final schemaDto = DocumentSchemaDto.fromJson(schemaJson); - final schema = schemaDto.toModel(); + final schema = schemaDto.toModel(); - for (var i = 0; i < schema.segments.length; i++) { - if (schemaDto.segments[i].order.length != - schema.segments[i].sections.length) { - continue; + if (schemaDto.order.length != schema.segments.length) { + return; } - for (var j = 0; j < schema.segments[i].sections.length; j++) { - expect( - schema.segments[i].sections[j].id, - schemaDto.segments[i].order[j], - ); + for (var i = 0; i < schema.segments.length; i++) { + expect(schema.segments[i].id, schemaDto.order[i]); } - } - }); + }); + + test('X-order of section is kept in model class', () { + final schemaDto = DocumentSchemaDto.fromJson(schemaJson); + final schema = schemaDto.toModel(); + + for (var i = 0; i < schema.segments.length; i++) { + if (schemaDto.segments[i].order.length != + schema.segments[i].sections.length) { + continue; + } + for (var j = 0; j < schema.segments[i].sections.length; j++) { + expect( + schema.segments[i].sections[j].id, + schemaDto.segments[i].order[j], + ); + } + } + }); - test('Check if every segment has a SegmentDefinition as ref', () { - final schemaDto = DocumentSchemaDto.fromJson(schemaJson); - final schema = schemaDto.toModel(); + test('Check if every segment has a SegmentDefinition as ref', () { + final schemaDto = DocumentSchemaDto.fromJson(schemaJson); + final schema = schemaDto.toModel(); - for (final segment in schema.segments) { - expect(segment.ref, isA()); - } + for (final segment in schema.segments) { + expect(segment.ref, isA()); + } + }); }); } diff --git a/catalyst_voices/packages/internal/catalyst_voices_shared/lib/src/catalyst_voices_shared.dart b/catalyst_voices/packages/internal/catalyst_voices_shared/lib/src/catalyst_voices_shared.dart index 03659712b47..884defba558 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_shared/lib/src/catalyst_voices_shared.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_shared/lib/src/catalyst_voices_shared.dart @@ -7,7 +7,9 @@ export 'crypto/crypto_service.dart'; export 'crypto/key_derivation.dart'; export 'crypto/local_crypto_service.dart'; export 'dependency/dependency_provider.dart'; -export 'extension/map_to_list_ext.dart'; +export 'document/extension/document_list_sort_ext.dart'; +export 'document/extension/document_map_to_list_ext.dart'; +export 'document/identifiable.dart'; export 'formatter/cryptocurrency_formatter.dart'; export 'formatter/wallet_address_formatter.dart'; export 'keychain/keychain.dart'; diff --git a/catalyst_voices/packages/internal/catalyst_voices_shared/lib/src/document/extension/document_list_sort_ext.dart b/catalyst_voices/packages/internal/catalyst_voices_shared/lib/src/document/extension/document_list_sort_ext.dart new file mode 100644 index 00000000000..7ff95db6d34 --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_shared/lib/src/document/extension/document_list_sort_ext.dart @@ -0,0 +1,13 @@ +import 'package:catalyst_voices_shared/catalyst_voices_shared.dart'; + +extension DocumentListSortExt on List { + void sortByOrder(List order) { + final orderMap = {for (var i = 0; i < order.length; i++) order[i]: i}; + + sort((a, b) { + final aIndex = orderMap[a.id] ?? double.maxFinite.toInt(); + final bIndex = orderMap[b.id] ?? double.maxFinite.toInt(); + return aIndex.compareTo(bIndex); + }); + } +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_shared/lib/src/extension/map_to_list_ext.dart b/catalyst_voices/packages/internal/catalyst_voices_shared/lib/src/document/extension/document_map_to_list_ext.dart similarity index 92% rename from catalyst_voices/packages/internal/catalyst_voices_shared/lib/src/extension/map_to_list_ext.dart rename to catalyst_voices/packages/internal/catalyst_voices_shared/lib/src/document/extension/document_map_to_list_ext.dart index a0e3f8e76f2..cab157eed80 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_shared/lib/src/extension/map_to_list_ext.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_shared/lib/src/document/extension/document_map_to_list_ext.dart @@ -1,4 +1,4 @@ -extension MapToListExt on Map { +extension DocumentMapToListExt on Map { List> convertMapToListWithIds() { final list = >[]; diff --git a/catalyst_voices/packages/internal/catalyst_voices_shared/lib/src/document/identifiable.dart b/catalyst_voices/packages/internal/catalyst_voices_shared/lib/src/document/identifiable.dart new file mode 100644 index 00000000000..5d0eb779875 --- /dev/null +++ b/catalyst_voices/packages/internal/catalyst_voices_shared/lib/src/document/identifiable.dart @@ -0,0 +1,3 @@ +abstract class Identifiable { + String get id; +} From b0783c5cabf576ad90cc675db95e094f69ebc006 Mon Sep 17 00:00:00 2001 From: Dominik Toton Date: Mon, 23 Dec 2024 15:15:06 +0100 Subject: [PATCH 18/18] chore: revert merge conflicts --- catalyst-gateway/bin/Cargo.toml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/catalyst-gateway/bin/Cargo.toml b/catalyst-gateway/bin/Cargo.toml index 3a04c07f233..75c578f6d92 100644 --- a/catalyst-gateway/bin/Cargo.toml +++ b/catalyst-gateway/bin/Cargo.toml @@ -17,6 +17,7 @@ workspace = true [dependencies] cardano-chain-follower = { version = "0.0.6", git = "https://github.com/input-output-hk/catalyst-libs.git", tag = "v0.0.10" } c509-certificate = { version = "0.0.3", git = "https://github.com/input-output-hk/catalyst-libs.git", tag = "v0.0.3" } +rbac-registration = { version = "0.0.2", git = "https://github.com/input-output-hk/catalyst-libs.git", tag = "v0.0.8" } pallas = { version = "0.30.1", git = "https://github.com/input-output-hk/catalyst-pallas.git", rev = "9b5183c8b90b90fe2cc319d986e933e9518957b3" } pallas-traverse = { version = "0.30.1", git = "https://github.com/input-output-hk/catalyst-pallas.git", rev = "9b5183c8b90b90fe2cc319d986e933e9518957b3" } @@ -42,6 +43,7 @@ tokio-postgres = { version = "0.7.12", features = [ "with-chrono-0_4", "with-serde_json-1", "with-time-0_3", + "with-uuid-1" ] } tokio = { version = "1.41.0", features = ["rt", "macros", "rt-multi-thread"] } dotenvy = "0.15.7" @@ -76,7 +78,7 @@ poem-openapi = { version = "5.1.2", features = [ "url", "chrono", ] } -uuid = { version = "1.11.0", features = ["v4", "serde"] } +uuid = { version = "1.11.0", features = ["v4", "v7", "serde"] } ulid = { version = "1.1.3", features = ["serde", "uuid"] } blake2b_simd = "1.0.2" url = "2.5.3"