This commit is contained in:
2026-09-18 23:02:30 +03:30
parent 2ad0fbcfb8
commit eb1e805419
6 changed files with 676 additions and 641 deletions
+5 -5
View File
@@ -1,5 +1,5 @@
آخرین نسخه تایید شده - در بردهای انتشار برای هر کارت باید قابلیت های زیر وجود داشته باشد:
- در گروه بردها از ابزارها یک گزینه بنام "مدیریت تگ ها" اضافه کن و در صورت انتخاب کاربر مودال مدیریت تگ ها را نمایش بده. 1. تاریخچه عملیات انجام شده روی کارت
- قابلیت فیلتر کارت‌ها بر اساس تگ در مودال بردها اضافه شود. 2. نام افرادمسئول که وظیفه به آن ها محول یا مربوط می شود باید دریافت شود
- قابلیت Drag & Drop ستونها و کارت‌ها بین ستون‌ها پیاده‌سازی شود. 3. در صورتیکه کارت هایی از قبل موجود باشند، می توان هر کارت را به یک یا چند کارت مرتبط کرد تا از این طریق وابستگی وظایف رو درک کرد.
- قابلیت جستجوی کارت‌ها در برد فعال اضافه شود. 4. در مودال بردهای انتشار در بخش فیلتر بر اساس تگ ها، امکان حذف فیتر وجود ندارد. نحوه فیلتر بر اساس تگها رو اصلاح کن
+176
View File
@@ -0,0 +1,176 @@
const projectData = {
projectId: "550e8400-e29b-41d4-a716-446655440000",
projectName: "xReleaseAssistant",
projectTitle: "دستیار انتشار",
description: "مدیریت نسخه‌ها و نیازمندی‌های محصولات",
version: "1.1.0",
developer: "هادی خزاعی اصل",
company: "رایان پرداز کاوش",
metadata: {
createdAt: "2026-09-13T00:00:00Z",
updatedAt: "2026-09-18T00:00:00Z",
tags: ["release-management"],
customFields: {},
},
webhook: { url: "", clientId: "", enabled: false },
toolGroups: [
{
id: "product-management",
title: "پرونده",
icon: "📁",
description: "مدیریت چرخه حیات محصول",
tools: [
{
id: "clear-all",
title: "پاکسازی",
icon: "🗑️",
action: "clearAll",
description: "پاکسازی کامل",
},
{
id: "save-product",
title: "ذخیره",
icon: "💾",
action: "saveProduct",
description: "دانلود داده‌ها",
},
{
id: "load-product",
title: "بارگذاری",
icon: "📂",
action: "loadProduct",
description: "بارگذاری از فایل",
},
{
id: "product-settings",
title: "تنظیمات",
icon: "⚙️",
action: "openProductSettings",
description: "پیکربندی",
},
],
},
{
id: "boards",
title: "بردها",
icon: "📋",
description: "مدیریت بردهای انتشار",
tools: [
{
id: "release-boards",
title: "بردهای انتشار",
icon: "🚀",
action: "showReleaseBoards",
description: "مشاهده و مدیریت بردهای انتشار",
},
/* ✅ NEW: ابزار مدیریت تگ‌ها */
{
id: "tag-manager",
title: "مدیریت تگ‌ها",
icon: "🏷️",
action: "showTagManager",
description: "مدیریت تگ‌های بردها",
},
],
},
{
id: "reports",
title: "گزارش‌ها",
icon: "📊",
description: "تحلیل و گزارش‌گیری",
tools: [
{
id: "executive-dashboard",
title: "داشبورد مدیریتی",
icon: "📊",
action: "showExecutiveDashboard",
description: "نمای کلی با نمودارها",
},
{
id: "dependency-analysis",
title: "تحلیل وابستگی‌ها",
icon: "🔗",
action: "showDependencyAnalysis",
description: "تحلیل وابستگی‌ها",
},
{
id: "deployment-analysis",
title: "تحلیل استقرار",
icon: "🚀",
action: "showDeploymentAnalysis",
description: "تحلیل استقرارها",
},
{
id: "version-analysis",
title: "تحلیل نسخه",
icon: "🔢",
action: "showVersionAnalysis",
description: "تحلیل نسخه‌ها",
},
{
id: "risk-analysis",
title: "تحلیل ریسک",
icon: "⚠️",
action: "showRiskAnalysis",
description: "تحلیل ریسک‌ها",
},
{
id: "galaxy-chart",
title: "نمودار کهکشانی",
icon: "🌌",
action: "showGalaxyChart",
description: "نمودار کهکشانی",
},
],
},
],
appData: {
environments: [
{
id: "env-prod-001",
name: "Production",
description: "محیط عملیاتی اصلی - در دسترس کاربران نهایی",
backgroundColor: "#38a169",
textColor: "#ffffff",
},
{
id: "env-stage-002",
name: "Staging",
description: "محیط پیش از تولید - شبیه‌سازی Production",
backgroundColor: "#dd6b20",
textColor: "#ffffff",
},
{
id: "env-dev-003",
name: "Development",
description: "محیط توسعه - برای تیم فنی",
backgroundColor: "#3182ce",
textColor: "#ffffff",
},
{
id: "env-qa-004",
name: "QA",
description: "محیط تست کیفیت - کنترل کیفیت خودکار و دستی",
backgroundColor: "#805ad5",
textColor: "#ffffff",
},
{
id: "env-uat-005",
name: "UAT",
description: "تست پذیرش کاربر - تأیید کارفرما",
backgroundColor: "#d69e2e",
textColor: "#ffffff",
},
{
id: "env-dr-006",
name: "Disaster Recovery",
description: "محیط بازیابی پس از بحران - پشتیبان Production",
backgroundColor: "#e53e3e",
textColor: "#ffffff",
},
],
products: [],
boards: [],
boardTags: [],
},
};
+187
View File
@@ -0,0 +1,187 @@
{
"environments": [
{
"id": "env-1789757606914",
"name": "کاوش - توسعه",
"description": "این محیط فقط برای تست عملیاتی توسعه دهندگان است",
"backgroundColor": "#3f94ee",
"textColor": "#ffffff"
},
{
"id": "env-1789757658261",
"name": "کاوش تست",
"description": "این محیط برای تست محصول توسط تیم های تضمین کیفیت و تحلیل است",
"backgroundColor": "#df3416",
"textColor": "#ffffff"
},
{
"id": "env-1789757730121",
"name": "کانون - قرمز",
"description": "محیطی برای تست محصولات در فضای کانون",
"backgroundColor": "#ff0000",
"textColor": "#ffffff"
},
{
"id": "env-1789757791901",
"name": "کانون - آبی",
"description": "محیط انتشار عمومی محصولات در کانون",
"backgroundColor": "#0000ff",
"textColor": "#ffffff"
},
{
"id": "env-1789757853333",
"name": "سازمان - قرمز",
"description": "محیطی برای تست محصولات در سازمان",
"backgroundColor": "#ff0000",
"textColor": "#ffffff"
},
{
"id": "env-1789757900213",
"name": "سازمان - آبی",
"description": "محیط انتشار عمومی محصولات در سازمان",
"backgroundColor": "#0000ff",
"textColor": "#ffffff"
}
],
"products": [],
"boards": [
{
"id": "board-1789756462321",
"title": "ساماندهی",
"description": "مدیریت تسک های مرتبط با محصول ساماندهی",
"backgroundColor": "#173154",
"createdAt": "2026-09-18T18:34:22.321Z",
"updatedAt": "2026-09-18T18:34:59.453Z",
"columns": [
{
"id": "col-1789756462321-0",
"title": "📥 بک لاگ",
"backgroundColor": "#6b7208",
"textColor": "#b4cbf9",
"cards": [
{
"id": "card-1789757126382",
"title": "پلن توسعه",
"description": "بررسی کامل پلن توسعه در راستای نسخه جدید",
"estimatedDate": null,
"backgroundColor": "#787fe8",
"tags": [],
"checklist": [],
"assignees": [],
"dependencies": [],
"history": [
{
"from": "—",
"to": "📥 بک لاگ",
"date": "2026-09-18T18:45:26.382Z"
},
{
"from": "📥 بک لاگ",
"to": "📋 برای انجام",
"date": "2026-09-18T18:45:30.580Z"
},
{
"from": "📋 برای انجام",
"to": "📥 بک لاگ",
"date": "2026-09-18T18:45:32.310Z"
}
],
"createdAt": "2026-09-18T18:45:26.382Z",
"updatedAt": "2026-09-18T18:45:26.382Z"
}
]
},
{
"id": "col-1789756462321-1",
"title": "📋 برای انجام",
"backgroundColor": "#393e65",
"textColor": "#b4cbf9",
"cards": []
},
{
"id": "col-1789756462321-2",
"title": "🔨 در حال انجام",
"backgroundColor": "#453111",
"textColor": "#b4cbf9",
"cards": []
},
{
"id": "col-1789756462321-3",
"title": "🔍 برای تست",
"backgroundColor": "#542881",
"textColor": "#b4cbf9",
"cards": []
},
{
"id": "col-1789756462321-4",
"title": "✅ انجام شده",
"backgroundColor": "#087224",
"textColor": "#d8d96d",
"cards": []
}
]
},
{
"id": "board-1789756537937",
"title": "دفترچه ای",
"description": "مدیریت وظایف مرتبط با انتشار محصول دفترچه ای",
"backgroundColor": "#1e3757",
"createdAt": "2026-09-18T18:35:37.937Z",
"updatedAt": "2026-09-18T18:35:37.937Z",
"columns": [
{
"id": "col-1789756537937-0",
"title": "📥 بک لاگ",
"backgroundColor": "#6b7208",
"textColor": "#b4cbf9",
"cards": []
},
{
"id": "col-1789756537937-1",
"title": "📋 برای انجام",
"backgroundColor": "#393e65",
"textColor": "#b4cbf9",
"cards": []
},
{
"id": "col-1789756537937-2",
"title": "🔨 در حال انجام",
"backgroundColor": "#453111",
"textColor": "#b4cbf9",
"cards": []
},
{
"id": "col-1789756537937-3",
"title": "🔍 برای تست",
"backgroundColor": "#542881",
"textColor": "#b4cbf9",
"cards": []
},
{
"id": "col-1789756537937-4",
"title": "✅ انجام شده",
"backgroundColor": "#087224",
"textColor": "#d8d96d",
"cards": []
}
]
}
],
"boardTags": [
{
"id": "tag-1789755845541",
"name": "فوری",
"color": "#e14141"
},
{
"id": "tag-1789755857090",
"name": "حساس",
"color": "#e1d741"
},
{
"id": "tag-1789755888873",
"name": "عادی",
"color": "#4299e1"
}
]
}
+244
View File
@@ -0,0 +1,244 @@
{
"environments": [
{
"id": "env-1789757606914",
"name": "کاوش - توسعه",
"description": "این محیط فقط برای تست عملیاتی توسعه دهندگان است",
"backgroundColor": "#3f94ee",
"textColor": "#ffffff"
},
{
"id": "env-1789757658261",
"name": "کاوش تست",
"description": "این محیط برای تست محصول توسط تیم های تضمین کیفیت و تحلیل است",
"backgroundColor": "#df3416",
"textColor": "#ffffff"
},
{
"id": "env-1789757730121",
"name": "کانون - قرمز",
"description": "محیطی برای تست محصولات در فضای کانون",
"backgroundColor": "#ff0000",
"textColor": "#ffffff"
},
{
"id": "env-1789757791901",
"name": "کانون - آبی",
"description": "محیط انتشار عمومی محصولات در کانون",
"backgroundColor": "#0000ff",
"textColor": "#ffffff"
},
{
"id": "env-1789757853333",
"name": "سازمان - قرمز",
"description": "محیطی برای تست محصولات در سازمان",
"backgroundColor": "#ff0000",
"textColor": "#ffffff"
},
{
"id": "env-1789757900213",
"name": "سازمان - آبی",
"description": "محیط انتشار عمومی محصولات در سازمان",
"backgroundColor": "#0000ff",
"textColor": "#ffffff"
}
],
"products": [
{
"id": "prod-1789758196583",
"title": "زیر ساخت کاوش",
"description": "ارائه کلیه زیر ساخت های لازم برای محصولات",
"metadata": {
"createdAt": "2026-09-18T19:03:16.583Z",
"owner": "تیم زیر ساخت",
"customFields": {}
},
"projects": [
{
"id": "proj-1789758302242",
"title": "فریمورک",
"description": "نوگت فریمورک که کلیه زیر ساخت های لازم برای پروژه ها را ارائه می دهد.",
"type": "infrastructure",
"repositoryUrl": "",
"metadata": {
"createdAt": "2026-09-18T19:05:02.242Z",
"customFields": {},
"framework": ".net",
"language": "C#"
},
"dependencies": [],
"deployments": []
}
]
},
{
"id": "prod-1789759034126",
"title": "ساماندهی",
"description": "فرآیندهی ساماندهی",
"metadata": {
"createdAt": "2026-09-18T19:17:14.126Z",
"owner": "تیم املاک",
"customFields": {}
},
"projects": [
{
"id": "proj-1789759100918",
"title": "Rem13 Dotnet Bo",
"description": "سرویس های ساماندهی در بک آفیس",
"type": "backend",
"repositoryUrl": "",
"metadata": {
"createdAt": "2026-09-18T19:18:20.918Z",
"customFields": {},
"framework": ".net",
"language": "C#"
},
"dependencies": [
"proj-1789758302242"
],
"deployments": []
}
]
}
],
"boards": [
{
"id": "board-1789756462321",
"title": "ساماندهی",
"description": "مدیریت تسک های مرتبط با محصول ساماندهی",
"backgroundColor": "#173154",
"createdAt": "2026-09-18T18:34:22.321Z",
"updatedAt": "2026-09-18T18:34:59.453Z",
"columns": [
{
"id": "col-1789756462321-0",
"title": "📥 بک لاگ",
"backgroundColor": "#6b7208",
"textColor": "#b4cbf9",
"cards": [
{
"id": "card-1789757126382",
"title": "پلن توسعه",
"description": "بررسی کامل پلن توسعه در راستای نسخه جدید",
"estimatedDate": null,
"backgroundColor": "#787fe8",
"tags": [],
"checklist": [],
"assignees": [],
"dependencies": [],
"history": [
{
"from": "—",
"to": "📥 بک لاگ",
"date": "2026-09-18T18:45:26.382Z"
},
{
"from": "📥 بک لاگ",
"to": "📋 برای انجام",
"date": "2026-09-18T18:45:30.580Z"
},
{
"from": "📋 برای انجام",
"to": "📥 بک لاگ",
"date": "2026-09-18T18:45:32.310Z"
}
],
"createdAt": "2026-09-18T18:45:26.382Z",
"updatedAt": "2026-09-18T18:45:26.382Z"
}
]
},
{
"id": "col-1789756462321-1",
"title": "📋 برای انجام",
"backgroundColor": "#393e65",
"textColor": "#b4cbf9",
"cards": []
},
{
"id": "col-1789756462321-2",
"title": "🔨 در حال انجام",
"backgroundColor": "#453111",
"textColor": "#b4cbf9",
"cards": []
},
{
"id": "col-1789756462321-3",
"title": "🔍 برای تست",
"backgroundColor": "#542881",
"textColor": "#b4cbf9",
"cards": []
},
{
"id": "col-1789756462321-4",
"title": "✅ انجام شده",
"backgroundColor": "#087224",
"textColor": "#d8d96d",
"cards": []
}
]
},
{
"id": "board-1789756537937",
"title": "دفترچه ای",
"description": "مدیریت وظایف مرتبط با انتشار محصول دفترچه ای",
"backgroundColor": "#1e3757",
"createdAt": "2026-09-18T18:35:37.937Z",
"updatedAt": "2026-09-18T18:35:37.937Z",
"columns": [
{
"id": "col-1789756537937-0",
"title": "📥 بک لاگ",
"backgroundColor": "#6b7208",
"textColor": "#b4cbf9",
"cards": []
},
{
"id": "col-1789756537937-1",
"title": "📋 برای انجام",
"backgroundColor": "#393e65",
"textColor": "#b4cbf9",
"cards": []
},
{
"id": "col-1789756537937-2",
"title": "🔨 در حال انجام",
"backgroundColor": "#453111",
"textColor": "#b4cbf9",
"cards": []
},
{
"id": "col-1789756537937-3",
"title": "🔍 برای تست",
"backgroundColor": "#542881",
"textColor": "#b4cbf9",
"cards": []
},
{
"id": "col-1789756537937-4",
"title": "✅ انجام شده",
"backgroundColor": "#087224",
"textColor": "#d8d96d",
"cards": []
}
]
}
],
"boardTags": [
{
"id": "tag-1789755845541",
"name": "فوری",
"color": "#e14141"
},
{
"id": "tag-1789755857090",
"name": "حساس",
"color": "#e1d741"
},
{
"id": "tag-1789755888873",
"name": "عادی",
"color": "#4299e1"
}
]
}
+32 -318
View File
@@ -1730,7 +1730,6 @@
background: rgba(255, 255, 255, 0.2); background: rgba(255, 255, 255, 0.2);
margin: 0 4px; margin: 0 4px;
} }
/* ✅ NEW: استایل جستجو و فیلتر در نوار ابزار بردها */
.rb-search-box { .rb-search-box {
position: relative; position: relative;
display: flex; display: flex;
@@ -1787,7 +1786,6 @@
align-items: center; align-items: center;
gap: 4px; gap: 4px;
} }
/* ✅ NEW: نوار فیلتر تگ‌ها */
.rb-tag-filter-bar { .rb-tag-filter-bar {
display: flex; display: flex;
align-items: center; align-items: center;
@@ -2428,9 +2426,6 @@
color: var(--text-muted); color: var(--text-muted);
font-size: 12px; font-size: 12px;
} }
/* ═══════════════════════════════════════════════════
✅ NEW: استایل‌های Drag & Drop و فیلتر
═══════════════════════════════════════════════════ */
.card.hidden-by-filter { .card.hidden-by-filter {
display: none !important; display: none !important;
} }
@@ -2815,7 +2810,7 @@
</div> </div>
<div class="modal-body" id="projectDetailBody"></div> <div class="modal-body" id="projectDetailBody"></div>
<div class="modal-footer"> <div class="modal-footer">
<button class="btn btn-danger btn-sm" id="projectDetailDeleteBtn"> <button class="btn btn-danger" id="projectDetailDeleteBtn">
🗑️ حذف محصول</button 🗑️ حذف محصول</button
><button class="btn btn-ghost" data-close-modal>بستن</button> ><button class="btn btn-ghost" data-close-modal>بستن</button>
</div> </div>
@@ -3205,9 +3200,6 @@
<div class="modal-header"> <div class="modal-header">
<div class="modal-title">📊 داشبورد مدیریتی</div> <div class="modal-title">📊 داشبورد مدیریتی</div>
<div class="galaxy-toolbar"> <div class="galaxy-toolbar">
<button class="btn btn-sm" id="dashboardRefresh">
🔄 به‌روزرسانی
</button>
</div> </div>
<button class="modal-close" data-close-modal>✕</button> <button class="modal-close" data-close-modal>✕</button>
</div> </div>
@@ -3227,7 +3219,6 @@
<div class="modal-header"> <div class="modal-header">
<div class="modal-title">🔗 تحلیل وابستگی‌ها</div> <div class="modal-title">🔗 تحلیل وابستگی‌ها</div>
<div class="galaxy-toolbar"> <div class="galaxy-toolbar">
<button class="btn btn-sm" id="depAnalysisRefresh">🔄</button>
</div> </div>
<button class="modal-close" data-close-modal>✕</button> <button class="modal-close" data-close-modal>✕</button>
</div> </div>
@@ -3250,7 +3241,6 @@
<div class="modal-header"> <div class="modal-header">
<div class="modal-title">🚀 تحلیل استقرار</div> <div class="modal-title">🚀 تحلیل استقرار</div>
<div class="galaxy-toolbar"> <div class="galaxy-toolbar">
<button class="btn btn-sm" id="deployAnalysisRefresh">🔄</button>
</div> </div>
<button class="modal-close" data-close-modal>✕</button> <button class="modal-close" data-close-modal>✕</button>
</div> </div>
@@ -3276,7 +3266,6 @@
<div class="modal-header"> <div class="modal-header">
<div class="modal-title">🔢 تحلیل نسخه</div> <div class="modal-title">🔢 تحلیل نسخه</div>
<div class="galaxy-toolbar"> <div class="galaxy-toolbar">
<button class="btn btn-sm" id="verAnalysisRefresh">🔄</button>
</div> </div>
<button class="modal-close" data-close-modal>✕</button> <button class="modal-close" data-close-modal>✕</button>
</div> </div>
@@ -3296,7 +3285,6 @@
<div class="modal-header"> <div class="modal-header">
<div class="modal-title">⚠️ تحلیل ریسک</div> <div class="modal-title">⚠️ تحلیل ریسک</div>
<div class="galaxy-toolbar"> <div class="galaxy-toolbar">
<button class="btn btn-sm" id="riskAnalysisRefresh">🔄</button>
</div> </div>
<button class="modal-close" data-close-modal>✕</button> <button class="modal-close" data-close-modal>✕</button>
</div> </div>
@@ -3329,7 +3317,6 @@
🏷️ تگ‌ها 🏷️ تگ‌ها
</button> </button>
<div class="rb-toolbar-separator"></div> <div class="rb-toolbar-separator"></div>
<!-- ✅ NEW: جستجوی کارت‌ها -->
<div class="rb-search-box"> <div class="rb-search-box">
<span style="opacity: 0.7; font-size: 12px">🔍</span> <span style="opacity: 0.7; font-size: 12px">🔍</span>
<input <input
@@ -3353,13 +3340,12 @@
> >
<div class="rb-toolbar-separator"></div> <div class="rb-toolbar-separator"></div>
<button class="btn" id="rbUndoBtn" title="بازگشت (Ctrl+Z)" disabled> <button class="btn" id="rbUndoBtn" title="بازگشت (Ctrl+Z)" disabled>
↩️ بازگشت ↩️
</button> </button>
<button class="btn" id="rbRedoBtn" title="از نو (Ctrl+Y)" disabled> <button class="btn" id="rbRedoBtn" title="از نو (Ctrl+Y)" disabled>
↪️ از نو ↪️
</button> </button>
</div> </div>
<!-- ✅ NEW: نوار فیلتر تگ‌ها -->
<div class="rb-tag-filter-bar" id="rbTagFilterBar"> <div class="rb-tag-filter-bar" id="rbTagFilterBar">
<span class="rb-tag-filter-label">🏷️ فیلتر تگ:</span> <span class="rb-tag-filter-label">🏷️ فیلتر تگ:</span>
<div <div
@@ -3413,8 +3399,8 @@
</div> </div>
<!-- Footer --> <!-- Footer -->
<div class="modal-footer"> <div class="modal-footer">
<div class="dashboard-footer-stats" id="rbFooterStats"></div>
<button class="btn btn-ghost" data-close-modal>بستن</button> <button class="btn btn-ghost" data-close-modal>بستن</button>
<div class="dashboard-footer-stats" id="rbFooterStats"></div>
</div> </div>
</div> </div>
</div> </div>
@@ -3480,31 +3466,31 @@
> >
<div <div
class="rb-preview-column" class="rb-preview-column"
style="background: #edf2f7; color: #1a202c" style="background: #6b7208; color: #b4cbf9"
> >
📥 بک لاگ 📥 بک لاگ
</div> </div>
<div <div
class="rb-preview-column" class="rb-preview-column"
style="background: #ebf8ff; color: #1a202c" style="background: #393e65; color: #b4cbf9"
> >
📋 برای انجام 📋 برای انجام
</div> </div>
<div <div
class="rb-preview-column" class="rb-preview-column"
style="background: #fef5e7; color: #1a202c" style="background: #453111; color: #b4cbf9"
> >
🔨 در حال انجام 🔨 در حال انجام
</div> </div>
<div <div
class="rb-preview-column" class="rb-preview-column"
style="background: #faf5ff; color: #1a202c" style="background: #542881; color: #b4cbf9"
> >
🔍 برای تست 🔍 برای تست
</div> </div>
<div <div
class="rb-preview-column" class="rb-preview-column"
style="background: #f0fff4; color: #1a202c" style="background: #087224; color: #d8d96d"
> >
✅ انجام شده ✅ انجام شده
</div> </div>
@@ -3721,10 +3707,10 @@
<div class="rb-tag-list" id="rbTagList"></div> <div class="rb-tag-list" id="rbTagList"></div>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button class="btn btn-ghost" data-close-modal>بستن</button>
<div style="font-size: 11px; color: var(--text-muted)"> <div style="font-size: 11px; color: var(--text-muted)">
💡 تغییرات تگ‌ها به صورت خودکار در تمام کارت‌ها اعمال می‌شود 💡 تغییرات تگ‌ها به صورت خودکار در تمام کارت‌ها اعمال می‌شود
</div> </div>
<button class="btn btn-ghost" data-close-modal>بستن</button>
</div> </div>
</div> </div>
</div> </div>
@@ -3790,177 +3776,21 @@
<div class="modal-title">💾 بازیابی خودکار داده‌ها</div> <div class="modal-title">💾 بازیابی خودکار داده‌ها</div>
</div> </div>
<div class="modal-body"> <div class="modal-body">
<div style="text-align: center; padding: 24px 16px">
<div style="font-size: 48px; margin-bottom: 16px">💾</div>
<div <div
style=" style="
background: linear-gradient(to left, #ebf8ff, #e6f6ff);
border: 1px solid #90cdf4;
border-right: 4px solid var(--info);
padding: 14px 18px;
border-radius: 8px;
margin-bottom: 16px;
font-size: 13px;
line-height: 1.8;
"
>
<div
style="
font-weight: 700;
font-size: 14px; font-size: 14px;
margin-bottom: 8px;
color: var(--primary);
"
>
⚠️ داده ذخیره‌شده خودکار یافت شد
</div>
<div style="color: var(--text-muted)">
به نظر می‌رسد در جلسه قبلی، تغییراتی در برنامه اعمال شده و به صورت
خودکار ذخیره شده‌اند.
</div>
<div
style="
margin-top: 10px;
font-size: 12px;
color: var(--text-muted);
"
>
📅 تاریخ ذخیره:
<strong id="rbAutosaveDate" style="color: var(--primary)"
>—</strong
>
</div>
</div>
<div
style="
background: var(--border-light);
border: 1px solid var(--border);
border-radius: 8px;
padding: 12px;
margin-bottom: 16px;
"
>
<div
style="
font-weight: 700; font-weight: 700;
font-size: 13px; color: var(--text);
margin-bottom: 10px; margin-bottom: 8px;
color: var(--primary);
" "
> >
📊 محتویات داده‌های ذخیره‌شده: داده‌هایی در حافظه موقت وجود دارند
</div> </div>
<div <div style="font-size: 12px; color: var(--text-muted)">
style=" آیا مایل به بازیابی آن‌ها هستید؟
display: grid;
grid-template-columns: 1fr 1fr;
gap: 8px;
font-size: 12px;
"
>
<div
style="
display: flex;
justify-content: space-between;
padding: 6px 10px;
background: var(--card-bg);
border-radius: 6px;
"
>
<span>🌍 محیط‌ها:</span
><strong id="rbAutosaveEnvCount" style="color: var(--primary)"
>0</strong
>
</div> </div>
<div
style="
display: flex;
justify-content: space-between;
padding: 6px 10px;
background: var(--card-bg);
border-radius: 6px;
"
>
<span>📦 محصولات:</span
><strong id="rbAutosaveProdCount" style="color: var(--primary)"
>0</strong
>
</div>
<div
style="
display: flex;
justify-content: space-between;
padding: 6px 10px;
background: var(--card-bg);
border-radius: 6px;
"
>
<span>🌿 پروژه‌ها:</span
><strong id="rbAutosaveProjCount" style="color: var(--primary)"
>0</strong
>
</div>
<div
style="
display: flex;
justify-content: space-between;
padding: 6px 10px;
background: var(--card-bg);
border-radius: 6px;
"
>
<span>🚀 استقرارها:</span
><strong id="rbAutosaveDepCount" style="color: var(--primary)"
>0</strong
>
</div>
<div
style="
display: flex;
justify-content: space-between;
padding: 6px 10px;
background: var(--card-bg);
border-radius: 6px;
"
>
<span>📋 بردها:</span
><strong id="rbAutosaveBoardCount" style="color: var(--primary)"
>0</strong
>
</div>
<div
style="
display: flex;
justify-content: space-between;
padding: 6px 10px;
background: var(--card-bg);
border-radius: 6px;
"
>
<span>🏷️ تگ‌های برد:</span
><strong id="rbAutosaveTagCount" style="color: var(--primary)"
>0</strong
>
</div>
</div>
</div>
<div style="font-size: 13px; color: var(--text); line-height: 1.8">
آیا می‌خواهید این داده‌ها را بازیابی کنید؟
<ul
style="
margin-top: 8px;
padding-right: 20px;
color: var(--text-muted);
font-size: 12px;
"
>
<li>
<strong>بازیابی:</strong> تمام داده‌های ذخیره‌شده جایگزین
داده‌های فعلی می‌شوند
</li>
<li>
<strong>نادیده گرفتن:</strong> داده‌های خودکار حذف شده و
داده‌های فعلی حفظ می‌شوند
</li>
</ul>
</div> </div>
</div> </div>
<div class="modal-footer" style="justify-content: space-between"> <div class="modal-footer" style="justify-content: space-between">
@@ -4031,7 +3861,7 @@
projectName: "xReleaseAssistant", projectName: "xReleaseAssistant",
projectTitle: "دستیار انتشار", projectTitle: "دستیار انتشار",
description: "مدیریت نسخه‌ها و نیازمندی‌های محصولات", description: "مدیریت نسخه‌ها و نیازمندی‌های محصولات",
version: "1.2.0", version: "1.1.0",
developer: "هادی خزاعی اصل", developer: "هادی خزاعی اصل",
company: "رایان پرداز کاوش", company: "رایان پرداز کاوش",
metadata: { metadata: {
@@ -4091,7 +3921,6 @@
action: "showReleaseBoards", action: "showReleaseBoards",
description: "مشاهده و مدیریت بردهای انتشار", description: "مشاهده و مدیریت بردهای انتشار",
}, },
/* ✅ NEW: ابزار مدیریت تگ‌ها */
{ {
id: "tag-manager", id: "tag-manager",
title: "مدیریت تگ‌ها", title: "مدیریت تگ‌ها",
@@ -4153,50 +3982,7 @@
}, },
], ],
appData: { appData: {
environments: [ environments: [],
{
id: "env-prod-001",
name: "Production",
description: "محیط عملیاتی اصلی - در دسترس کاربران نهایی",
backgroundColor: "#38a169",
textColor: "#ffffff",
},
{
id: "env-stage-002",
name: "Staging",
description: "محیط پیش از تولید - شبیه‌سازی Production",
backgroundColor: "#dd6b20",
textColor: "#ffffff",
},
{
id: "env-dev-003",
name: "Development",
description: "محیط توسعه - برای تیم فنی",
backgroundColor: "#3182ce",
textColor: "#ffffff",
},
{
id: "env-qa-004",
name: "QA",
description: "محیط تست کیفیت - کنترل کیفیت خودکار و دستی",
backgroundColor: "#805ad5",
textColor: "#ffffff",
},
{
id: "env-uat-005",
name: "UAT",
description: "تست پذیرش کاربر - تأیید کارفرما",
backgroundColor: "#d69e2e",
textColor: "#ffffff",
},
{
id: "env-dr-006",
name: "Disaster Recovery",
description: "محیط بازیابی پس از بحران - پشتیبان Production",
backgroundColor: "#e53e3e",
textColor: "#ffffff",
},
],
products: [], products: [],
boards: [], boards: [],
boardTags: [], boardTags: [],
@@ -4546,7 +4332,7 @@
getSectionHTML() { getSectionHTML() {
const d = this.getData(); const d = this.getData();
let h = `<div class="board-section" id="section-dashboard">`; let h = `<div class="board-section" id="section-dashboard">`;
h += `<div class="board-header"><div class="board-header-title"><span class="collapse-icon">▼</span>📊 داشبورد مدیریتی</div><div class="board-header-actions"><button class="btn btn-accent btn-sm" onclick="DashboardManager.open()">📊 مشاهده کامل</button></div></div>`; h += `<div class="board-header"><div class="board-header-title"><span class="collapse-icon">▼</span>📊 داشبورد مدیریتی</div><div class="board-header-actions"><button class="btn btn-accent" onclick="DashboardManager.open()">📊 مشاهده کامل</button></div></div>`;
h += `<div class="section-content">`; h += `<div class="section-content">`;
h += '<div class="dashboard-kpi-row" style="margin-bottom:16px">'; h += '<div class="dashboard-kpi-row" style="margin-bottom:16px">';
h += `<div class="dashboard-kpi-card"><div class="dashboard-kpi-icon">📦</div><div class="dashboard-kpi-value">${d.products}</div><div class="dashboard-kpi-label">محصول</div></div>`; h += `<div class="dashboard-kpi-card"><div class="dashboard-kpi-icon">📦</div><div class="dashboard-kpi-value">${d.products}</div><div class="dashboard-kpi-label">محصول</div></div>`;
@@ -4972,7 +4758,6 @@
showReleaseBoards() { showReleaseBoards() {
ReleaseBoardsManager.open(); ReleaseBoardsManager.open();
}, },
/* ✅ NEW: اکشن مدیریت تگ‌ها */
showTagManager() { showTagManager() {
ReleaseBoardsManager.openTagManager(); ReleaseBoardsManager.openTagManager();
}, },
@@ -5969,8 +5754,6 @@
: 0; : 0;
document.getElementById("dashboardFooterStats").innerHTML = document.getElementById("dashboardFooterStats").innerHTML =
`<span>📦 محصولات: <span class="stat-highlight">${d.products}</span></span><span>🌿 پروژه‌ها: <span class="stat-highlight">${d.projects}</span></span><span>🚀 استقرارها: <span class="stat-highlight">${d.deploys}</span></span><span>📈 پوشش استقرار: <span class="stat-highlight">${coverage}%</span></span>`; `<span>📦 محصولات: <span class="stat-highlight">${d.products}</span></span><span>🌿 پروژه‌ها: <span class="stat-highlight">${d.projects}</span></span><span>🚀 استقرارها: <span class="stat-highlight">${d.deploys}</span></span><span>📈 پوشش استقرار: <span class="stat-highlight">${coverage}%</span></span>`;
document.getElementById("dashboardRefresh").onclick = () =>
this.render();
}, },
renderDonut(cid, data) { renderDonut(cid, data) {
const c = document.getElementById(cid); const c = document.getElementById(cid);
@@ -6724,53 +6507,12 @@
checkRecovery() { checkRecovery() {
const saved = this.load(); const saved = this.load();
if (!saved || !saved.appData) return; if (!saved || !saved.appData) return;
const appData = saved.appData;
const stats = {
environments: (appData.environments || []).length,
products: (appData.products || []).length,
projects: 0,
deployments: 0,
boards: (appData.boards || []).length,
boardTags: (appData.boardTags || []).length,
};
(appData.products || []).forEach((prod) => {
stats.projects += (prod.projects || []).length;
(prod.projects || []).forEach((pr) => {
stats.deployments += (pr.deployments || []).filter(
(d) => d.status === "active",
).length;
});
});
const dateEl = document.getElementById("rbAutosaveDate");
const envCountEl = document.getElementById("rbAutosaveEnvCount");
const prodCountEl = document.getElementById("rbAutosaveProdCount");
const projCountEl = document.getElementById("rbAutosaveProjCount");
const depCountEl = document.getElementById("rbAutosaveDepCount");
const boardCountEl = document.getElementById("rbAutosaveBoardCount");
if (dateEl) {
const d = new Date(saved.savedAt);
dateEl.textContent =
d.toLocaleDateString("fa-IR") +
" - " +
d.toLocaleTimeString("fa-IR", {
hour: "2-digit",
minute: "2-digit",
});
}
if (envCountEl)
envCountEl.textContent = stats.environments.toLocaleString("fa-IR");
if (prodCountEl)
prodCountEl.textContent = stats.products.toLocaleString("fa-IR");
if (projCountEl)
projCountEl.textContent = stats.projects.toLocaleString("fa-IR");
if (depCountEl)
depCountEl.textContent = stats.deployments.toLocaleString("fa-IR");
if (boardCountEl)
boardCountEl.textContent = stats.boards.toLocaleString("fa-IR");
document.getElementById("rbRecoverAutosaveBtn").onclick = () => document.getElementById("rbRecoverAutosaveBtn").onclick = () =>
this.recover(); this.recover();
document.getElementById("rbDiscardAutosaveBtn").onclick = () => document.getElementById("rbDiscardAutosaveBtn").onclick = () =>
this.discard(); this.discard();
setTimeout(() => { setTimeout(() => {
ModalManager.open("rbAutosaveModal"); ModalManager.open("rbAutosaveModal");
}, 600); }, 600);
@@ -6825,28 +6567,28 @@
DEFAULT_COLUMNS: [ DEFAULT_COLUMNS: [
{ {
title: "📥 بک لاگ", title: "📥 بک لاگ",
backgroundColor: "#edf2f7", backgroundColor: "#6b7208",
textColor: "#1a202c", textColor: "#b4cbf9",
}, },
{ {
title: "📋 برای انجام", title: "📋 برای انجام",
backgroundColor: "#ebf8ff", backgroundColor: "#393e65",
textColor: "#1a202c", textColor: "#b4cbf9",
}, },
{ {
title: "🔨 در حال انجام", title: "🔨 در حال انجام",
backgroundColor: "#fef5e7", backgroundColor: "#453111",
textColor: "#1a202c", textColor: "#b4cbf9",
}, },
{ {
title: "🔍 برای تست", title: "🔍 برای تست",
backgroundColor: "#faf5ff", backgroundColor: "#542881",
textColor: "#1a202c", textColor: "#b4cbf9",
}, },
{ {
title: "✅ انجام شده", title: "✅ انجام شده",
backgroundColor: "#f0fff4", backgroundColor: "#087224",
textColor: "#1a202c", textColor: "#d8d96d",
}, },
], ],
open() { open() {
@@ -6897,7 +6639,6 @@
} else { } else {
this._incrementalRender(board); this._incrementalRender(board);
} }
/* ✅ NEW: اعمال فیلترها و اتصال درگ پس از رندر */
this.applyFilters(); this.applyFilters();
this.initDragAndDrop(); this.initDragAndDrop();
this.updateFooterStats(); this.updateFooterStats();
@@ -7098,9 +6839,6 @@ ${checklistTotal > 0 ? `<span class="card-meta-item">✅ ${checklistDone}/${chec
${checklistHtml} ${checklistHtml}
</div>`; </div>`;
}, },
/* ═══════════════════════════════════════════════════
✅ NEW: فیلتر تگ‌ها
═══════════════════════════════════════════════════ */
renderFilterBar() { renderFilterBar() {
const container = document.getElementById("rbTagFilterContainer"); const container = document.getElementById("rbTagFilterContainer");
const clearBtn = document.getElementById("rbClearTagFilter"); const clearBtn = document.getElementById("rbClearTagFilter");
@@ -7138,9 +6876,6 @@ ${checklistHtml}
}; };
} }
}, },
/* ═══════════════════════════════════════════════════
✅ NEW: اعمال فیلتر و جستجو
═══════════════════════════════════════════════════ */
applyFilters() { applyFilters() {
const board = this.getActiveBoard(); const board = this.getActiveBoard();
if (!board) return; if (!board) return;
@@ -7224,9 +6959,6 @@ ${checklistHtml}
} }
} }
}, },
/* ═══════════════════════════════════════════════════
✅ NEW: رویدادهای جستجو
═══════════════════════════════════════════════════ */
bindSearchEvents() { bindSearchEvents() {
const inp = document.getElementById("rbCardSearchInput"); const inp = document.getElementById("rbCardSearchInput");
const clr = document.getElementById("rbCardSearchClear"); const clr = document.getElementById("rbCardSearchClear");
@@ -7253,9 +6985,6 @@ ${checklistHtml}
inp.focus(); inp.focus();
}; };
}, },
/* ═══════════════════════════════════════════════════
✅ NEW: Drag & Drop
═══════════════════════════════════════════════════ */
initDragAndDrop() { initDragAndDrop() {
const wrapper = document.getElementById("rbBoardWrapper"); const wrapper = document.getElementById("rbBoardWrapper");
if (!wrapper) return; if (!wrapper) return;
@@ -7350,7 +7079,6 @@ ${checklistHtml}
.querySelectorAll(".drag-over-column") .querySelectorAll(".drag-over-column")
.forEach((el) => el.classList.remove("drag-over-column")); .forEach((el) => el.classList.remove("drag-over-column"));
}, },
/* ── جابجایی کارت بین ستون‌ها ── */
moveCard(cardId, targetColumnId) { moveCard(cardId, targetColumnId) {
const board = this.getActiveBoard(); const board = this.getActiveBoard();
if (!board) return; if (!board) return;
@@ -7387,7 +7115,6 @@ ${checklistHtml}
2000, 2000,
); );
}, },
/* ── جابجایی ستون‌ها ── */
moveColumn(sourceColId, targetColId) { moveColumn(sourceColId, targetColId) {
const board = this.getActiveBoard(); const board = this.getActiveBoard();
if (!board) return; if (!board) return;
@@ -7406,7 +7133,6 @@ ${checklistHtml}
this.render(true); this.render(true);
showToast("📊 ستون جابجا شد", "success", 2000); showToast("📊 ستون جابجا شد", "success", 2000);
}, },
/* ── مدیریت برد ── */
getActiveBoard() { getActiveBoard() {
return (projectData.appData.boards || []).find( return (projectData.appData.boards || []).find(
(b) => b.id === this.activeBoardId, (b) => b.id === this.activeBoardId,
@@ -7525,7 +7251,6 @@ ${checklistHtml}
showToast("برد حذف شد", "warning"); showToast("برد حذف شد", "warning");
this.render(true); this.render(true);
}, },
/* ── مدیریت ستون ── */
openNewColumnModal() { openNewColumnModal() {
if (!this.getActiveBoard()) { if (!this.getActiveBoard()) {
showToast("ابتدا یک برد ایجاد کنید", "warning"); showToast("ابتدا یک برد ایجاد کنید", "warning");
@@ -7600,7 +7325,6 @@ ${checklistHtml}
showToast("ستون حذف شد", "warning"); showToast("ستون حذف شد", "warning");
this.render(true); this.render(true);
}, },
/* ── مدیریت کارت ── */
openNewCardModal(columnId) { openNewCardModal(columnId) {
this.editing.cardId = null; this.editing.cardId = null;
this.editing.columnForCard = columnId; this.editing.columnForCard = columnId;
@@ -7818,7 +7542,6 @@ ${checklistHtml}
document.getElementById("rbDeleteCardBtn").onclick = () => document.getElementById("rbDeleteCardBtn").onclick = () =>
this.deleteCard(); this.deleteCard();
}, },
/* ── Toolbar Events ── */
bindToolbarEvents() { bindToolbarEvents() {
document.getElementById("rbEditBoard").onclick = () => document.getElementById("rbEditBoard").onclick = () =>
this.openEditBoardModal(); this.openEditBoardModal();
@@ -7852,7 +7575,6 @@ ${checklistHtml}
document.getElementById("rbFooterStats").innerHTML = document.getElementById("rbFooterStats").innerHTML =
`<span>📋 بردها: <span class="stat-highlight">${boards.length}</span></span><span>📑 ستون‌ها: <span class="stat-highlight">${boards.reduce((s, b) => s + b.columns.length, 0)}</span></span><span>📝 کارت‌ها: <span class="stat-highlight">${totalCards}</span></span>`; `<span>📋 بردها: <span class="stat-highlight">${boards.length}</span></span><span>📑 ستون‌ها: <span class="stat-highlight">${boards.reduce((s, b) => s + b.columns.length, 0)}</span></span><span>📝 کارت‌ها: <span class="stat-highlight">${totalCards}</span></span>`;
}, },
/* ── Tag Manager ── */
openTagManager() { openTagManager() {
ModalManager.open("rbTagManagerModal"); ModalManager.open("rbTagManagerModal");
this.renderTagList(); this.renderTagList();
@@ -8089,8 +7811,6 @@ ${checklistHtml}
this.renderRiskList("depRiskList", d); this.renderRiskList("depRiskList", d);
document.getElementById("depAnalysisFooterStats").innerHTML = document.getElementById("depAnalysisFooterStats").innerHTML =
`<span>🔗 کل: <span class="stat-highlight">${d.totalDeps}</span></span><span>⚠️ گلوگاه: <span class="stat-highlight">${d.bottlenecks.length}</span></span><span>🔴 شکسته: <span class="stat-highlight">${d.brokenDeps}</span></span><span>🔵 ایزوله: <span class="stat-highlight">${d.isolated.length}</span></span>`; `<span>🔗 کل: <span class="stat-highlight">${d.totalDeps}</span></span><span>⚠️ گلوگاه: <span class="stat-highlight">${d.bottlenecks.length}</span></span><span>🔴 شکسته: <span class="stat-highlight">${d.brokenDeps}</span></span><span>🔵 ایزوله: <span class="stat-highlight">${d.isolated.length}</span></span>`;
document.getElementById("depAnalysisRefresh").onclick = () =>
this.render();
}, },
renderHubChart(cid, bottlenecks) { renderHubChart(cid, bottlenecks) {
const c = document.getElementById(cid); const c = document.getElementById(cid);
@@ -8463,8 +8183,6 @@ ${checklistHtml}
this.renderRiskList("deployRiskList", d.riskList); this.renderRiskList("deployRiskList", d.riskList);
document.getElementById("deployAnalysisFooterStats").innerHTML = document.getElementById("deployAnalysisFooterStats").innerHTML =
`<span>🚀 کل: <span class="stat-highlight">${d.total}</span></span><span>📈 پوشش: <span class="stat-highlight">${d.coverage}%</span></span><span>⚠️ ریسک‌ها: <span class="stat-highlight">${d.riskList.length}</span></span>`; `<span>🚀 کل: <span class="stat-highlight">${d.total}</span></span><span>📈 پوشش: <span class="stat-highlight">${d.coverage}%</span></span><span>⚠️ ریسک‌ها: <span class="stat-highlight">${d.riskList.length}</span></span>`;
document.getElementById("deployAnalysisRefresh").onclick = () =>
this.render();
}, },
renderEnvBarChart(cid, edc) { renderEnvBarChart(cid, edc) {
const c = document.getElementById(cid); const c = document.getElementById(cid);
@@ -8888,8 +8606,6 @@ ${checklistHtml}
this.renderRiskList("verRiskList", d.riskList); this.renderRiskList("verRiskList", d.riskList);
document.getElementById("verAnalysisFooterStats").innerHTML = document.getElementById("verAnalysisFooterStats").innerHTML =
`<span>🔢 کل: <span class="stat-highlight">${d.total}</span></span><span>📦 یکتا: <span class="stat-highlight">${d.uniqueVersions}</span></span><span>📈 میانگین: <span class="stat-highlight">${d.avgVersion}</span></span><span>⚠️ ریسک‌ها: <span class="stat-highlight">${d.riskList.length}</span></span>`; `<span>🔢 کل: <span class="stat-highlight">${d.total}</span></span><span>📦 یکتا: <span class="stat-highlight">${d.uniqueVersions}</span></span><span>📈 میانگین: <span class="stat-highlight">${d.avgVersion}</span></span><span>⚠️ ریسک‌ها: <span class="stat-highlight">${d.riskList.length}</span></span>`;
document.getElementById("verAnalysisRefresh").onclick = () =>
this.render();
}, },
renderMajorBarChart(cid, majorCounts) { renderMajorBarChart(cid, majorCounts) {
const c = document.getElementById(cid); const c = document.getElementById(cid);
@@ -9274,8 +8990,6 @@ ${checklistHtml}
this.renderRiskList("riskDetailList", d.risks); this.renderRiskList("riskDetailList", d.risks);
document.getElementById("riskAnalysisFooterStats").innerHTML = document.getElementById("riskAnalysisFooterStats").innerHTML =
`<span>🎯 سلامت: <span class="stat-highlight">${d.healthScore}%</span></span><span>⚠️ ریسک‌ها: <span class="stat-highlight">${d.total}</span></span><span>🔴 بحرانی: <span class="stat-highlight">${d.crit}</span></span><span>🟠 بالا: <span class="stat-highlight">${d.high}</span></span>`; `<span>🎯 سلامت: <span class="stat-highlight">${d.healthScore}%</span></span><span>⚠️ ریسک‌ها: <span class="stat-highlight">${d.total}</span></span><span>🔴 بحرانی: <span class="stat-highlight">${d.crit}</span></span><span>🟠 بالا: <span class="stat-highlight">${d.high}</span></span>`;
document.getElementById("riskAnalysisRefresh").onclick = () =>
this.render();
}, },
renderSeverityDonut(cid, d) { renderSeverityDonut(cid, d) {
const c = document.getElementById(cid); const c = document.getElementById(cid);
+32 -318
View File
@@ -1730,7 +1730,6 @@
background: rgba(255, 255, 255, 0.2); background: rgba(255, 255, 255, 0.2);
margin: 0 4px; margin: 0 4px;
} }
/* ✅ NEW: استایل جستجو و فیلتر در نوار ابزار بردها */
.rb-search-box { .rb-search-box {
position: relative; position: relative;
display: flex; display: flex;
@@ -1787,7 +1786,6 @@
align-items: center; align-items: center;
gap: 4px; gap: 4px;
} }
/* ✅ NEW: نوار فیلتر تگ‌ها */
.rb-tag-filter-bar { .rb-tag-filter-bar {
display: flex; display: flex;
align-items: center; align-items: center;
@@ -2428,9 +2426,6 @@
color: var(--text-muted); color: var(--text-muted);
font-size: 12px; font-size: 12px;
} }
/* ═══════════════════════════════════════════════════
✅ NEW: استایل‌های Drag & Drop و فیلتر
═══════════════════════════════════════════════════ */
.card.hidden-by-filter { .card.hidden-by-filter {
display: none !important; display: none !important;
} }
@@ -2815,7 +2810,7 @@
</div> </div>
<div class="modal-body" id="projectDetailBody"></div> <div class="modal-body" id="projectDetailBody"></div>
<div class="modal-footer"> <div class="modal-footer">
<button class="btn btn-danger btn-sm" id="projectDetailDeleteBtn"> <button class="btn btn-danger" id="projectDetailDeleteBtn">
🗑️ حذف محصول</button 🗑️ حذف محصول</button
><button class="btn btn-ghost" data-close-modal>بستن</button> ><button class="btn btn-ghost" data-close-modal>بستن</button>
</div> </div>
@@ -3205,9 +3200,6 @@
<div class="modal-header"> <div class="modal-header">
<div class="modal-title">📊 داشبورد مدیریتی</div> <div class="modal-title">📊 داشبورد مدیریتی</div>
<div class="galaxy-toolbar"> <div class="galaxy-toolbar">
<button class="btn btn-sm" id="dashboardRefresh">
🔄 به‌روزرسانی
</button>
</div> </div>
<button class="modal-close" data-close-modal>✕</button> <button class="modal-close" data-close-modal>✕</button>
</div> </div>
@@ -3227,7 +3219,6 @@
<div class="modal-header"> <div class="modal-header">
<div class="modal-title">🔗 تحلیل وابستگی‌ها</div> <div class="modal-title">🔗 تحلیل وابستگی‌ها</div>
<div class="galaxy-toolbar"> <div class="galaxy-toolbar">
<button class="btn btn-sm" id="depAnalysisRefresh">🔄</button>
</div> </div>
<button class="modal-close" data-close-modal>✕</button> <button class="modal-close" data-close-modal>✕</button>
</div> </div>
@@ -3250,7 +3241,6 @@
<div class="modal-header"> <div class="modal-header">
<div class="modal-title">🚀 تحلیل استقرار</div> <div class="modal-title">🚀 تحلیل استقرار</div>
<div class="galaxy-toolbar"> <div class="galaxy-toolbar">
<button class="btn btn-sm" id="deployAnalysisRefresh">🔄</button>
</div> </div>
<button class="modal-close" data-close-modal>✕</button> <button class="modal-close" data-close-modal>✕</button>
</div> </div>
@@ -3276,7 +3266,6 @@
<div class="modal-header"> <div class="modal-header">
<div class="modal-title">🔢 تحلیل نسخه</div> <div class="modal-title">🔢 تحلیل نسخه</div>
<div class="galaxy-toolbar"> <div class="galaxy-toolbar">
<button class="btn btn-sm" id="verAnalysisRefresh">🔄</button>
</div> </div>
<button class="modal-close" data-close-modal>✕</button> <button class="modal-close" data-close-modal>✕</button>
</div> </div>
@@ -3296,7 +3285,6 @@
<div class="modal-header"> <div class="modal-header">
<div class="modal-title">⚠️ تحلیل ریسک</div> <div class="modal-title">⚠️ تحلیل ریسک</div>
<div class="galaxy-toolbar"> <div class="galaxy-toolbar">
<button class="btn btn-sm" id="riskAnalysisRefresh">🔄</button>
</div> </div>
<button class="modal-close" data-close-modal>✕</button> <button class="modal-close" data-close-modal>✕</button>
</div> </div>
@@ -3329,7 +3317,6 @@
🏷️ تگ‌ها 🏷️ تگ‌ها
</button> </button>
<div class="rb-toolbar-separator"></div> <div class="rb-toolbar-separator"></div>
<!-- ✅ NEW: جستجوی کارت‌ها -->
<div class="rb-search-box"> <div class="rb-search-box">
<span style="opacity: 0.7; font-size: 12px">🔍</span> <span style="opacity: 0.7; font-size: 12px">🔍</span>
<input <input
@@ -3353,13 +3340,12 @@
> >
<div class="rb-toolbar-separator"></div> <div class="rb-toolbar-separator"></div>
<button class="btn" id="rbUndoBtn" title="بازگشت (Ctrl+Z)" disabled> <button class="btn" id="rbUndoBtn" title="بازگشت (Ctrl+Z)" disabled>
↩️ بازگشت ↩️
</button> </button>
<button class="btn" id="rbRedoBtn" title="از نو (Ctrl+Y)" disabled> <button class="btn" id="rbRedoBtn" title="از نو (Ctrl+Y)" disabled>
↪️ از نو ↪️
</button> </button>
</div> </div>
<!-- ✅ NEW: نوار فیلتر تگ‌ها -->
<div class="rb-tag-filter-bar" id="rbTagFilterBar"> <div class="rb-tag-filter-bar" id="rbTagFilterBar">
<span class="rb-tag-filter-label">🏷️ فیلتر تگ:</span> <span class="rb-tag-filter-label">🏷️ فیلتر تگ:</span>
<div <div
@@ -3413,8 +3399,8 @@
</div> </div>
<!-- Footer --> <!-- Footer -->
<div class="modal-footer"> <div class="modal-footer">
<div class="dashboard-footer-stats" id="rbFooterStats"></div>
<button class="btn btn-ghost" data-close-modal>بستن</button> <button class="btn btn-ghost" data-close-modal>بستن</button>
<div class="dashboard-footer-stats" id="rbFooterStats"></div>
</div> </div>
</div> </div>
</div> </div>
@@ -3480,31 +3466,31 @@
> >
<div <div
class="rb-preview-column" class="rb-preview-column"
style="background: #edf2f7; color: #1a202c" style="background: #6b7208; color: #b4cbf9"
> >
📥 بک لاگ 📥 بک لاگ
</div> </div>
<div <div
class="rb-preview-column" class="rb-preview-column"
style="background: #ebf8ff; color: #1a202c" style="background: #393e65; color: #b4cbf9"
> >
📋 برای انجام 📋 برای انجام
</div> </div>
<div <div
class="rb-preview-column" class="rb-preview-column"
style="background: #fef5e7; color: #1a202c" style="background: #453111; color: #b4cbf9"
> >
🔨 در حال انجام 🔨 در حال انجام
</div> </div>
<div <div
class="rb-preview-column" class="rb-preview-column"
style="background: #faf5ff; color: #1a202c" style="background: #542881; color: #b4cbf9"
> >
🔍 برای تست 🔍 برای تست
</div> </div>
<div <div
class="rb-preview-column" class="rb-preview-column"
style="background: #f0fff4; color: #1a202c" style="background: #087224; color: #d8d96d"
> >
✅ انجام شده ✅ انجام شده
</div> </div>
@@ -3721,10 +3707,10 @@
<div class="rb-tag-list" id="rbTagList"></div> <div class="rb-tag-list" id="rbTagList"></div>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button class="btn btn-ghost" data-close-modal>بستن</button>
<div style="font-size: 11px; color: var(--text-muted)"> <div style="font-size: 11px; color: var(--text-muted)">
💡 تغییرات تگ‌ها به صورت خودکار در تمام کارت‌ها اعمال می‌شود 💡 تغییرات تگ‌ها به صورت خودکار در تمام کارت‌ها اعمال می‌شود
</div> </div>
<button class="btn btn-ghost" data-close-modal>بستن</button>
</div> </div>
</div> </div>
</div> </div>
@@ -3790,177 +3776,21 @@
<div class="modal-title">💾 بازیابی خودکار داده‌ها</div> <div class="modal-title">💾 بازیابی خودکار داده‌ها</div>
</div> </div>
<div class="modal-body"> <div class="modal-body">
<div style="text-align: center; padding: 24px 16px">
<div style="font-size: 48px; margin-bottom: 16px">💾</div>
<div <div
style=" style="
background: linear-gradient(to left, #ebf8ff, #e6f6ff);
border: 1px solid #90cdf4;
border-right: 4px solid var(--info);
padding: 14px 18px;
border-radius: 8px;
margin-bottom: 16px;
font-size: 13px;
line-height: 1.8;
"
>
<div
style="
font-weight: 700;
font-size: 14px; font-size: 14px;
margin-bottom: 8px;
color: var(--primary);
"
>
⚠️ داده ذخیره‌شده خودکار یافت شد
</div>
<div style="color: var(--text-muted)">
به نظر می‌رسد در جلسه قبلی، تغییراتی در برنامه اعمال شده و به صورت
خودکار ذخیره شده‌اند.
</div>
<div
style="
margin-top: 10px;
font-size: 12px;
color: var(--text-muted);
"
>
📅 تاریخ ذخیره:
<strong id="rbAutosaveDate" style="color: var(--primary)"
>—</strong
>
</div>
</div>
<div
style="
background: var(--border-light);
border: 1px solid var(--border);
border-radius: 8px;
padding: 12px;
margin-bottom: 16px;
"
>
<div
style="
font-weight: 700; font-weight: 700;
font-size: 13px; color: var(--text);
margin-bottom: 10px; margin-bottom: 8px;
color: var(--primary);
" "
> >
📊 محتویات داده‌های ذخیره‌شده: داده‌هایی در حافظه موقت وجود دارند
</div> </div>
<div <div style="font-size: 12px; color: var(--text-muted)">
style=" آیا مایل به بازیابی آن‌ها هستید؟
display: grid;
grid-template-columns: 1fr 1fr;
gap: 8px;
font-size: 12px;
"
>
<div
style="
display: flex;
justify-content: space-between;
padding: 6px 10px;
background: var(--card-bg);
border-radius: 6px;
"
>
<span>🌍 محیط‌ها:</span
><strong id="rbAutosaveEnvCount" style="color: var(--primary)"
>0</strong
>
</div> </div>
<div
style="
display: flex;
justify-content: space-between;
padding: 6px 10px;
background: var(--card-bg);
border-radius: 6px;
"
>
<span>📦 محصولات:</span
><strong id="rbAutosaveProdCount" style="color: var(--primary)"
>0</strong
>
</div>
<div
style="
display: flex;
justify-content: space-between;
padding: 6px 10px;
background: var(--card-bg);
border-radius: 6px;
"
>
<span>🌿 پروژه‌ها:</span
><strong id="rbAutosaveProjCount" style="color: var(--primary)"
>0</strong
>
</div>
<div
style="
display: flex;
justify-content: space-between;
padding: 6px 10px;
background: var(--card-bg);
border-radius: 6px;
"
>
<span>🚀 استقرارها:</span
><strong id="rbAutosaveDepCount" style="color: var(--primary)"
>0</strong
>
</div>
<div
style="
display: flex;
justify-content: space-between;
padding: 6px 10px;
background: var(--card-bg);
border-radius: 6px;
"
>
<span>📋 بردها:</span
><strong id="rbAutosaveBoardCount" style="color: var(--primary)"
>0</strong
>
</div>
<div
style="
display: flex;
justify-content: space-between;
padding: 6px 10px;
background: var(--card-bg);
border-radius: 6px;
"
>
<span>🏷️ تگ‌های برد:</span
><strong id="rbAutosaveTagCount" style="color: var(--primary)"
>0</strong
>
</div>
</div>
</div>
<div style="font-size: 13px; color: var(--text); line-height: 1.8">
آیا می‌خواهید این داده‌ها را بازیابی کنید؟
<ul
style="
margin-top: 8px;
padding-right: 20px;
color: var(--text-muted);
font-size: 12px;
"
>
<li>
<strong>بازیابی:</strong> تمام داده‌های ذخیره‌شده جایگزین
داده‌های فعلی می‌شوند
</li>
<li>
<strong>نادیده گرفتن:</strong> داده‌های خودکار حذف شده و
داده‌های فعلی حفظ می‌شوند
</li>
</ul>
</div> </div>
</div> </div>
<div class="modal-footer" style="justify-content: space-between"> <div class="modal-footer" style="justify-content: space-between">
@@ -4031,7 +3861,7 @@
projectName: "xReleaseAssistant", projectName: "xReleaseAssistant",
projectTitle: "دستیار انتشار", projectTitle: "دستیار انتشار",
description: "مدیریت نسخه‌ها و نیازمندی‌های محصولات", description: "مدیریت نسخه‌ها و نیازمندی‌های محصولات",
version: "1.2.0", version: "1.1.0",
developer: "هادی خزاعی اصل", developer: "هادی خزاعی اصل",
company: "رایان پرداز کاوش", company: "رایان پرداز کاوش",
metadata: { metadata: {
@@ -4091,7 +3921,6 @@
action: "showReleaseBoards", action: "showReleaseBoards",
description: "مشاهده و مدیریت بردهای انتشار", description: "مشاهده و مدیریت بردهای انتشار",
}, },
/* ✅ NEW: ابزار مدیریت تگ‌ها */
{ {
id: "tag-manager", id: "tag-manager",
title: "مدیریت تگ‌ها", title: "مدیریت تگ‌ها",
@@ -4153,50 +3982,7 @@
}, },
], ],
appData: { appData: {
environments: [ environments: [],
{
id: "env-prod-001",
name: "Production",
description: "محیط عملیاتی اصلی - در دسترس کاربران نهایی",
backgroundColor: "#38a169",
textColor: "#ffffff",
},
{
id: "env-stage-002",
name: "Staging",
description: "محیط پیش از تولید - شبیه‌سازی Production",
backgroundColor: "#dd6b20",
textColor: "#ffffff",
},
{
id: "env-dev-003",
name: "Development",
description: "محیط توسعه - برای تیم فنی",
backgroundColor: "#3182ce",
textColor: "#ffffff",
},
{
id: "env-qa-004",
name: "QA",
description: "محیط تست کیفیت - کنترل کیفیت خودکار و دستی",
backgroundColor: "#805ad5",
textColor: "#ffffff",
},
{
id: "env-uat-005",
name: "UAT",
description: "تست پذیرش کاربر - تأیید کارفرما",
backgroundColor: "#d69e2e",
textColor: "#ffffff",
},
{
id: "env-dr-006",
name: "Disaster Recovery",
description: "محیط بازیابی پس از بحران - پشتیبان Production",
backgroundColor: "#e53e3e",
textColor: "#ffffff",
},
],
products: [], products: [],
boards: [], boards: [],
boardTags: [], boardTags: [],
@@ -4546,7 +4332,7 @@
getSectionHTML() { getSectionHTML() {
const d = this.getData(); const d = this.getData();
let h = `<div class="board-section" id="section-dashboard">`; let h = `<div class="board-section" id="section-dashboard">`;
h += `<div class="board-header"><div class="board-header-title"><span class="collapse-icon">▼</span>📊 داشبورد مدیریتی</div><div class="board-header-actions"><button class="btn btn-accent btn-sm" onclick="DashboardManager.open()">📊 مشاهده کامل</button></div></div>`; h += `<div class="board-header"><div class="board-header-title"><span class="collapse-icon">▼</span>📊 داشبورد مدیریتی</div><div class="board-header-actions"><button class="btn btn-accent" onclick="DashboardManager.open()">📊 مشاهده کامل</button></div></div>`;
h += `<div class="section-content">`; h += `<div class="section-content">`;
h += '<div class="dashboard-kpi-row" style="margin-bottom:16px">'; h += '<div class="dashboard-kpi-row" style="margin-bottom:16px">';
h += `<div class="dashboard-kpi-card"><div class="dashboard-kpi-icon">📦</div><div class="dashboard-kpi-value">${d.products}</div><div class="dashboard-kpi-label">محصول</div></div>`; h += `<div class="dashboard-kpi-card"><div class="dashboard-kpi-icon">📦</div><div class="dashboard-kpi-value">${d.products}</div><div class="dashboard-kpi-label">محصول</div></div>`;
@@ -4972,7 +4758,6 @@
showReleaseBoards() { showReleaseBoards() {
ReleaseBoardsManager.open(); ReleaseBoardsManager.open();
}, },
/* ✅ NEW: اکشن مدیریت تگ‌ها */
showTagManager() { showTagManager() {
ReleaseBoardsManager.openTagManager(); ReleaseBoardsManager.openTagManager();
}, },
@@ -5969,8 +5754,6 @@
: 0; : 0;
document.getElementById("dashboardFooterStats").innerHTML = document.getElementById("dashboardFooterStats").innerHTML =
`<span>📦 محصولات: <span class="stat-highlight">${d.products}</span></span><span>🌿 پروژه‌ها: <span class="stat-highlight">${d.projects}</span></span><span>🚀 استقرارها: <span class="stat-highlight">${d.deploys}</span></span><span>📈 پوشش استقرار: <span class="stat-highlight">${coverage}%</span></span>`; `<span>📦 محصولات: <span class="stat-highlight">${d.products}</span></span><span>🌿 پروژه‌ها: <span class="stat-highlight">${d.projects}</span></span><span>🚀 استقرارها: <span class="stat-highlight">${d.deploys}</span></span><span>📈 پوشش استقرار: <span class="stat-highlight">${coverage}%</span></span>`;
document.getElementById("dashboardRefresh").onclick = () =>
this.render();
}, },
renderDonut(cid, data) { renderDonut(cid, data) {
const c = document.getElementById(cid); const c = document.getElementById(cid);
@@ -6724,53 +6507,12 @@
checkRecovery() { checkRecovery() {
const saved = this.load(); const saved = this.load();
if (!saved || !saved.appData) return; if (!saved || !saved.appData) return;
const appData = saved.appData;
const stats = {
environments: (appData.environments || []).length,
products: (appData.products || []).length,
projects: 0,
deployments: 0,
boards: (appData.boards || []).length,
boardTags: (appData.boardTags || []).length,
};
(appData.products || []).forEach((prod) => {
stats.projects += (prod.projects || []).length;
(prod.projects || []).forEach((pr) => {
stats.deployments += (pr.deployments || []).filter(
(d) => d.status === "active",
).length;
});
});
const dateEl = document.getElementById("rbAutosaveDate");
const envCountEl = document.getElementById("rbAutosaveEnvCount");
const prodCountEl = document.getElementById("rbAutosaveProdCount");
const projCountEl = document.getElementById("rbAutosaveProjCount");
const depCountEl = document.getElementById("rbAutosaveDepCount");
const boardCountEl = document.getElementById("rbAutosaveBoardCount");
if (dateEl) {
const d = new Date(saved.savedAt);
dateEl.textContent =
d.toLocaleDateString("fa-IR") +
" - " +
d.toLocaleTimeString("fa-IR", {
hour: "2-digit",
minute: "2-digit",
});
}
if (envCountEl)
envCountEl.textContent = stats.environments.toLocaleString("fa-IR");
if (prodCountEl)
prodCountEl.textContent = stats.products.toLocaleString("fa-IR");
if (projCountEl)
projCountEl.textContent = stats.projects.toLocaleString("fa-IR");
if (depCountEl)
depCountEl.textContent = stats.deployments.toLocaleString("fa-IR");
if (boardCountEl)
boardCountEl.textContent = stats.boards.toLocaleString("fa-IR");
document.getElementById("rbRecoverAutosaveBtn").onclick = () => document.getElementById("rbRecoverAutosaveBtn").onclick = () =>
this.recover(); this.recover();
document.getElementById("rbDiscardAutosaveBtn").onclick = () => document.getElementById("rbDiscardAutosaveBtn").onclick = () =>
this.discard(); this.discard();
setTimeout(() => { setTimeout(() => {
ModalManager.open("rbAutosaveModal"); ModalManager.open("rbAutosaveModal");
}, 600); }, 600);
@@ -6825,28 +6567,28 @@
DEFAULT_COLUMNS: [ DEFAULT_COLUMNS: [
{ {
title: "📥 بک لاگ", title: "📥 بک لاگ",
backgroundColor: "#edf2f7", backgroundColor: "#6b7208",
textColor: "#1a202c", textColor: "#b4cbf9",
}, },
{ {
title: "📋 برای انجام", title: "📋 برای انجام",
backgroundColor: "#ebf8ff", backgroundColor: "#393e65",
textColor: "#1a202c", textColor: "#b4cbf9",
}, },
{ {
title: "🔨 در حال انجام", title: "🔨 در حال انجام",
backgroundColor: "#fef5e7", backgroundColor: "#453111",
textColor: "#1a202c", textColor: "#b4cbf9",
}, },
{ {
title: "🔍 برای تست", title: "🔍 برای تست",
backgroundColor: "#faf5ff", backgroundColor: "#542881",
textColor: "#1a202c", textColor: "#b4cbf9",
}, },
{ {
title: "✅ انجام شده", title: "✅ انجام شده",
backgroundColor: "#f0fff4", backgroundColor: "#087224",
textColor: "#1a202c", textColor: "#d8d96d",
}, },
], ],
open() { open() {
@@ -6897,7 +6639,6 @@
} else { } else {
this._incrementalRender(board); this._incrementalRender(board);
} }
/* ✅ NEW: اعمال فیلترها و اتصال درگ پس از رندر */
this.applyFilters(); this.applyFilters();
this.initDragAndDrop(); this.initDragAndDrop();
this.updateFooterStats(); this.updateFooterStats();
@@ -7098,9 +6839,6 @@ ${checklistTotal > 0 ? `<span class="card-meta-item">✅ ${checklistDone}/${chec
${checklistHtml} ${checklistHtml}
</div>`; </div>`;
}, },
/* ═══════════════════════════════════════════════════
✅ NEW: فیلتر تگ‌ها
═══════════════════════════════════════════════════ */
renderFilterBar() { renderFilterBar() {
const container = document.getElementById("rbTagFilterContainer"); const container = document.getElementById("rbTagFilterContainer");
const clearBtn = document.getElementById("rbClearTagFilter"); const clearBtn = document.getElementById("rbClearTagFilter");
@@ -7138,9 +6876,6 @@ ${checklistHtml}
}; };
} }
}, },
/* ═══════════════════════════════════════════════════
✅ NEW: اعمال فیلتر و جستجو
═══════════════════════════════════════════════════ */
applyFilters() { applyFilters() {
const board = this.getActiveBoard(); const board = this.getActiveBoard();
if (!board) return; if (!board) return;
@@ -7224,9 +6959,6 @@ ${checklistHtml}
} }
} }
}, },
/* ═══════════════════════════════════════════════════
✅ NEW: رویدادهای جستجو
═══════════════════════════════════════════════════ */
bindSearchEvents() { bindSearchEvents() {
const inp = document.getElementById("rbCardSearchInput"); const inp = document.getElementById("rbCardSearchInput");
const clr = document.getElementById("rbCardSearchClear"); const clr = document.getElementById("rbCardSearchClear");
@@ -7253,9 +6985,6 @@ ${checklistHtml}
inp.focus(); inp.focus();
}; };
}, },
/* ═══════════════════════════════════════════════════
✅ NEW: Drag & Drop
═══════════════════════════════════════════════════ */
initDragAndDrop() { initDragAndDrop() {
const wrapper = document.getElementById("rbBoardWrapper"); const wrapper = document.getElementById("rbBoardWrapper");
if (!wrapper) return; if (!wrapper) return;
@@ -7350,7 +7079,6 @@ ${checklistHtml}
.querySelectorAll(".drag-over-column") .querySelectorAll(".drag-over-column")
.forEach((el) => el.classList.remove("drag-over-column")); .forEach((el) => el.classList.remove("drag-over-column"));
}, },
/* ── جابجایی کارت بین ستون‌ها ── */
moveCard(cardId, targetColumnId) { moveCard(cardId, targetColumnId) {
const board = this.getActiveBoard(); const board = this.getActiveBoard();
if (!board) return; if (!board) return;
@@ -7387,7 +7115,6 @@ ${checklistHtml}
2000, 2000,
); );
}, },
/* ── جابجایی ستون‌ها ── */
moveColumn(sourceColId, targetColId) { moveColumn(sourceColId, targetColId) {
const board = this.getActiveBoard(); const board = this.getActiveBoard();
if (!board) return; if (!board) return;
@@ -7406,7 +7133,6 @@ ${checklistHtml}
this.render(true); this.render(true);
showToast("📊 ستون جابجا شد", "success", 2000); showToast("📊 ستون جابجا شد", "success", 2000);
}, },
/* ── مدیریت برد ── */
getActiveBoard() { getActiveBoard() {
return (projectData.appData.boards || []).find( return (projectData.appData.boards || []).find(
(b) => b.id === this.activeBoardId, (b) => b.id === this.activeBoardId,
@@ -7525,7 +7251,6 @@ ${checklistHtml}
showToast("برد حذف شد", "warning"); showToast("برد حذف شد", "warning");
this.render(true); this.render(true);
}, },
/* ── مدیریت ستون ── */
openNewColumnModal() { openNewColumnModal() {
if (!this.getActiveBoard()) { if (!this.getActiveBoard()) {
showToast("ابتدا یک برد ایجاد کنید", "warning"); showToast("ابتدا یک برد ایجاد کنید", "warning");
@@ -7600,7 +7325,6 @@ ${checklistHtml}
showToast("ستون حذف شد", "warning"); showToast("ستون حذف شد", "warning");
this.render(true); this.render(true);
}, },
/* ── مدیریت کارت ── */
openNewCardModal(columnId) { openNewCardModal(columnId) {
this.editing.cardId = null; this.editing.cardId = null;
this.editing.columnForCard = columnId; this.editing.columnForCard = columnId;
@@ -7818,7 +7542,6 @@ ${checklistHtml}
document.getElementById("rbDeleteCardBtn").onclick = () => document.getElementById("rbDeleteCardBtn").onclick = () =>
this.deleteCard(); this.deleteCard();
}, },
/* ── Toolbar Events ── */
bindToolbarEvents() { bindToolbarEvents() {
document.getElementById("rbEditBoard").onclick = () => document.getElementById("rbEditBoard").onclick = () =>
this.openEditBoardModal(); this.openEditBoardModal();
@@ -7852,7 +7575,6 @@ ${checklistHtml}
document.getElementById("rbFooterStats").innerHTML = document.getElementById("rbFooterStats").innerHTML =
`<span>📋 بردها: <span class="stat-highlight">${boards.length}</span></span><span>📑 ستون‌ها: <span class="stat-highlight">${boards.reduce((s, b) => s + b.columns.length, 0)}</span></span><span>📝 کارت‌ها: <span class="stat-highlight">${totalCards}</span></span>`; `<span>📋 بردها: <span class="stat-highlight">${boards.length}</span></span><span>📑 ستون‌ها: <span class="stat-highlight">${boards.reduce((s, b) => s + b.columns.length, 0)}</span></span><span>📝 کارت‌ها: <span class="stat-highlight">${totalCards}</span></span>`;
}, },
/* ── Tag Manager ── */
openTagManager() { openTagManager() {
ModalManager.open("rbTagManagerModal"); ModalManager.open("rbTagManagerModal");
this.renderTagList(); this.renderTagList();
@@ -8089,8 +7811,6 @@ ${checklistHtml}
this.renderRiskList("depRiskList", d); this.renderRiskList("depRiskList", d);
document.getElementById("depAnalysisFooterStats").innerHTML = document.getElementById("depAnalysisFooterStats").innerHTML =
`<span>🔗 کل: <span class="stat-highlight">${d.totalDeps}</span></span><span>⚠️ گلوگاه: <span class="stat-highlight">${d.bottlenecks.length}</span></span><span>🔴 شکسته: <span class="stat-highlight">${d.brokenDeps}</span></span><span>🔵 ایزوله: <span class="stat-highlight">${d.isolated.length}</span></span>`; `<span>🔗 کل: <span class="stat-highlight">${d.totalDeps}</span></span><span>⚠️ گلوگاه: <span class="stat-highlight">${d.bottlenecks.length}</span></span><span>🔴 شکسته: <span class="stat-highlight">${d.brokenDeps}</span></span><span>🔵 ایزوله: <span class="stat-highlight">${d.isolated.length}</span></span>`;
document.getElementById("depAnalysisRefresh").onclick = () =>
this.render();
}, },
renderHubChart(cid, bottlenecks) { renderHubChart(cid, bottlenecks) {
const c = document.getElementById(cid); const c = document.getElementById(cid);
@@ -8463,8 +8183,6 @@ ${checklistHtml}
this.renderRiskList("deployRiskList", d.riskList); this.renderRiskList("deployRiskList", d.riskList);
document.getElementById("deployAnalysisFooterStats").innerHTML = document.getElementById("deployAnalysisFooterStats").innerHTML =
`<span>🚀 کل: <span class="stat-highlight">${d.total}</span></span><span>📈 پوشش: <span class="stat-highlight">${d.coverage}%</span></span><span>⚠️ ریسک‌ها: <span class="stat-highlight">${d.riskList.length}</span></span>`; `<span>🚀 کل: <span class="stat-highlight">${d.total}</span></span><span>📈 پوشش: <span class="stat-highlight">${d.coverage}%</span></span><span>⚠️ ریسک‌ها: <span class="stat-highlight">${d.riskList.length}</span></span>`;
document.getElementById("deployAnalysisRefresh").onclick = () =>
this.render();
}, },
renderEnvBarChart(cid, edc) { renderEnvBarChart(cid, edc) {
const c = document.getElementById(cid); const c = document.getElementById(cid);
@@ -8888,8 +8606,6 @@ ${checklistHtml}
this.renderRiskList("verRiskList", d.riskList); this.renderRiskList("verRiskList", d.riskList);
document.getElementById("verAnalysisFooterStats").innerHTML = document.getElementById("verAnalysisFooterStats").innerHTML =
`<span>🔢 کل: <span class="stat-highlight">${d.total}</span></span><span>📦 یکتا: <span class="stat-highlight">${d.uniqueVersions}</span></span><span>📈 میانگین: <span class="stat-highlight">${d.avgVersion}</span></span><span>⚠️ ریسک‌ها: <span class="stat-highlight">${d.riskList.length}</span></span>`; `<span>🔢 کل: <span class="stat-highlight">${d.total}</span></span><span>📦 یکتا: <span class="stat-highlight">${d.uniqueVersions}</span></span><span>📈 میانگین: <span class="stat-highlight">${d.avgVersion}</span></span><span>⚠️ ریسک‌ها: <span class="stat-highlight">${d.riskList.length}</span></span>`;
document.getElementById("verAnalysisRefresh").onclick = () =>
this.render();
}, },
renderMajorBarChart(cid, majorCounts) { renderMajorBarChart(cid, majorCounts) {
const c = document.getElementById(cid); const c = document.getElementById(cid);
@@ -9274,8 +8990,6 @@ ${checklistHtml}
this.renderRiskList("riskDetailList", d.risks); this.renderRiskList("riskDetailList", d.risks);
document.getElementById("riskAnalysisFooterStats").innerHTML = document.getElementById("riskAnalysisFooterStats").innerHTML =
`<span>🎯 سلامت: <span class="stat-highlight">${d.healthScore}%</span></span><span>⚠️ ریسک‌ها: <span class="stat-highlight">${d.total}</span></span><span>🔴 بحرانی: <span class="stat-highlight">${d.crit}</span></span><span>🟠 بالا: <span class="stat-highlight">${d.high}</span></span>`; `<span>🎯 سلامت: <span class="stat-highlight">${d.healthScore}%</span></span><span>⚠️ ریسک‌ها: <span class="stat-highlight">${d.total}</span></span><span>🔴 بحرانی: <span class="stat-highlight">${d.crit}</span></span><span>🟠 بالا: <span class="stat-highlight">${d.high}</span></span>`;
document.getElementById("riskAnalysisRefresh").onclick = () =>
this.render();
}, },
renderSeverityDonut(cid, d) { renderSeverityDonut(cid, d) {
const c = document.getElementById(cid); const c = document.getElementById(cid);