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:
Individual Entity (Incorporated) 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:
Individual Entity (Incorporated) Entity (Not Incorporated) ",
+ "x-guidance": "Please select from one of the following:
Individual Entity (Incorporated) 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