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 @@
آخرین نسخه تایید شده
- در گروه بردها از ابزارها یک گزینه بنام "مدیریت تگ ها" اضافه کن و در صورت انتخاب کاربر مودال مدیریت تگ ها را نمایش بده.
- قابلیت فیلتر کارت‌ها بر اساس تگ در مودال بردها اضافه شود.
- قابلیت Drag & Drop ستونها و کارت‌ها بین ستون‌ها پیاده‌سازی شود.
- قابلیت جستجوی کارت‌ها در برد فعال اضافه شود.
- در بردهای انتشار برای هر کارت باید قابلیت های زیر وجود داشته باشد:
1. تاریخچه عملیات انجام شده روی کارت
2. نام افرادمسئول که وظیفه به آن ها محول یا مربوط می شود باید دریافت شود
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);
margin: 0 4px;
}
/* ✅ NEW: استایل جستجو و فیلتر در نوار ابزار بردها */
.rb-search-box {
position: relative;
display: flex;
@@ -1787,7 +1786,6 @@
align-items: center;
gap: 4px;
}
/* ✅ NEW: نوار فیلتر تگ‌ها */
.rb-tag-filter-bar {
display: flex;
align-items: center;
@@ -2428,9 +2426,6 @@
color: var(--text-muted);
font-size: 12px;
}
/* ═══════════════════════════════════════════════════
✅ NEW: استایل‌های Drag & Drop و فیلتر
═══════════════════════════════════════════════════ */
.card.hidden-by-filter {
display: none !important;
}
@@ -2815,7 +2810,7 @@
</div>
<div class="modal-body" id="projectDetailBody"></div>
<div class="modal-footer">
<button class="btn btn-danger btn-sm" id="projectDetailDeleteBtn">
<button class="btn btn-danger" id="projectDetailDeleteBtn">
🗑️ حذف محصول</button
><button class="btn btn-ghost" data-close-modal>بستن</button>
</div>
@@ -3205,9 +3200,6 @@
<div class="modal-header">
<div class="modal-title">📊 داشبورد مدیریتی</div>
<div class="galaxy-toolbar">
<button class="btn btn-sm" id="dashboardRefresh">
🔄 به‌روزرسانی
</button>
</div>
<button class="modal-close" data-close-modal>✕</button>
</div>
@@ -3227,7 +3219,6 @@
<div class="modal-header">
<div class="modal-title">🔗 تحلیل وابستگی‌ها</div>
<div class="galaxy-toolbar">
<button class="btn btn-sm" id="depAnalysisRefresh">🔄</button>
</div>
<button class="modal-close" data-close-modal>✕</button>
</div>
@@ -3250,7 +3241,6 @@
<div class="modal-header">
<div class="modal-title">🚀 تحلیل استقرار</div>
<div class="galaxy-toolbar">
<button class="btn btn-sm" id="deployAnalysisRefresh">🔄</button>
</div>
<button class="modal-close" data-close-modal>✕</button>
</div>
@@ -3276,7 +3266,6 @@
<div class="modal-header">
<div class="modal-title">🔢 تحلیل نسخه</div>
<div class="galaxy-toolbar">
<button class="btn btn-sm" id="verAnalysisRefresh">🔄</button>
</div>
<button class="modal-close" data-close-modal>✕</button>
</div>
@@ -3296,7 +3285,6 @@
<div class="modal-header">
<div class="modal-title">⚠️ تحلیل ریسک</div>
<div class="galaxy-toolbar">
<button class="btn btn-sm" id="riskAnalysisRefresh">🔄</button>
</div>
<button class="modal-close" data-close-modal>✕</button>
</div>
@@ -3329,7 +3317,6 @@
🏷️ تگ‌ها
</button>
<div class="rb-toolbar-separator"></div>
<!-- ✅ NEW: جستجوی کارت‌ها -->
<div class="rb-search-box">
<span style="opacity: 0.7; font-size: 12px">🔍</span>
<input
@@ -3353,13 +3340,12 @@
>
<div class="rb-toolbar-separator"></div>
<button class="btn" id="rbUndoBtn" title="بازگشت (Ctrl+Z)" disabled>
↩️ بازگشت
↩️
</button>
<button class="btn" id="rbRedoBtn" title="از نو (Ctrl+Y)" disabled>
↪️ از نو
↪️
</button>
</div>
<!-- ✅ NEW: نوار فیلتر تگ‌ها -->
<div class="rb-tag-filter-bar" id="rbTagFilterBar">
<span class="rb-tag-filter-label">🏷️ فیلتر تگ:</span>
<div
@@ -3413,8 +3399,8 @@
</div>
<!-- Footer -->
<div class="modal-footer">
<div class="dashboard-footer-stats" id="rbFooterStats"></div>
<button class="btn btn-ghost" data-close-modal>بستن</button>
<div class="dashboard-footer-stats" id="rbFooterStats"></div>
</div>
</div>
</div>
@@ -3480,31 +3466,31 @@
>
<div
class="rb-preview-column"
style="background: #edf2f7; color: #1a202c"
style="background: #6b7208; color: #b4cbf9"
>
📥 بک لاگ
</div>
<div
class="rb-preview-column"
style="background: #ebf8ff; color: #1a202c"
style="background: #393e65; color: #b4cbf9"
>
📋 برای انجام
</div>
<div
class="rb-preview-column"
style="background: #fef5e7; color: #1a202c"
style="background: #453111; color: #b4cbf9"
>
🔨 در حال انجام
</div>
<div
class="rb-preview-column"
style="background: #faf5ff; color: #1a202c"
style="background: #542881; color: #b4cbf9"
>
🔍 برای تست
</div>
<div
class="rb-preview-column"
style="background: #f0fff4; color: #1a202c"
style="background: #087224; color: #d8d96d"
>
✅ انجام شده
</div>
@@ -3721,10 +3707,10 @@
<div class="rb-tag-list" id="rbTagList"></div>
</div>
<div class="modal-footer">
<button class="btn btn-ghost" data-close-modal>بستن</button>
<div style="font-size: 11px; color: var(--text-muted)">
💡 تغییرات تگ‌ها به صورت خودکار در تمام کارت‌ها اعمال می‌شود
</div>
<button class="btn btn-ghost" data-close-modal>بستن</button>
</div>
</div>
</div>
@@ -3790,177 +3776,21 @@
<div class="modal-title">💾 بازیابی خودکار داده‌ها</div>
</div>
<div class="modal-body">
<div style="text-align: center; padding: 24px 16px">
<div style="font-size: 48px; margin-bottom: 16px">💾</div>
<div
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;
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-size: 13px;
margin-bottom: 10px;
color: var(--primary);
color: var(--text);
margin-bottom: 8px;
"
>
📊 محتویات داده‌های ذخیره‌شده:
داده‌هایی در حافظه موقت وجود دارند
</div>
<div
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 style="font-size: 12px; color: var(--text-muted)">
آیا مایل به بازیابی آن‌ها هستید؟
</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 class="modal-footer" style="justify-content: space-between">
@@ -4031,7 +3861,7 @@
projectName: "xReleaseAssistant",
projectTitle: "دستیار انتشار",
description: "مدیریت نسخه‌ها و نیازمندی‌های محصولات",
version: "1.2.0",
version: "1.1.0",
developer: "هادی خزاعی اصل",
company: "رایان پرداز کاوش",
metadata: {
@@ -4091,7 +3921,6 @@
action: "showReleaseBoards",
description: "مشاهده و مدیریت بردهای انتشار",
},
/* ✅ NEW: ابزار مدیریت تگ‌ها */
{
id: "tag-manager",
title: "مدیریت تگ‌ها",
@@ -4153,50 +3982,7 @@
},
],
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",
},
],
environments: [],
products: [],
boards: [],
boardTags: [],
@@ -4546,7 +4332,7 @@
getSectionHTML() {
const d = this.getData();
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="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>`;
@@ -4972,7 +4758,6 @@
showReleaseBoards() {
ReleaseBoardsManager.open();
},
/* ✅ NEW: اکشن مدیریت تگ‌ها */
showTagManager() {
ReleaseBoardsManager.openTagManager();
},
@@ -5969,8 +5754,6 @@
: 0;
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>`;
document.getElementById("dashboardRefresh").onclick = () =>
this.render();
},
renderDonut(cid, data) {
const c = document.getElementById(cid);
@@ -6724,53 +6507,12 @@
checkRecovery() {
const saved = this.load();
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 = () =>
this.recover();
document.getElementById("rbDiscardAutosaveBtn").onclick = () =>
this.discard();
setTimeout(() => {
ModalManager.open("rbAutosaveModal");
}, 600);
@@ -6825,28 +6567,28 @@
DEFAULT_COLUMNS: [
{
title: "📥 بک لاگ",
backgroundColor: "#edf2f7",
textColor: "#1a202c",
backgroundColor: "#6b7208",
textColor: "#b4cbf9",
},
{
title: "📋 برای انجام",
backgroundColor: "#ebf8ff",
textColor: "#1a202c",
backgroundColor: "#393e65",
textColor: "#b4cbf9",
},
{
title: "🔨 در حال انجام",
backgroundColor: "#fef5e7",
textColor: "#1a202c",
backgroundColor: "#453111",
textColor: "#b4cbf9",
},
{
title: "🔍 برای تست",
backgroundColor: "#faf5ff",
textColor: "#1a202c",
backgroundColor: "#542881",
textColor: "#b4cbf9",
},
{
title: "✅ انجام شده",
backgroundColor: "#f0fff4",
textColor: "#1a202c",
backgroundColor: "#087224",
textColor: "#d8d96d",
},
],
open() {
@@ -6897,7 +6639,6 @@
} else {
this._incrementalRender(board);
}
/* ✅ NEW: اعمال فیلترها و اتصال درگ پس از رندر */
this.applyFilters();
this.initDragAndDrop();
this.updateFooterStats();
@@ -7098,9 +6839,6 @@ ${checklistTotal > 0 ? `<span class="card-meta-item">✅ ${checklistDone}/${chec
${checklistHtml}
</div>`;
},
/* ═══════════════════════════════════════════════════
✅ NEW: فیلتر تگ‌ها
═══════════════════════════════════════════════════ */
renderFilterBar() {
const container = document.getElementById("rbTagFilterContainer");
const clearBtn = document.getElementById("rbClearTagFilter");
@@ -7138,9 +6876,6 @@ ${checklistHtml}
};
}
},
/* ═══════════════════════════════════════════════════
✅ NEW: اعمال فیلتر و جستجو
═══════════════════════════════════════════════════ */
applyFilters() {
const board = this.getActiveBoard();
if (!board) return;
@@ -7224,9 +6959,6 @@ ${checklistHtml}
}
}
},
/* ═══════════════════════════════════════════════════
✅ NEW: رویدادهای جستجو
═══════════════════════════════════════════════════ */
bindSearchEvents() {
const inp = document.getElementById("rbCardSearchInput");
const clr = document.getElementById("rbCardSearchClear");
@@ -7253,9 +6985,6 @@ ${checklistHtml}
inp.focus();
};
},
/* ═══════════════════════════════════════════════════
✅ NEW: Drag & Drop
═══════════════════════════════════════════════════ */
initDragAndDrop() {
const wrapper = document.getElementById("rbBoardWrapper");
if (!wrapper) return;
@@ -7350,7 +7079,6 @@ ${checklistHtml}
.querySelectorAll(".drag-over-column")
.forEach((el) => el.classList.remove("drag-over-column"));
},
/* ── جابجایی کارت بین ستون‌ها ── */
moveCard(cardId, targetColumnId) {
const board = this.getActiveBoard();
if (!board) return;
@@ -7387,7 +7115,6 @@ ${checklistHtml}
2000,
);
},
/* ── جابجایی ستون‌ها ── */
moveColumn(sourceColId, targetColId) {
const board = this.getActiveBoard();
if (!board) return;
@@ -7406,7 +7133,6 @@ ${checklistHtml}
this.render(true);
showToast("📊 ستون جابجا شد", "success", 2000);
},
/* ── مدیریت برد ── */
getActiveBoard() {
return (projectData.appData.boards || []).find(
(b) => b.id === this.activeBoardId,
@@ -7525,7 +7251,6 @@ ${checklistHtml}
showToast("برد حذف شد", "warning");
this.render(true);
},
/* ── مدیریت ستون ── */
openNewColumnModal() {
if (!this.getActiveBoard()) {
showToast("ابتدا یک برد ایجاد کنید", "warning");
@@ -7600,7 +7325,6 @@ ${checklistHtml}
showToast("ستون حذف شد", "warning");
this.render(true);
},
/* ── مدیریت کارت ── */
openNewCardModal(columnId) {
this.editing.cardId = null;
this.editing.columnForCard = columnId;
@@ -7818,7 +7542,6 @@ ${checklistHtml}
document.getElementById("rbDeleteCardBtn").onclick = () =>
this.deleteCard();
},
/* ── Toolbar Events ── */
bindToolbarEvents() {
document.getElementById("rbEditBoard").onclick = () =>
this.openEditBoardModal();
@@ -7852,7 +7575,6 @@ ${checklistHtml}
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>`;
},
/* ── Tag Manager ── */
openTagManager() {
ModalManager.open("rbTagManagerModal");
this.renderTagList();
@@ -8089,8 +7811,6 @@ ${checklistHtml}
this.renderRiskList("depRiskList", d);
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>`;
document.getElementById("depAnalysisRefresh").onclick = () =>
this.render();
},
renderHubChart(cid, bottlenecks) {
const c = document.getElementById(cid);
@@ -8463,8 +8183,6 @@ ${checklistHtml}
this.renderRiskList("deployRiskList", d.riskList);
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>`;
document.getElementById("deployAnalysisRefresh").onclick = () =>
this.render();
},
renderEnvBarChart(cid, edc) {
const c = document.getElementById(cid);
@@ -8888,8 +8606,6 @@ ${checklistHtml}
this.renderRiskList("verRiskList", d.riskList);
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>`;
document.getElementById("verAnalysisRefresh").onclick = () =>
this.render();
},
renderMajorBarChart(cid, majorCounts) {
const c = document.getElementById(cid);
@@ -9274,8 +8990,6 @@ ${checklistHtml}
this.renderRiskList("riskDetailList", d.risks);
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>`;
document.getElementById("riskAnalysisRefresh").onclick = () =>
this.render();
},
renderSeverityDonut(cid, d) {
const c = document.getElementById(cid);
+32 -318
View File
@@ -1730,7 +1730,6 @@
background: rgba(255, 255, 255, 0.2);
margin: 0 4px;
}
/* ✅ NEW: استایل جستجو و فیلتر در نوار ابزار بردها */
.rb-search-box {
position: relative;
display: flex;
@@ -1787,7 +1786,6 @@
align-items: center;
gap: 4px;
}
/* ✅ NEW: نوار فیلتر تگ‌ها */
.rb-tag-filter-bar {
display: flex;
align-items: center;
@@ -2428,9 +2426,6 @@
color: var(--text-muted);
font-size: 12px;
}
/* ═══════════════════════════════════════════════════
✅ NEW: استایل‌های Drag & Drop و فیلتر
═══════════════════════════════════════════════════ */
.card.hidden-by-filter {
display: none !important;
}
@@ -2815,7 +2810,7 @@
</div>
<div class="modal-body" id="projectDetailBody"></div>
<div class="modal-footer">
<button class="btn btn-danger btn-sm" id="projectDetailDeleteBtn">
<button class="btn btn-danger" id="projectDetailDeleteBtn">
🗑️ حذف محصول</button
><button class="btn btn-ghost" data-close-modal>بستن</button>
</div>
@@ -3205,9 +3200,6 @@
<div class="modal-header">
<div class="modal-title">📊 داشبورد مدیریتی</div>
<div class="galaxy-toolbar">
<button class="btn btn-sm" id="dashboardRefresh">
🔄 به‌روزرسانی
</button>
</div>
<button class="modal-close" data-close-modal>✕</button>
</div>
@@ -3227,7 +3219,6 @@
<div class="modal-header">
<div class="modal-title">🔗 تحلیل وابستگی‌ها</div>
<div class="galaxy-toolbar">
<button class="btn btn-sm" id="depAnalysisRefresh">🔄</button>
</div>
<button class="modal-close" data-close-modal>✕</button>
</div>
@@ -3250,7 +3241,6 @@
<div class="modal-header">
<div class="modal-title">🚀 تحلیل استقرار</div>
<div class="galaxy-toolbar">
<button class="btn btn-sm" id="deployAnalysisRefresh">🔄</button>
</div>
<button class="modal-close" data-close-modal>✕</button>
</div>
@@ -3276,7 +3266,6 @@
<div class="modal-header">
<div class="modal-title">🔢 تحلیل نسخه</div>
<div class="galaxy-toolbar">
<button class="btn btn-sm" id="verAnalysisRefresh">🔄</button>
</div>
<button class="modal-close" data-close-modal>✕</button>
</div>
@@ -3296,7 +3285,6 @@
<div class="modal-header">
<div class="modal-title">⚠️ تحلیل ریسک</div>
<div class="galaxy-toolbar">
<button class="btn btn-sm" id="riskAnalysisRefresh">🔄</button>
</div>
<button class="modal-close" data-close-modal>✕</button>
</div>
@@ -3329,7 +3317,6 @@
🏷️ تگ‌ها
</button>
<div class="rb-toolbar-separator"></div>
<!-- ✅ NEW: جستجوی کارت‌ها -->
<div class="rb-search-box">
<span style="opacity: 0.7; font-size: 12px">🔍</span>
<input
@@ -3353,13 +3340,12 @@
>
<div class="rb-toolbar-separator"></div>
<button class="btn" id="rbUndoBtn" title="بازگشت (Ctrl+Z)" disabled>
↩️ بازگشت
↩️
</button>
<button class="btn" id="rbRedoBtn" title="از نو (Ctrl+Y)" disabled>
↪️ از نو
↪️
</button>
</div>
<!-- ✅ NEW: نوار فیلتر تگ‌ها -->
<div class="rb-tag-filter-bar" id="rbTagFilterBar">
<span class="rb-tag-filter-label">🏷️ فیلتر تگ:</span>
<div
@@ -3413,8 +3399,8 @@
</div>
<!-- Footer -->
<div class="modal-footer">
<div class="dashboard-footer-stats" id="rbFooterStats"></div>
<button class="btn btn-ghost" data-close-modal>بستن</button>
<div class="dashboard-footer-stats" id="rbFooterStats"></div>
</div>
</div>
</div>
@@ -3480,31 +3466,31 @@
>
<div
class="rb-preview-column"
style="background: #edf2f7; color: #1a202c"
style="background: #6b7208; color: #b4cbf9"
>
📥 بک لاگ
</div>
<div
class="rb-preview-column"
style="background: #ebf8ff; color: #1a202c"
style="background: #393e65; color: #b4cbf9"
>
📋 برای انجام
</div>
<div
class="rb-preview-column"
style="background: #fef5e7; color: #1a202c"
style="background: #453111; color: #b4cbf9"
>
🔨 در حال انجام
</div>
<div
class="rb-preview-column"
style="background: #faf5ff; color: #1a202c"
style="background: #542881; color: #b4cbf9"
>
🔍 برای تست
</div>
<div
class="rb-preview-column"
style="background: #f0fff4; color: #1a202c"
style="background: #087224; color: #d8d96d"
>
✅ انجام شده
</div>
@@ -3721,10 +3707,10 @@
<div class="rb-tag-list" id="rbTagList"></div>
</div>
<div class="modal-footer">
<button class="btn btn-ghost" data-close-modal>بستن</button>
<div style="font-size: 11px; color: var(--text-muted)">
💡 تغییرات تگ‌ها به صورت خودکار در تمام کارت‌ها اعمال می‌شود
</div>
<button class="btn btn-ghost" data-close-modal>بستن</button>
</div>
</div>
</div>
@@ -3790,177 +3776,21 @@
<div class="modal-title">💾 بازیابی خودکار داده‌ها</div>
</div>
<div class="modal-body">
<div style="text-align: center; padding: 24px 16px">
<div style="font-size: 48px; margin-bottom: 16px">💾</div>
<div
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;
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-size: 13px;
margin-bottom: 10px;
color: var(--primary);
color: var(--text);
margin-bottom: 8px;
"
>
📊 محتویات داده‌های ذخیره‌شده:
داده‌هایی در حافظه موقت وجود دارند
</div>
<div
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 style="font-size: 12px; color: var(--text-muted)">
آیا مایل به بازیابی آن‌ها هستید؟
</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 class="modal-footer" style="justify-content: space-between">
@@ -4031,7 +3861,7 @@
projectName: "xReleaseAssistant",
projectTitle: "دستیار انتشار",
description: "مدیریت نسخه‌ها و نیازمندی‌های محصولات",
version: "1.2.0",
version: "1.1.0",
developer: "هادی خزاعی اصل",
company: "رایان پرداز کاوش",
metadata: {
@@ -4091,7 +3921,6 @@
action: "showReleaseBoards",
description: "مشاهده و مدیریت بردهای انتشار",
},
/* ✅ NEW: ابزار مدیریت تگ‌ها */
{
id: "tag-manager",
title: "مدیریت تگ‌ها",
@@ -4153,50 +3982,7 @@
},
],
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",
},
],
environments: [],
products: [],
boards: [],
boardTags: [],
@@ -4546,7 +4332,7 @@
getSectionHTML() {
const d = this.getData();
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="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>`;
@@ -4972,7 +4758,6 @@
showReleaseBoards() {
ReleaseBoardsManager.open();
},
/* ✅ NEW: اکشن مدیریت تگ‌ها */
showTagManager() {
ReleaseBoardsManager.openTagManager();
},
@@ -5969,8 +5754,6 @@
: 0;
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>`;
document.getElementById("dashboardRefresh").onclick = () =>
this.render();
},
renderDonut(cid, data) {
const c = document.getElementById(cid);
@@ -6724,53 +6507,12 @@
checkRecovery() {
const saved = this.load();
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 = () =>
this.recover();
document.getElementById("rbDiscardAutosaveBtn").onclick = () =>
this.discard();
setTimeout(() => {
ModalManager.open("rbAutosaveModal");
}, 600);
@@ -6825,28 +6567,28 @@
DEFAULT_COLUMNS: [
{
title: "📥 بک لاگ",
backgroundColor: "#edf2f7",
textColor: "#1a202c",
backgroundColor: "#6b7208",
textColor: "#b4cbf9",
},
{
title: "📋 برای انجام",
backgroundColor: "#ebf8ff",
textColor: "#1a202c",
backgroundColor: "#393e65",
textColor: "#b4cbf9",
},
{
title: "🔨 در حال انجام",
backgroundColor: "#fef5e7",
textColor: "#1a202c",
backgroundColor: "#453111",
textColor: "#b4cbf9",
},
{
title: "🔍 برای تست",
backgroundColor: "#faf5ff",
textColor: "#1a202c",
backgroundColor: "#542881",
textColor: "#b4cbf9",
},
{
title: "✅ انجام شده",
backgroundColor: "#f0fff4",
textColor: "#1a202c",
backgroundColor: "#087224",
textColor: "#d8d96d",
},
],
open() {
@@ -6897,7 +6639,6 @@
} else {
this._incrementalRender(board);
}
/* ✅ NEW: اعمال فیلترها و اتصال درگ پس از رندر */
this.applyFilters();
this.initDragAndDrop();
this.updateFooterStats();
@@ -7098,9 +6839,6 @@ ${checklistTotal > 0 ? `<span class="card-meta-item">✅ ${checklistDone}/${chec
${checklistHtml}
</div>`;
},
/* ═══════════════════════════════════════════════════
✅ NEW: فیلتر تگ‌ها
═══════════════════════════════════════════════════ */
renderFilterBar() {
const container = document.getElementById("rbTagFilterContainer");
const clearBtn = document.getElementById("rbClearTagFilter");
@@ -7138,9 +6876,6 @@ ${checklistHtml}
};
}
},
/* ═══════════════════════════════════════════════════
✅ NEW: اعمال فیلتر و جستجو
═══════════════════════════════════════════════════ */
applyFilters() {
const board = this.getActiveBoard();
if (!board) return;
@@ -7224,9 +6959,6 @@ ${checklistHtml}
}
}
},
/* ═══════════════════════════════════════════════════
✅ NEW: رویدادهای جستجو
═══════════════════════════════════════════════════ */
bindSearchEvents() {
const inp = document.getElementById("rbCardSearchInput");
const clr = document.getElementById("rbCardSearchClear");
@@ -7253,9 +6985,6 @@ ${checklistHtml}
inp.focus();
};
},
/* ═══════════════════════════════════════════════════
✅ NEW: Drag & Drop
═══════════════════════════════════════════════════ */
initDragAndDrop() {
const wrapper = document.getElementById("rbBoardWrapper");
if (!wrapper) return;
@@ -7350,7 +7079,6 @@ ${checklistHtml}
.querySelectorAll(".drag-over-column")
.forEach((el) => el.classList.remove("drag-over-column"));
},
/* ── جابجایی کارت بین ستون‌ها ── */
moveCard(cardId, targetColumnId) {
const board = this.getActiveBoard();
if (!board) return;
@@ -7387,7 +7115,6 @@ ${checklistHtml}
2000,
);
},
/* ── جابجایی ستون‌ها ── */
moveColumn(sourceColId, targetColId) {
const board = this.getActiveBoard();
if (!board) return;
@@ -7406,7 +7133,6 @@ ${checklistHtml}
this.render(true);
showToast("📊 ستون جابجا شد", "success", 2000);
},
/* ── مدیریت برد ── */
getActiveBoard() {
return (projectData.appData.boards || []).find(
(b) => b.id === this.activeBoardId,
@@ -7525,7 +7251,6 @@ ${checklistHtml}
showToast("برد حذف شد", "warning");
this.render(true);
},
/* ── مدیریت ستون ── */
openNewColumnModal() {
if (!this.getActiveBoard()) {
showToast("ابتدا یک برد ایجاد کنید", "warning");
@@ -7600,7 +7325,6 @@ ${checklistHtml}
showToast("ستون حذف شد", "warning");
this.render(true);
},
/* ── مدیریت کارت ── */
openNewCardModal(columnId) {
this.editing.cardId = null;
this.editing.columnForCard = columnId;
@@ -7818,7 +7542,6 @@ ${checklistHtml}
document.getElementById("rbDeleteCardBtn").onclick = () =>
this.deleteCard();
},
/* ── Toolbar Events ── */
bindToolbarEvents() {
document.getElementById("rbEditBoard").onclick = () =>
this.openEditBoardModal();
@@ -7852,7 +7575,6 @@ ${checklistHtml}
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>`;
},
/* ── Tag Manager ── */
openTagManager() {
ModalManager.open("rbTagManagerModal");
this.renderTagList();
@@ -8089,8 +7811,6 @@ ${checklistHtml}
this.renderRiskList("depRiskList", d);
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>`;
document.getElementById("depAnalysisRefresh").onclick = () =>
this.render();
},
renderHubChart(cid, bottlenecks) {
const c = document.getElementById(cid);
@@ -8463,8 +8183,6 @@ ${checklistHtml}
this.renderRiskList("deployRiskList", d.riskList);
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>`;
document.getElementById("deployAnalysisRefresh").onclick = () =>
this.render();
},
renderEnvBarChart(cid, edc) {
const c = document.getElementById(cid);
@@ -8888,8 +8606,6 @@ ${checklistHtml}
this.renderRiskList("verRiskList", d.riskList);
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>`;
document.getElementById("verAnalysisRefresh").onclick = () =>
this.render();
},
renderMajorBarChart(cid, majorCounts) {
const c = document.getElementById(cid);
@@ -9274,8 +8990,6 @@ ${checklistHtml}
this.renderRiskList("riskDetailList", d.risks);
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>`;
document.getElementById("riskAnalysisRefresh").onclick = () =>
this.render();
},
renderSeverityDonut(cid, d) {
const c = document.getElementById(cid);