Spaces:
Running
Running
| using System; | |
| using System.Collections.Generic; | |
| using FlowAPI.Application.DTOs.Graph; | |
| using FlowAPI.Domain.Entities; | |
| using FlowAPI.Domain.Enums; | |
| namespace FlowAPI.Application.Services | |
| { | |
| public static class TemplateLibrary | |
| { | |
| private class TemplateNodeDef | |
| { | |
| public string TempId { get; set; } = string.Empty; | |
| public string Label { get; set; } = string.Empty; | |
| public double PosX { get; set; } | |
| public double PosY { get; set; } | |
| public string Type { get; set; } = "sketch"; | |
| public string Color { get; set; } = "white"; | |
| public string Description { get; set; } = string.Empty; | |
| public string DecisionJson { get; set; } = string.Empty; | |
| public double? Width { get; set; } | |
| public double? Height { get; set; } | |
| } | |
| private class TemplateEdgeDef | |
| { | |
| public string FromTempId { get; set; } = string.Empty; | |
| public string ToTempId { get; set; } = string.Empty; | |
| public string Condition { get; set; } = "True"; | |
| } | |
| private class TemplateDef | |
| { | |
| public string Key { get; set; } = string.Empty; | |
| public string Title { get; set; } = string.Empty; | |
| public string Description { get; set; } = string.Empty; | |
| public string Icon { get; set; } = string.Empty; | |
| public string Category { get; set; } = string.Empty; | |
| public List<TemplateNodeDef> Nodes { get; set; } = new(); | |
| public List<TemplateEdgeDef> Edges { get; set; } = new(); | |
| } | |
| private static readonly Dictionary<string, TemplateDef> Templates = new() | |
| { | |
| { | |
| "startup", | |
| new TemplateDef | |
| { | |
| Key = "startup", | |
| Title = "Запуск Стартапу", | |
| Description = "Шлях від формулювання ціннісної пропозиції та CustDev до запуску MVP та перших 100 користувачів.", | |
| Icon = "Rocket", | |
| Category = "Business", | |
| Nodes = new List<TemplateNodeDef> | |
| { | |
| new() { TempId = "vprop", Label = "Формулювання ціннісної пропозиції", PosX = 250, PosY = 50, Color = "purple", Description = "Чітко опишіть, яку проблему вирішує ваш продукт і для кого." }, | |
| new() { TempId = "custdev", Label = "CustDev: Інтерв'ю з клієнтами", PosX = 250, PosY = 170, Color = "blue", Description = "Проведіть принаймні 10 інтерв'ю з потенційними користувачами." }, | |
| new() { TempId = "fit", Label = "Чи підтверджено проблему?", PosX = 250, PosY = 290, Type = "condition", DecisionJson = "{\"options\":[{\"id\":\"opt-yes\",\"label\":\"Так (Є інтерес)\"},{\"id\":\"opt-no\",\"label\":\"Ні (Потрібен півот)\"}],\"selected\":[],\"multiSelect\":false}" }, | |
| new() { TempId = "mvp", Label = "Розробка MVP", PosX = 100, PosY = 420, Color = "green", Description = "Створіть мінімально життєздатний продукт з однією ключовою функцією." }, | |
| new() { TempId = "pivot", Label = "Півот ідеї", PosX = 400, PosY = 420, Color = "orange", Description = "Змініть напрямок або цільову аудиторію на основі фідбеку з інтерв'ю." }, | |
| new() { TempId = "landing", Label = "Лендинг та збір заявок", PosX = 100, PosY = 550, Color = "pink", Description = "Налаштуйте просту сторінку для збору контактів зацікавлених клієнтів." }, | |
| new() { TempId = "users", Label = "Залучення перших 100 користувачів", PosX = 100, PosY = 680, Color = "yellow", Description = "Використовуйте безкоштовні канали (соцмережі, профільні форуми, зв'язки)." } | |
| }, | |
| Edges = new List<TemplateEdgeDef> | |
| { | |
| new() { FromTempId = "vprop", ToTempId = "custdev" }, | |
| new() { FromTempId = "custdev", ToTempId = "fit" }, | |
| new() { FromTempId = "fit", ToTempId = "mvp", Condition = "True" }, | |
| new() { FromTempId = "fit", ToTempId = "pivot", Condition = "False" }, | |
| new() { FromTempId = "pivot", ToTempId = "vprop" }, | |
| new() { FromTempId = "mvp", ToTempId = "landing" }, | |
| new() { FromTempId = "landing", ToTempId = "users" } | |
| } | |
| } | |
| }, | |
| { | |
| "software", | |
| new TemplateDef | |
| { | |
| Key = "software", | |
| Title = "Розробка ПЗ (Web App)", | |
| Description = "Стандартний життєвий цикл розробки веб-додатку: вимоги, дизайн, UI/UX, API, інтеграція та реліз.", | |
| Icon = "Code", | |
| Category = "Development", | |
| Nodes = new List<TemplateNodeDef> | |
| { | |
| new() { TempId = "req", Label = "Збір та аналіз вимог", PosX = 250, PosY = 50, Color = "blue", Description = "Опишіть функціонал проекту та підготуйте ТЗ." }, | |
| new() { TempId = "arch", Label = "Архітектура та проектування БД", PosX = 250, PosY = 170, Color = "purple", Description = "Спроектуйте схему бази даних та виберіть стек технологій." }, | |
| new() { TempId = "uiux", Label = "UI/UX макети та дизайн", PosX = 100, PosY = 300, Color = "pink", Description = "Створіть клікабельний прототип у Figma." }, | |
| new() { TempId = "api", Label = "Розробка API та Бекенду", PosX = 400, PosY = 300, Color = "yellow", Description = "Реалізуйте серверу логіку, авторизацію та базу даних." }, | |
| new() { TempId = "integ", Label = "Інтеграція та тестування", PosX = 250, PosY = 440, Color = "green", Description = "З'єднайте фронтенд з бекендом та проведіть ручне тестування." }, | |
| new() { TempId = "staging", Label = "Деплой на Staging сервер", PosX = 250, PosY = 560, Color = "orange", Description = "Розгорніть тестову версію додатку для фінальної перевірки." }, | |
| new() { TempId = "prod", Label = "Реліз у Production та моніторинг", PosX = 250, PosY = 680, Color = "green", Description = "Запустіть додаток для реальних користувачів та підключіть аналітику." } | |
| }, | |
| Edges = new List<TemplateEdgeDef> | |
| { | |
| new() { FromTempId = "req", ToTempId = "arch" }, | |
| new() { FromTempId = "arch", ToTempId = "uiux" }, | |
| new() { FromTempId = "arch", ToTempId = "api" }, | |
| new() { FromTempId = "uiux", ToTempId = "integ" }, | |
| new() { FromTempId = "api", ToTempId = "integ" }, | |
| new() { FromTempId = "integ", ToTempId = "staging" }, | |
| new() { FromTempId = "staging", ToTempId = "prod" } | |
| } | |
| } | |
| }, | |
| { | |
| "language", | |
| new TemplateDef | |
| { | |
| Key = "language", | |
| Title = "Вивчення Іноземної Мови", | |
| Description = "Методика освоєння мови через щоденні звички, проходження базового курсу та вихід у практику.", | |
| Icon = "Languages", | |
| Category = "Education", | |
| Nodes = new List<TemplateNodeDef> | |
| { | |
| new() { TempId = "goal", Label = "Визначення цілей та ресурсів", PosX = 250, PosY = 50, Color = "purple", Description = "Оберіть додатки, підручники та поставте чітку ціль (наприклад, рівень B1)." }, | |
| new() { TempId = "words", Label = "Вчити 15 нових слів щодня", PosX = 100, PosY = 170, Type = "habit", Color = "blue", Description = "Використовуйте картки Anki або Quizlet для регулярного повторення.", DecisionJson = "{\"resetRule\":{\"type\":\"daily\",\"time\":\"00:00\"},\"createdAt\":\"" + DateTime.UtcNow.ToString("o") + "\",\"description\":\"Використовуйте картки Anki або Quizlet для регулярного повторення.\",\"tags\":[],\"status\":\"Todo\",\"progress\":0}" }, | |
| new() { TempId = "listen", Label = "Слухати подкаст / дивитись відео", PosX = 400, PosY = 170, Type = "habit", Color = "pink", Description = "Принаймні 20 хвилин фонового або активного слухання щодня.", DecisionJson = "{\"resetRule\":{\"type\":\"daily\",\"time\":\"00:00\"},\"createdAt\":\"" + DateTime.UtcNow.ToString("o") + "\",\"description\":\"Принаймні 20 хвилин фонового або активного слухання щодня.\",\"tags\":[],\"status\":\"Todo\",\"progress\":0}" }, | |
| new() { TempId = "course", Label = "Завершити курс для початківців", PosX = 250, PosY = 300, Color = "yellow", Description = "Пройти базову граматику та отримати розуміння структури мови." }, | |
| new() { TempId = "speak", Label = "Розмовна сесія (1 раз на тиждень)", PosX = 100, PosY = 430, Type = "habit", Color = "green", Description = "Знайдіть партнера для спілкування на Tandem або викладача.", DecisionJson = "{\"resetRule\":{\"type\":\"weekly\",\"time\":\"00:00\"},\"createdAt\":\"" + DateTime.UtcNow.ToString("o") + "\",\"description\":\"Знайдіть партнера для спілкування на Tandem або викладача.\",\"tags\":[],\"status\":\"Todo\",\"progress\":0}" }, | |
| new() { TempId = "read", Label = "Прочитати першу коротку розповідь", PosX = 400, PosY = 430, Color = "orange", Description = "Оберіть адаптовану книгу під ваш поточний рівень." }, | |
| new() { TempId = "exam", Label = "Скласти тестовий іспит", PosX = 250, PosY = 560, Color = "green", Description = "Перевірте свій прогрес за допомогою офіційного пробного тесту." } | |
| }, | |
| Edges = new List<TemplateEdgeDef> | |
| { | |
| new() { FromTempId = "goal", ToTempId = "words" }, | |
| new() { FromTempId = "goal", ToTempId = "listen" }, | |
| new() { FromTempId = "words", ToTempId = "course" }, | |
| new() { FromTempId = "listen", ToTempId = "course" }, | |
| new() { FromTempId = "course", ToTempId = "speak" }, | |
| new() { FromTempId = "course", ToTempId = "read" }, | |
| new() { FromTempId = "speak", ToTempId = "exam" }, | |
| new() { FromTempId = "read", ToTempId = "exam" } | |
| } | |
| } | |
| }, | |
| { | |
| "fitness", | |
| new TemplateDef | |
| { | |
| Key = "fitness", | |
| Title = "Фітнес та Здорове Тіло", | |
| Description = "Збалансований план тренувань, контролю харчування та циклічного аналізу результатів.", | |
| Icon = "Activity", | |
| Category = "Health", | |
| Nodes = new List<TemplateNodeDef> | |
| { | |
| new() { TempId = "setup", Label = "Поставити ціль та розрахувати КБЖВ", PosX = 250, PosY = 50, Color = "blue", Description = "Визначте добову норму калорій залежно від мети (схуднення чи набір маси)." }, | |
| new() { TempId = "plan", Label = "Скласти план тренувань та раціон", PosX = 250, PosY = 170, Color = "purple", Description = "Виберіть 3 дні для занять та підготуйте перелік здорових страв." }, | |
| new() { TempId = "diet", Label = "Трекати щоденне харчування та воду", PosX = 100, PosY = 300, Type = "habit", Color = "green", Description = "Записуйте все з'їдене в MyFitnessPal та пийте достатньо води.", DecisionJson = "{\"resetRule\":{\"type\":\"daily\",\"time\":\"00:00\"},\"createdAt\":\"" + DateTime.UtcNow.ToString("o") + "\",\"description\":\"Записуйте все з'їдене в MyFitnessPal та пийте достатньо води.\",\"tags\":[],\"status\":\"Todo\",\"progress\":0}" }, | |
| new() { TempId = "workout", Label = "Силове або кардіо тренування", PosX = 400, PosY = 300, Type = "habit", Color = "orange", Description = "Виконуйте заплановане тренування 3 рази на тиждень.", DecisionJson = "{\"resetRule\":{\"type\":\"weekly\",\"time\":\"00:00\"},\"createdAt\":\"" + DateTime.UtcNow.ToString("o") + "\",\"description\":\"Виконуйте заплановане тренування 3 рази на тиждень.\",\"tags\":[],\"status\":\"Todo\",\"progress\":0}" }, | |
| new() { TempId = "check", Label = "Контрольне зважування та заміри (4 тижні)", PosX = 250, PosY = 430, Color = "yellow", Description = "Порівняйте поточну вагу та об'єми тіла з початковими показниками." }, | |
| new() { TempId = "satisfied", Label = "Чи є прогрес задовільним?", PosX = 250, PosY = 550, Type = "condition", DecisionJson = "{\"options\":[{\"id\":\"opt-yes\",\"label\":\"Так (Продовжуємо)\"},{\"id\":\"opt-no\",\"label\":\"Ні (Потрібні коригування)\"}],\"selected\":[],\"multiSelect\":false}" }, | |
| new() { TempId = "advance", Label = "Ускладнити програму тренувань", PosX = 100, PosY = 680, Color = "pink", Description = "Додайте вагу на снарядах або збільшіть інтенсивність." }, | |
| new() { TempId = "adjust", Label = "Скоригувати КБЖВ та план їжі", PosX = 400, PosY = 680, Color = "yellow", Description = "Зменшіть або збільшіть калорійність раціону на 10%." } | |
| }, | |
| Edges = new List<TemplateEdgeDef> | |
| { | |
| new() { FromTempId = "setup", ToTempId = "plan" }, | |
| new() { FromTempId = "plan", ToTempId = "diet" }, | |
| new() { FromTempId = "plan", ToTempId = "workout" }, | |
| new() { FromTempId = "diet", ToTempId = "check" }, | |
| new() { FromTempId = "workout", ToTempId = "check" }, | |
| new() { FromTempId = "check", ToTempId = "satisfied" }, | |
| new() { FromTempId = "satisfied", ToTempId = "advance", Condition = "True" }, | |
| new() { FromTempId = "satisfied", ToTempId = "adjust", Condition = "False" }, | |
| new() { FromTempId = "adjust", ToTempId = "plan" } | |
| } | |
| } | |
| }, | |
| { | |
| "gamedev", | |
| new TemplateDef | |
| { | |
| Key = "gamedev", | |
| Title = "Створення Інді-Гри", | |
| Description = "Повний цикл геймдеву від ідеї та прототипу до створення сторінки в Steam та релізу.", | |
| Icon = "Gamepad", | |
| Category = "Creative", | |
| Nodes = new List<TemplateNodeDef> | |
| { | |
| new() { TempId = "concept", Label = "Концепт та написання GDD", PosX = 250, PosY = 50, Color = "pink", Description = "Сформулюйте основну ідею гри та опишіть її механіки в дизайн-документі." }, | |
| new() { TempId = "proto", Label = "Прототип базового геймплею", PosX = 250, PosY = 170, Color = "purple", Description = "Створіть «сіру коробку» на рушії, щоб перевірити, чи весело грати." }, | |
| new() { TempId = "art", Label = "Стилістика та створення артів", PosX = 100, PosY = 300, Color = "orange", Description = "Визначте художній стиль та підготуйте перші 2D/3D моделі." }, | |
| new() { TempId = "level", Label = "Дизайн рівнів та звуковий супровід", PosX = 400, PosY = 300, Color = "blue", Description = "Створіть тестовий рівень та додайте базові звукові ефекти." }, | |
| new() { TempId = "playable", Label = "Перша грабельна демо-версія", PosX = 250, PosY = 430, Color = "yellow", Description = "Зберіть стабільний білд для тестування друзями." }, | |
| new() { TempId = "test", Label = "Плейтести та виправлення багів", PosX = 100, PosY = 560, Type = "habit", Color = "pink", Description = "Щодня грайте, збирайте фідбек та виправляйте помилки.", DecisionJson = "{\"resetRule\":{\"type\":\"daily\",\"time\":\"00:00\"},\"createdAt\":\"" + DateTime.UtcNow.ToString("o") + "\",\"description\":\"Щодня грайте, збирайте фідбек та виправляйте помилки.\",\"tags\":[],\"status\":\"Todo\",\"progress\":0}" }, | |
| new() { TempId = "steam", Label = "Створення сторінки в Steam", PosX = 400, PosY = 560, Color = "yellow", Description = "Підготуйте красиві скріншоти, трейлер та запустіть сторінку для збору Wishlists." }, | |
| new() { TempId = "release", Label = "Реліз гри в Steam", PosX = 250, PosY = 690, Color = "green", Description = "Опублікуйте фінальний білд та підтримайте запуск маркетинговою кампанією." } | |
| }, | |
| Edges = new List<TemplateEdgeDef> | |
| { | |
| new() { FromTempId = "concept", ToTempId = "proto" }, | |
| new() { FromTempId = "proto", ToTempId = "art" }, | |
| new() { FromTempId = "proto", ToTempId = "level" }, | |
| new() { FromTempId = "art", ToTempId = "playable" }, | |
| new() { FromTempId = "level", ToTempId = "playable" }, | |
| new() { FromTempId = "playable", ToTempId = "test" }, | |
| new() { FromTempId = "playable", ToTempId = "steam" }, | |
| new() { FromTempId = "test", ToTempId = "release" }, | |
| new() { FromTempId = "steam", ToTempId = "release" } | |
| } | |
| } | |
| }, | |
| { | |
| "finance", | |
| new TemplateDef | |
| { | |
| Key = "finance", | |
| Title = "Фінансова Свобода", | |
| Description = "Покроковий план досягнення фінансової незалежності: облік витрат, подушка безпеки та інвестиції.", | |
| Icon = "DollarSign", | |
| Category = "Finance", | |
| Nodes = new List<TemplateNodeDef> | |
| { | |
| new() { TempId = "audit", Label = "Аудит активів та боргових зобов'язань", PosX = 250, PosY = 50, Color = "yellow", Description = "Запишіть усі свої збереження, майно та кредити." }, | |
| new() { TempId = "track", Label = "Щоденний облік усіх витрат", PosX = 100, PosY = 170, Type = "habit", Color = "blue", Description = "Записуйте кожну покупку в мобільний додаток або Excel таблицю.", DecisionJson = "{\"resetRule\":{\"type\":\"daily\",\"time\":\"00:00\"},\"createdAt\":\"" + DateTime.UtcNow.ToString("o") + "\",\"description\":\"Записуйте кожну покупку в мобільний додаток або Excel таблицю.\",\"tags\":[],\"status\":\"Todo\",\"progress\":0}" }, | |
| new() { TempId = "emergency", Label = "Сформувати подушку на 3 місяці", PosX = 300, PosY = 170, Color = "orange", Description = "Розрахуйте мінімальний бюджет життя та накопичте цю суму на депозиті." }, | |
| new() { TempId = "debt", Label = "Виплатити всі споживчі кредити", PosX = 250, PosY = 290, Color = "pink", Description = "Спрямуйте вільні кошти на швидке закриття боргів з найвищими відсотками." }, | |
| new() { TempId = "invest", Label = "Інвестувати 20% від доходу", PosX = 100, PosY = 420, Type = "habit", Color = "green", Description = "Регулярно купуйте надійні індекси (ETF) або облігації.", DecisionJson = "{\"resetRule\":{\"type\":\"monthly\",\"time\":\"00:00\"},\"createdAt\":\"" + DateTime.UtcNow.ToString("o") + "\",\"description\":\"Регулярно купуйте надійні індекси (ETF) або облігації.\",\"tags\":[],\"status\":\"Todo\",\"progress\":0}" }, | |
| new() { TempId = "passive", Label = "Створити джерело пасивного доходу", PosX = 400, PosY = 420, Color = "purple", Description = "Створіть власний блог, курс, невеликий онлайн-сервіс чи придбайте дивідендні акції." }, | |
| new() { TempId = "freedom", Label = "Досягти фінансової незалежності", PosX = 250, PosY = 550, Color = "green", Description = "Коли пасивний дохід повністю перекриє ваші щомісячні витрати." } | |
| }, | |
| Edges = new List<TemplateEdgeDef> | |
| { | |
| new() { FromTempId = "audit", ToTempId = "track" }, | |
| new() { FromTempId = "audit", ToTempId = "emergency" }, | |
| new() { FromTempId = "track", ToTempId = "debt" }, | |
| new() { FromTempId = "emergency", ToTempId = "debt" }, | |
| new() { FromTempId = "debt", ToTempId = "invest" }, | |
| new() { FromTempId = "debt", ToTempId = "passive" }, | |
| new() { FromTempId = "invest", ToTempId = "freedom" }, | |
| new() { FromTempId = "passive", ToTempId = "freedom" } | |
| } | |
| } | |
| }, | |
| { | |
| "writing", | |
| new TemplateDef | |
| { | |
| Key = "writing", | |
| Title = "Написання та Публікація Книги", | |
| Description = "Шлях автора: від розробки сюжету та персонажів до щоденного написання, редактури та релізу.", | |
| Icon = "BookOpen", | |
| Category = "Creative", | |
| Nodes = new List<TemplateNodeDef> | |
| { | |
| new() { TempId = "outline", Label = "Побудова сюжету та анкет персонажів", PosX = 250, PosY = 50, Color = "pink", Description = "Напишіть синопсис та детально розпишіть структуру розділів книги." }, | |
| new() { TempId = "words", Label = "Писати по 1000 слів щодня", PosX = 100, PosY = 170, Type = "habit", Color = "purple", Description = "Формуйте звичку писати без критики та внутрішнього редактора.", DecisionJson = "{\"resetRule\":{\"type\":\"daily\",\"time\":\"00:00\"},\"createdAt\":\"" + DateTime.UtcNow.ToString("o") + "\",\"description\":\"Формуйте звичку писати без критики та внутрішнього редактора.\",\"tags\":[],\"status\":\"Todo\",\"progress\":0}" }, | |
| new() { TempId = "draft", Label = "Завершити першу чернетку", PosX = 350, PosY = 170, Color = "yellow", Description = "Напишіть повну історію від початку до кінця (орієнтовно 50-80 тис. слів)." }, | |
| new() { TempId = "edit", Label = "Самостійна редактура та вичитка", PosX = 250, PosY = 300, Color = "orange", Description = "Виправте логічні помилки, покращіть діалоги та стиль оповідання." }, | |
| new() { TempId = "beta", Label = "Отримати фідбек від бета-рідерів", PosX = 250, PosY = 420, Color = "blue", Description = "Дайте почитати книгу кільком людям із вашої цільової аудиторії." }, | |
| new() { TempId = "professional", Label = "Професійна коректура та верстка", PosX = 250, PosY = 540, Color = "pink", Description = "Знайдіть професійного редактора для виправлення граматики та підготовки макету." }, | |
| new() { TempId = "cover", Label = "Створення обкладинки та форматування", PosX = 100, PosY = 660, Color = "purple", Description = "Замовте обкладинку в дизайнера та підготуйте формати ePub, PDF." }, | |
| new() { TempId = "publish", Label = "Публікація та запуск маркетингу", PosX = 350, PosY = 660, Color = "green", Description = "Опублікуйте книгу на Amazon / Litres та запустіть промо-акції." } | |
| }, | |
| Edges = new List<TemplateEdgeDef> | |
| { | |
| new() { FromTempId = "outline", ToTempId = "words" }, | |
| new() { FromTempId = "words", ToTempId = "draft" }, | |
| new() { FromTempId = "draft", ToTempId = "edit" }, | |
| new() { FromTempId = "edit", ToTempId = "beta" }, | |
| new() { FromTempId = "beta", ToTempId = "professional" }, | |
| new() { FromTempId = "professional", ToTempId = "cover" }, | |
| new() { FromTempId = "professional", ToTempId = "publish" } | |
| } | |
| } | |
| } | |
| }; | |
| public static IEnumerable<TemplateInfoDto> GetTemplateInfos() | |
| { | |
| var list = new List<TemplateInfoDto>(); | |
| foreach (var kv in Templates) | |
| { | |
| list.Add(new TemplateInfoDto | |
| { | |
| Key = kv.Value.Key, | |
| Title = kv.Value.Title, | |
| Description = kv.Value.Description, | |
| Icon = kv.Value.Icon, | |
| Category = kv.Value.Category | |
| }); | |
| } | |
| return list; | |
| } | |
| public static (List<TaskNode> Nodes, List<Edge> Edges) GetTemplateContent(string key, Guid graphId) | |
| { | |
| if (!Templates.TryGetValue(key.ToLower().Trim(), out var template)) | |
| { | |
| return (new List<TaskNode>(), new List<Edge>()); | |
| } | |
| var nodes = new List<TaskNode>(); | |
| var edges = new List<Edge>(); | |
| var idMapping = new Dictionary<string, Guid>(); | |
| // 1. Instantiate nodes and map their IDs | |
| foreach (var nodeDef in template.Nodes) | |
| { | |
| var newId = Guid.NewGuid(); | |
| idMapping[nodeDef.TempId] = newId; | |
| var taskNode = new TaskNode | |
| { | |
| Id = newId, | |
| GraphId = graphId, | |
| Label = nodeDef.Label, | |
| PosX = nodeDef.PosX, | |
| PosY = nodeDef.PosY, | |
| Type = nodeDef.Type, | |
| State = NodeState.Pending, | |
| CreatedAt = DateTime.UtcNow, | |
| Description = nodeDef.Description, | |
| Color = nodeDef.Color, | |
| IsPinned = false, | |
| Decision = string.IsNullOrEmpty(nodeDef.DecisionJson) ? null : nodeDef.DecisionJson | |
| }; | |
| // For normal sketch nodes without custom Decision JSON, populate standard default JSON | |
| if (nodeDef.Type == "sketch" && string.IsNullOrEmpty(nodeDef.DecisionJson)) | |
| { | |
| taskNode.Decision = $"{{\"description\":\"{nodeDef.Description}\",\"progress\":0,\"showProgress\":false,\"decision\":\"bottom\",\"assignees\":[],\"color\":\"{nodeDef.Color}\",\"isPinned\":false,\"tags\":[],\"status\":\"Todo\"}}"; | |
| } | |
| nodes.Add(taskNode); | |
| } | |
| // 2. Instantiate edges | |
| foreach (var edgeDef in template.Edges) | |
| { | |
| if (idMapping.TryGetValue(edgeDef.FromTempId, out var fromId) && | |
| idMapping.TryGetValue(edgeDef.ToTempId, out var toId)) | |
| { | |
| var edge = new Edge | |
| { | |
| Id = Guid.NewGuid(), | |
| GraphId = graphId, | |
| FromNodeId = fromId, | |
| ToNodeId = toId, | |
| Condition = edgeDef.Condition | |
| }; | |
| edges.Add(edge); | |
| } | |
| } | |
| return (nodes, edges); | |
| } | |
| } | |
| } | |