change tools->meToCo
This commit is contained in:
@@ -158,7 +158,7 @@
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.tools-grid {
|
||||
.meToCo-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
||||
gap: 20px;
|
||||
@@ -370,7 +370,7 @@
|
||||
.stats-grid {
|
||||
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
|
||||
}
|
||||
.tools-grid {
|
||||
.meToCo-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
.checkbox-group {
|
||||
@@ -396,12 +396,12 @@
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h1>🔧 DFIR Tools YAML Editor</h1>
|
||||
<p>Enhanced editor for Digital Forensics and Incident Response tools, methods, and concepts</p>
|
||||
<p>Enhanced editor for Digital Forensics and Incident Response meToCo, methods, and concepts</p>
|
||||
</div>
|
||||
|
||||
<div class="tabs">
|
||||
<div class="tab active" onclick="showTab('overview')">📊 Overview</div>
|
||||
<div class="tab" onclick="showTab('tools')">🛠️ Tools & Concepts</div>
|
||||
<div class="tab" onclick="showTab('meToCo')">🛠️ Tools & Concepts</div>
|
||||
<div class="tab" onclick="showTab('editor')">✏️ Editor</div>
|
||||
<div class="tab" onclick="showTab('bulk')">📋 Bulk Edit</div>
|
||||
<div class="tab" onclick="showTab('knowledge')">📚 Knowledge Generator</div>
|
||||
@@ -413,7 +413,7 @@
|
||||
<div style="background: var(--light); padding: 20px; border-radius: 10px; margin-bottom: 20px; border: 2px dashed var(--border); text-align: center;">
|
||||
<h3>📁 Load YAML File</h3>
|
||||
<input type="file" id="fileInput" accept=".yaml,.yml" onchange="loadFile()">
|
||||
<p>Select a YAML file to load existing tools data</p>
|
||||
<p>Select a YAML file to load existing meToCo data</p>
|
||||
</div>
|
||||
|
||||
<div id="stats" class="stats-grid"></div>
|
||||
@@ -430,7 +430,7 @@
|
||||
</div>
|
||||
|
||||
<!-- Tools Tab with Enhanced Search -->
|
||||
<div id="tools" class="tab-content">
|
||||
<div id="meToCo" class="tab-content">
|
||||
<div class="search-container">
|
||||
<h3>🔍 Search & Filter Tools</h3>
|
||||
<input type="text"
|
||||
@@ -460,7 +460,7 @@
|
||||
<button class="btn btn-secondary" onclick="clearFilters()">Clear All</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="toolsGrid" class="tools-grid"></div>
|
||||
<div id="meToCoGrid" class="meToCo-grid"></div>
|
||||
</div>
|
||||
|
||||
<!-- Enhanced Editor Tab -->
|
||||
@@ -645,7 +645,7 @@
|
||||
<div class="bulk-section">
|
||||
<h3>📋 Bulk Operations</h3>
|
||||
<div id="selectionInfo" style="margin-bottom: 15px; padding: 15px; background: white; border-radius: 8px; font-weight: 600; text-align: center; border: 2px solid var(--primary);">
|
||||
No tools selected
|
||||
No meToCo selected
|
||||
</div>
|
||||
|
||||
<div class="bulk-controls">
|
||||
@@ -702,7 +702,7 @@
|
||||
<button class="btn btn-danger" onclick="bulkDelete()">💀 Delete Selected Tools</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="bulkToolsGrid" class="tools-grid"></div>
|
||||
<div id="bulkToolsGrid" class="meToCo-grid"></div>
|
||||
</div>
|
||||
|
||||
<!-- Knowledge Generator Tab -->
|
||||
@@ -755,7 +755,7 @@
|
||||
// Initialize with correct YAML structure including scenarios
|
||||
function init() {
|
||||
yamlData = {
|
||||
tools: [],
|
||||
meToCo: [],
|
||||
domains: [
|
||||
{ id: 'incident-response', name: 'Incident Response & Breach-Untersuchung' },
|
||||
{ id: 'static-investigations', name: 'Datenträgerforensik & Ermittlungen' },
|
||||
@@ -773,7 +773,7 @@
|
||||
{ id: 'reporting', name: 'Bericht & Präsentation', description: 'Documentation, Visualization, Presentation Tools' }
|
||||
],
|
||||
'domain-agnostic-software': [
|
||||
{ id: 'collaboration-general', name: 'Übergreifend & Kollaboration', description: 'Cross-cutting tools and collaboration platforms' },
|
||||
{ id: 'collaboration-general', name: 'Übergreifend & Kollaboration', description: 'Cross-cutting meToCo and collaboration platforms' },
|
||||
{ id: 'specific-os', name: 'Betriebssysteme', description: 'Operating Systems which focus on forensics' }
|
||||
],
|
||||
scenarios: [
|
||||
@@ -801,7 +801,7 @@
|
||||
document.getElementById(tabName).classList.add('active');
|
||||
event.target.classList.add('active');
|
||||
|
||||
if (tabName === 'tools') renderToolsGrid();
|
||||
if (tabName === 'meToCo') renderToolsGrid();
|
||||
else if (tabName === 'bulk') renderBulkGrid();
|
||||
else if (tabName === 'knowledge') updateKnowledgeToolSelect();
|
||||
}
|
||||
@@ -811,11 +811,11 @@
|
||||
applyFilters();
|
||||
}
|
||||
|
||||
function searchTools(tools, searchTerm) {
|
||||
if (!searchTerm) return tools;
|
||||
function searchTools(meToCo, searchTerm) {
|
||||
if (!searchTerm) return meToCo;
|
||||
|
||||
const term = searchTerm.toLowerCase();
|
||||
return tools.filter(tool => {
|
||||
return meToCo.filter(tool => {
|
||||
// Search in name
|
||||
if (tool.name && tool.name.toLowerCase().includes(term)) return true;
|
||||
|
||||
@@ -946,15 +946,15 @@
|
||||
}
|
||||
|
||||
function updateStats() {
|
||||
if (!yamlData?.tools) return;
|
||||
if (!yamlData?.meToCo) return;
|
||||
|
||||
const stats = {
|
||||
total: yamlData.tools.length,
|
||||
software: yamlData.tools.filter(t => t.type === 'software' || !t.type).length,
|
||||
methods: yamlData.tools.filter(t => t.type === 'method').length,
|
||||
concepts: yamlData.tools.filter(t => t.type === 'concept').length,
|
||||
withKnowledgebase: yamlData.tools.filter(t => t.knowledgebase).length,
|
||||
withRelatedSoftware: yamlData.tools.filter(t => t.related_software && t.related_software.length > 0).length
|
||||
total: yamlData.meToCo.length,
|
||||
software: yamlData.meToCo.filter(t => t.type === 'software' || !t.type).length,
|
||||
methods: yamlData.meToCo.filter(t => t.type === 'method').length,
|
||||
concepts: yamlData.meToCo.filter(t => t.type === 'concept').length,
|
||||
withKnowledgebase: yamlData.meToCo.filter(t => t.knowledgebase).length,
|
||||
withRelatedSoftware: yamlData.meToCo.filter(t => t.related_software && t.related_software.length > 0).length
|
||||
};
|
||||
|
||||
document.getElementById('stats').innerHTML = `
|
||||
@@ -1042,8 +1042,8 @@
|
||||
|
||||
function saveTool() {
|
||||
try {
|
||||
if (!yamlData) yamlData = { tools: [] };
|
||||
if (!yamlData.tools) yamlData.tools = [];
|
||||
if (!yamlData) yamlData = { meToCo: [] };
|
||||
if (!yamlData.meToCo) yamlData.meToCo = [];
|
||||
|
||||
const toolType = document.getElementById('toolType').value;
|
||||
const tool = {
|
||||
@@ -1104,11 +1104,11 @@
|
||||
}
|
||||
|
||||
if (currentEditingIndex >= 0) {
|
||||
yamlData.tools[currentEditingIndex] = tool;
|
||||
yamlData.meToCo[currentEditingIndex] = tool;
|
||||
showMessage('Tool updated successfully!');
|
||||
currentEditingIndex = -1;
|
||||
} else {
|
||||
yamlData.tools.push(tool);
|
||||
yamlData.meToCo.push(tool);
|
||||
showMessage('Tool added successfully!');
|
||||
}
|
||||
|
||||
@@ -1146,7 +1146,7 @@
|
||||
}
|
||||
|
||||
function editTool(index) {
|
||||
const tool = yamlData.tools[index];
|
||||
const tool = yamlData.meToCo[index];
|
||||
currentEditingIndex = index;
|
||||
|
||||
// Populate form fields
|
||||
@@ -1208,7 +1208,7 @@
|
||||
|
||||
function deleteTool(index) {
|
||||
if (confirm('Are you sure you want to delete this tool?')) {
|
||||
yamlData.tools.splice(index, 1);
|
||||
yamlData.meToCo.splice(index, 1);
|
||||
showMessage('Tool deleted successfully!');
|
||||
updateStats();
|
||||
renderToolsGrid();
|
||||
@@ -1217,12 +1217,12 @@
|
||||
}
|
||||
|
||||
function renderToolsGrid() {
|
||||
const container = document.getElementById('toolsGrid');
|
||||
const container = document.getElementById('meToCoGrid');
|
||||
container.innerHTML = '';
|
||||
|
||||
if (!yamlData?.tools) return;
|
||||
if (!yamlData?.meToCo) return;
|
||||
|
||||
let filteredTools = yamlData.tools;
|
||||
let filteredTools = yamlData.meToCo;
|
||||
|
||||
// Apply search filter
|
||||
const searchTerm = document.getElementById('searchInput')?.value;
|
||||
@@ -1243,17 +1243,17 @@
|
||||
// Update search results info
|
||||
const searchResults = document.getElementById('searchResults');
|
||||
if (searchResults) {
|
||||
const totalTools = yamlData.tools.length;
|
||||
const totalTools = yamlData.meToCo.length;
|
||||
const filteredCount = filteredTools.length;
|
||||
if (searchTerm || typeFilter || skillFilter) {
|
||||
searchResults.textContent = `Showing ${filteredCount} of ${totalTools} tools`;
|
||||
searchResults.textContent = `Showing ${filteredCount} of ${totalTools} meToCo`;
|
||||
} else {
|
||||
searchResults.textContent = `Showing all ${totalTools} tools`;
|
||||
searchResults.textContent = `Showing all ${totalTools} meToCo`;
|
||||
}
|
||||
}
|
||||
|
||||
filteredTools.forEach((tool, index) => {
|
||||
const originalIndex = yamlData.tools.indexOf(tool);
|
||||
const originalIndex = yamlData.meToCo.indexOf(tool);
|
||||
const card = createToolCard(tool, originalIndex);
|
||||
container.appendChild(card);
|
||||
});
|
||||
@@ -1296,9 +1296,9 @@
|
||||
const container = document.getElementById('bulkToolsGrid');
|
||||
container.innerHTML = '';
|
||||
|
||||
if (!yamlData?.tools) return;
|
||||
if (!yamlData?.meToCo) return;
|
||||
|
||||
yamlData.tools.forEach((tool, index) => {
|
||||
yamlData.meToCo.forEach((tool, index) => {
|
||||
const card = createBulkToolCard(tool, index);
|
||||
container.appendChild(card);
|
||||
});
|
||||
@@ -1350,7 +1350,7 @@
|
||||
|
||||
function selectAllTools() {
|
||||
selectedTools.clear();
|
||||
yamlData.tools.forEach((_, index) => selectedTools.add(index));
|
||||
yamlData.meToCo.forEach((_, index) => selectedTools.add(index));
|
||||
updateSelectionCount();
|
||||
renderBulkGrid();
|
||||
}
|
||||
@@ -1365,7 +1365,7 @@
|
||||
const count = selectedTools.size;
|
||||
const info = document.getElementById('selectionInfo');
|
||||
if (count === 0) {
|
||||
info.textContent = 'No tools selected';
|
||||
info.textContent = 'No meToCo selected';
|
||||
info.style.background = 'white';
|
||||
info.style.borderColor = 'var(--border)';
|
||||
} else {
|
||||
@@ -1377,175 +1377,175 @@
|
||||
|
||||
// Enhanced bulk operations with scenarios and related software
|
||||
function bulkSetType() {
|
||||
if (selectedTools.size === 0) return showMessage('No tools selected', 'error');
|
||||
if (selectedTools.size === 0) return showMessage('No meToCo selected', 'error');
|
||||
const newType = prompt('Enter new type (software/method/concept):');
|
||||
if (newType && ['software', 'method', 'concept'].includes(newType)) {
|
||||
selectedTools.forEach(index => yamlData.tools[index].type = newType);
|
||||
showMessage(`Updated type for ${selectedTools.size} tools`);
|
||||
selectedTools.forEach(index => yamlData.meToCo[index].type = newType);
|
||||
showMessage(`Updated type for ${selectedTools.size} meToCo`);
|
||||
updateStats();
|
||||
renderBulkGrid();
|
||||
}
|
||||
}
|
||||
|
||||
function bulkSetSkillLevel() {
|
||||
if (selectedTools.size === 0) return showMessage('No tools selected', 'error');
|
||||
if (selectedTools.size === 0) return showMessage('No meToCo selected', 'error');
|
||||
const newLevel = prompt('Enter skill level (novice/beginner/intermediate/advanced/expert):');
|
||||
if (newLevel && ['novice', 'beginner', 'intermediate', 'advanced', 'expert'].includes(newLevel)) {
|
||||
selectedTools.forEach(index => yamlData.tools[index].skillLevel = newLevel);
|
||||
showMessage(`Updated skill level for ${selectedTools.size} tools`);
|
||||
selectedTools.forEach(index => yamlData.meToCo[index].skillLevel = newLevel);
|
||||
showMessage(`Updated skill level for ${selectedTools.size} meToCo`);
|
||||
renderBulkGrid();
|
||||
}
|
||||
}
|
||||
|
||||
function bulkAddTags() {
|
||||
if (selectedTools.size === 0) return showMessage('No tools selected', 'error');
|
||||
if (selectedTools.size === 0) return showMessage('No meToCo selected', 'error');
|
||||
const tags = prompt('Enter tags to add (comma-separated):');
|
||||
if (tags) {
|
||||
const tagList = tags.split(',').map(t => t.trim()).filter(t => t);
|
||||
selectedTools.forEach(index => {
|
||||
const tool = yamlData.tools[index];
|
||||
const tool = yamlData.meToCo[index];
|
||||
tool.tags = [...new Set([...(tool.tags || []), ...tagList])];
|
||||
});
|
||||
showMessage(`Added tags to ${selectedTools.size} tools`);
|
||||
showMessage(`Added tags to ${selectedTools.size} meToCo`);
|
||||
renderBulkGrid();
|
||||
}
|
||||
}
|
||||
|
||||
function bulkRemoveTags() {
|
||||
if (selectedTools.size === 0) return showMessage('No tools selected', 'error');
|
||||
if (selectedTools.size === 0) return showMessage('No meToCo selected', 'error');
|
||||
const tags = prompt('Enter tags to remove (comma-separated):');
|
||||
if (tags) {
|
||||
const tagList = tags.split(',').map(t => t.trim()).filter(t => t);
|
||||
selectedTools.forEach(index => {
|
||||
const tool = yamlData.tools[index];
|
||||
const tool = yamlData.meToCo[index];
|
||||
if (tool.tags) {
|
||||
tool.tags = tool.tags.filter(tag => !tagList.includes(tag));
|
||||
if (tool.tags.length === 0) delete tool.tags;
|
||||
}
|
||||
});
|
||||
showMessage(`Removed tags from ${selectedTools.size} tools`);
|
||||
showMessage(`Removed tags from ${selectedTools.size} meToCo`);
|
||||
renderBulkGrid();
|
||||
}
|
||||
}
|
||||
|
||||
function bulkReplaceTags() {
|
||||
if (selectedTools.size === 0) return showMessage('No tools selected', 'error');
|
||||
if (selectedTools.size === 0) return showMessage('No meToCo selected', 'error');
|
||||
const tags = prompt('Enter new tags (comma-separated, will replace all existing tags):');
|
||||
if (tags !== null) {
|
||||
const tagList = tags.split(',').map(t => t.trim()).filter(t => t);
|
||||
selectedTools.forEach(index => {
|
||||
const tool = yamlData.tools[index];
|
||||
const tool = yamlData.meToCo[index];
|
||||
if (tagList.length > 0) {
|
||||
tool.tags = tagList;
|
||||
} else {
|
||||
delete tool.tags;
|
||||
}
|
||||
});
|
||||
showMessage(`Replaced tags for ${selectedTools.size} tools`);
|
||||
showMessage(`Replaced tags for ${selectedTools.size} meToCo`);
|
||||
renderBulkGrid();
|
||||
}
|
||||
}
|
||||
|
||||
function bulkClearTags() {
|
||||
if (selectedTools.size === 0) return showMessage('No tools selected', 'error');
|
||||
if (confirm(`Are you sure you want to clear ALL tags from ${selectedTools.size} selected tools?`)) {
|
||||
if (selectedTools.size === 0) return showMessage('No meToCo selected', 'error');
|
||||
if (confirm(`Are you sure you want to clear ALL tags from ${selectedTools.size} selected meToCo?`)) {
|
||||
selectedTools.forEach(index => {
|
||||
delete yamlData.tools[index].tags;
|
||||
delete yamlData.meToCo[index].tags;
|
||||
});
|
||||
showMessage(`Cleared tags from ${selectedTools.size} tools`);
|
||||
showMessage(`Cleared tags from ${selectedTools.size} meToCo`);
|
||||
renderBulkGrid();
|
||||
}
|
||||
}
|
||||
|
||||
// Domain operations
|
||||
function bulkAddDomains() {
|
||||
if (selectedTools.size === 0) return showMessage('No tools selected', 'error');
|
||||
if (selectedTools.size === 0) return showMessage('No meToCo selected', 'error');
|
||||
const domains = prompt('Enter domain IDs to add (comma-separated):');
|
||||
if (domains) {
|
||||
const domainList = domains.split(',').map(d => d.trim()).filter(d => d);
|
||||
selectedTools.forEach(index => {
|
||||
const tool = yamlData.tools[index];
|
||||
const tool = yamlData.meToCo[index];
|
||||
tool.domains = [...new Set([...(tool.domains || []), ...domainList])];
|
||||
});
|
||||
showMessage(`Added domains to ${selectedTools.size} tools`);
|
||||
showMessage(`Added domains to ${selectedTools.size} meToCo`);
|
||||
renderBulkGrid();
|
||||
}
|
||||
}
|
||||
|
||||
function bulkRemoveDomains() {
|
||||
if (selectedTools.size === 0) return showMessage('No tools selected', 'error');
|
||||
if (selectedTools.size === 0) return showMessage('No meToCo selected', 'error');
|
||||
const domains = prompt('Enter domain IDs to remove (comma-separated):');
|
||||
if (domains) {
|
||||
const domainList = domains.split(',').map(d => d.trim()).filter(d => d);
|
||||
selectedTools.forEach(index => {
|
||||
const tool = yamlData.tools[index];
|
||||
const tool = yamlData.meToCo[index];
|
||||
if (tool.domains) {
|
||||
tool.domains = tool.domains.filter(domain => !domainList.includes(domain));
|
||||
if (tool.domains.length === 0) delete tool.domains;
|
||||
}
|
||||
});
|
||||
showMessage(`Removed domains from ${selectedTools.size} tools`);
|
||||
showMessage(`Removed domains from ${selectedTools.size} meToCo`);
|
||||
renderBulkGrid();
|
||||
}
|
||||
}
|
||||
|
||||
function bulkClearDomains() {
|
||||
if (selectedTools.size === 0) return showMessage('No tools selected', 'error');
|
||||
if (confirm(`Are you sure you want to clear ALL domains from ${selectedTools.size} selected tools?`)) {
|
||||
if (selectedTools.size === 0) return showMessage('No meToCo selected', 'error');
|
||||
if (confirm(`Are you sure you want to clear ALL domains from ${selectedTools.size} selected meToCo?`)) {
|
||||
selectedTools.forEach(index => {
|
||||
delete yamlData.tools[index].domains;
|
||||
delete yamlData.meToCo[index].domains;
|
||||
});
|
||||
showMessage(`Cleared domains from ${selectedTools.size} tools`);
|
||||
showMessage(`Cleared domains from ${selectedTools.size} meToCo`);
|
||||
renderBulkGrid();
|
||||
}
|
||||
}
|
||||
|
||||
// Phase operations
|
||||
function bulkAddPhases() {
|
||||
if (selectedTools.size === 0) return showMessage('No tools selected', 'error');
|
||||
if (selectedTools.size === 0) return showMessage('No meToCo selected', 'error');
|
||||
const phases = prompt('Enter phase IDs to add (comma-separated):');
|
||||
if (phases) {
|
||||
const phaseList = phases.split(',').map(p => p.trim()).filter(p => p);
|
||||
selectedTools.forEach(index => {
|
||||
const tool = yamlData.tools[index];
|
||||
const tool = yamlData.meToCo[index];
|
||||
tool.phases = [...new Set([...(tool.phases || []), ...phaseList])];
|
||||
});
|
||||
showMessage(`Added phases to ${selectedTools.size} tools`);
|
||||
showMessage(`Added phases to ${selectedTools.size} meToCo`);
|
||||
renderBulkGrid();
|
||||
}
|
||||
}
|
||||
|
||||
function bulkRemovePhases() {
|
||||
if (selectedTools.size === 0) return showMessage('No tools selected', 'error');
|
||||
if (selectedTools.size === 0) return showMessage('No meToCo selected', 'error');
|
||||
const phases = prompt('Enter phase IDs to remove (comma-separated):');
|
||||
if (phases) {
|
||||
const phaseList = phases.split(',').map(p => p.trim()).filter(p => p);
|
||||
selectedTools.forEach(index => {
|
||||
const tool = yamlData.tools[index];
|
||||
const tool = yamlData.meToCo[index];
|
||||
if (tool.phases) {
|
||||
tool.phases = tool.phases.filter(phase => !phaseList.includes(phase));
|
||||
if (tool.phases.length === 0) delete tool.phases;
|
||||
}
|
||||
});
|
||||
showMessage(`Removed phases from ${selectedTools.size} tools`);
|
||||
showMessage(`Removed phases from ${selectedTools.size} meToCo`);
|
||||
renderBulkGrid();
|
||||
}
|
||||
}
|
||||
|
||||
function bulkClearPhases() {
|
||||
if (selectedTools.size === 0) return showMessage('No tools selected', 'error');
|
||||
if (confirm(`Are you sure you want to clear ALL phases from ${selectedTools.size} selected tools?`)) {
|
||||
if (selectedTools.size === 0) return showMessage('No meToCo selected', 'error');
|
||||
if (confirm(`Are you sure you want to clear ALL phases from ${selectedTools.size} selected meToCo?`)) {
|
||||
selectedTools.forEach(index => {
|
||||
delete yamlData.tools[index].phases;
|
||||
delete yamlData.meToCo[index].phases;
|
||||
});
|
||||
showMessage(`Cleared phases from ${selectedTools.size} tools`);
|
||||
showMessage(`Cleared phases from ${selectedTools.size} meToCo`);
|
||||
renderBulkGrid();
|
||||
}
|
||||
}
|
||||
|
||||
// Scenario operations (work with tags that have scenario: prefix)
|
||||
function bulkAddScenarios() {
|
||||
if (selectedTools.size === 0) return showMessage('No tools selected', 'error');
|
||||
if (selectedTools.size === 0) return showMessage('No meToCo selected', 'error');
|
||||
const scenarios = prompt('Enter scenario IDs to add (comma-separated, e.g., scenario:memory_dump,scenario:registry):');
|
||||
if (scenarios) {
|
||||
const scenarioList = scenarios.split(',').map(s => {
|
||||
@@ -1553,16 +1553,16 @@
|
||||
return trimmed.startsWith('scenario:') ? trimmed : `scenario:${trimmed}`;
|
||||
}).filter(s => s !== 'scenario:');
|
||||
selectedTools.forEach(index => {
|
||||
const tool = yamlData.tools[index];
|
||||
const tool = yamlData.meToCo[index];
|
||||
tool.tags = [...new Set([...(tool.tags || []), ...scenarioList])];
|
||||
});
|
||||
showMessage(`Added scenario tags to ${selectedTools.size} tools`);
|
||||
showMessage(`Added scenario tags to ${selectedTools.size} meToCo`);
|
||||
renderBulkGrid();
|
||||
}
|
||||
}
|
||||
|
||||
function bulkRemoveScenarios() {
|
||||
if (selectedTools.size === 0) return showMessage('No tools selected', 'error');
|
||||
if (selectedTools.size === 0) return showMessage('No meToCo selected', 'error');
|
||||
const scenarios = prompt('Enter scenario IDs to remove (comma-separated):');
|
||||
if (scenarios) {
|
||||
const scenarioList = scenarios.split(',').map(s => {
|
||||
@@ -1570,168 +1570,168 @@
|
||||
return trimmed.startsWith('scenario:') ? trimmed : `scenario:${trimmed}`;
|
||||
}).filter(s => s !== 'scenario:');
|
||||
selectedTools.forEach(index => {
|
||||
const tool = yamlData.tools[index];
|
||||
const tool = yamlData.meToCo[index];
|
||||
if (tool.tags) {
|
||||
tool.tags = tool.tags.filter(tag => !scenarioList.includes(tag));
|
||||
if (tool.tags.length === 0) delete tool.tags;
|
||||
}
|
||||
});
|
||||
showMessage(`Removed scenario tags from ${selectedTools.size} tools`);
|
||||
showMessage(`Removed scenario tags from ${selectedTools.size} meToCo`);
|
||||
renderBulkGrid();
|
||||
}
|
||||
}
|
||||
|
||||
function bulkClearScenarios() {
|
||||
if (selectedTools.size === 0) return showMessage('No tools selected', 'error');
|
||||
if (confirm(`Are you sure you want to clear ALL scenario tags from ${selectedTools.size} selected tools?`)) {
|
||||
if (selectedTools.size === 0) return showMessage('No meToCo selected', 'error');
|
||||
if (confirm(`Are you sure you want to clear ALL scenario tags from ${selectedTools.size} selected meToCo?`)) {
|
||||
selectedTools.forEach(index => {
|
||||
const tool = yamlData.tools[index];
|
||||
const tool = yamlData.meToCo[index];
|
||||
if (tool.tags) {
|
||||
tool.tags = tool.tags.filter(tag => !tag.startsWith('scenario:'));
|
||||
if (tool.tags.length === 0) delete tool.tags;
|
||||
}
|
||||
});
|
||||
showMessage(`Cleared scenario tags from ${selectedTools.size} tools`);
|
||||
showMessage(`Cleared scenario tags from ${selectedTools.size} meToCo`);
|
||||
renderBulkGrid();
|
||||
}
|
||||
}
|
||||
|
||||
// Platform operations
|
||||
function bulkAddPlatforms() {
|
||||
if (selectedTools.size === 0) return showMessage('No tools selected', 'error');
|
||||
if (selectedTools.size === 0) return showMessage('No meToCo selected', 'error');
|
||||
const platforms = prompt('Enter platforms to add (comma-separated, e.g., Windows,Linux,macOS):');
|
||||
if (platforms) {
|
||||
const platformList = platforms.split(',').map(p => p.trim()).filter(p => p);
|
||||
selectedTools.forEach(index => {
|
||||
const tool = yamlData.tools[index];
|
||||
const tool = yamlData.meToCo[index];
|
||||
tool.platforms = [...new Set([...(tool.platforms || []), ...platformList])];
|
||||
});
|
||||
showMessage(`Added platforms to ${selectedTools.size} tools`);
|
||||
showMessage(`Added platforms to ${selectedTools.size} meToCo`);
|
||||
renderBulkGrid();
|
||||
}
|
||||
}
|
||||
|
||||
function bulkRemovePlatforms() {
|
||||
if (selectedTools.size === 0) return showMessage('No tools selected', 'error');
|
||||
if (selectedTools.size === 0) return showMessage('No meToCo selected', 'error');
|
||||
const platforms = prompt('Enter platforms to remove (comma-separated):');
|
||||
if (platforms) {
|
||||
const platformList = platforms.split(',').map(p => p.trim()).filter(p => p);
|
||||
selectedTools.forEach(index => {
|
||||
const tool = yamlData.tools[index];
|
||||
const tool = yamlData.meToCo[index];
|
||||
if (tool.platforms) {
|
||||
tool.platforms = tool.platforms.filter(platform => !platformList.includes(platform));
|
||||
if (tool.platforms.length === 0) delete tool.platforms;
|
||||
}
|
||||
});
|
||||
showMessage(`Removed platforms from ${selectedTools.size} tools`);
|
||||
showMessage(`Removed platforms from ${selectedTools.size} meToCo`);
|
||||
renderBulkGrid();
|
||||
}
|
||||
}
|
||||
|
||||
function bulkClearPlatforms() {
|
||||
if (selectedTools.size === 0) return showMessage('No tools selected', 'error');
|
||||
if (confirm(`Are you sure you want to clear ALL platforms from ${selectedTools.size} selected tools?`)) {
|
||||
if (selectedTools.size === 0) return showMessage('No meToCo selected', 'error');
|
||||
if (confirm(`Are you sure you want to clear ALL platforms from ${selectedTools.size} selected meToCo?`)) {
|
||||
selectedTools.forEach(index => {
|
||||
delete yamlData.tools[index].platforms;
|
||||
delete yamlData.meToCo[index].platforms;
|
||||
});
|
||||
showMessage(`Cleared platforms from ${selectedTools.size} tools`);
|
||||
showMessage(`Cleared platforms from ${selectedTools.size} meToCo`);
|
||||
renderBulkGrid();
|
||||
}
|
||||
}
|
||||
|
||||
// Related concepts operations
|
||||
function bulkAddRelatedConcepts() {
|
||||
if (selectedTools.size === 0) return showMessage('No tools selected', 'error');
|
||||
if (selectedTools.size === 0) return showMessage('No meToCo selected', 'error');
|
||||
const concepts = prompt('Enter related concept names to add (comma-separated):');
|
||||
if (concepts) {
|
||||
const conceptList = concepts.split(',').map(c => c.trim()).filter(c => c);
|
||||
selectedTools.forEach(index => {
|
||||
const tool = yamlData.tools[index];
|
||||
const tool = yamlData.meToCo[index];
|
||||
tool.related_concepts = [...new Set([...(tool.related_concepts || []), ...conceptList])];
|
||||
});
|
||||
showMessage(`Added related concepts to ${selectedTools.size} tools`);
|
||||
showMessage(`Added related concepts to ${selectedTools.size} meToCo`);
|
||||
renderBulkGrid();
|
||||
}
|
||||
}
|
||||
|
||||
function bulkRemoveRelatedConcepts() {
|
||||
if (selectedTools.size === 0) return showMessage('No tools selected', 'error');
|
||||
if (selectedTools.size === 0) return showMessage('No meToCo selected', 'error');
|
||||
const concepts = prompt('Enter related concept names to remove (comma-separated):');
|
||||
if (concepts) {
|
||||
const conceptList = concepts.split(',').map(c => c.trim()).filter(c => c);
|
||||
selectedTools.forEach(index => {
|
||||
const tool = yamlData.tools[index];
|
||||
const tool = yamlData.meToCo[index];
|
||||
if (tool.related_concepts) {
|
||||
tool.related_concepts = tool.related_concepts.filter(concept => !conceptList.includes(concept));
|
||||
if (tool.related_concepts.length === 0) delete tool.related_concepts;
|
||||
}
|
||||
});
|
||||
showMessage(`Removed related concepts from ${selectedTools.size} tools`);
|
||||
showMessage(`Removed related concepts from ${selectedTools.size} meToCo`);
|
||||
renderBulkGrid();
|
||||
}
|
||||
}
|
||||
|
||||
function bulkClearRelatedConcepts() {
|
||||
if (selectedTools.size === 0) return showMessage('No tools selected', 'error');
|
||||
if (confirm(`Are you sure you want to clear ALL related concepts from ${selectedTools.size} selected tools?`)) {
|
||||
if (selectedTools.size === 0) return showMessage('No meToCo selected', 'error');
|
||||
if (confirm(`Are you sure you want to clear ALL related concepts from ${selectedTools.size} selected meToCo?`)) {
|
||||
selectedTools.forEach(index => {
|
||||
delete yamlData.tools[index].related_concepts;
|
||||
delete yamlData.meToCo[index].related_concepts;
|
||||
});
|
||||
showMessage(`Cleared related concepts from ${selectedTools.size} tools`);
|
||||
showMessage(`Cleared related concepts from ${selectedTools.size} meToCo`);
|
||||
renderBulkGrid();
|
||||
}
|
||||
}
|
||||
|
||||
// NEW: Related software operations
|
||||
function bulkAddRelatedSoftware() {
|
||||
if (selectedTools.size === 0) return showMessage('No tools selected', 'error');
|
||||
if (selectedTools.size === 0) return showMessage('No meToCo selected', 'error');
|
||||
const software = prompt('Enter related software names to add (comma-separated):');
|
||||
if (software) {
|
||||
const softwareList = software.split(',').map(s => s.trim()).filter(s => s);
|
||||
selectedTools.forEach(index => {
|
||||
const tool = yamlData.tools[index];
|
||||
const tool = yamlData.meToCo[index];
|
||||
tool.related_software = [...new Set([...(tool.related_software || []), ...softwareList])];
|
||||
});
|
||||
showMessage(`Added related software to ${selectedTools.size} tools`);
|
||||
showMessage(`Added related software to ${selectedTools.size} meToCo`);
|
||||
renderBulkGrid();
|
||||
}
|
||||
}
|
||||
|
||||
function bulkRemoveRelatedSoftware() {
|
||||
if (selectedTools.size === 0) return showMessage('No tools selected', 'error');
|
||||
if (selectedTools.size === 0) return showMessage('No meToCo selected', 'error');
|
||||
const software = prompt('Enter related software names to remove (comma-separated):');
|
||||
if (software) {
|
||||
const softwareList = software.split(',').map(s => s.trim()).filter(s => s);
|
||||
selectedTools.forEach(index => {
|
||||
const tool = yamlData.tools[index];
|
||||
const tool = yamlData.meToCo[index];
|
||||
if (tool.related_software) {
|
||||
tool.related_software = tool.related_software.filter(sw => !softwareList.includes(sw));
|
||||
if (tool.related_software.length === 0) delete tool.related_software;
|
||||
}
|
||||
});
|
||||
showMessage(`Removed related software from ${selectedTools.size} tools`);
|
||||
showMessage(`Removed related software from ${selectedTools.size} meToCo`);
|
||||
renderBulkGrid();
|
||||
}
|
||||
}
|
||||
|
||||
function bulkClearRelatedSoftware() {
|
||||
if (selectedTools.size === 0) return showMessage('No tools selected', 'error');
|
||||
if (confirm(`Are you sure you want to clear ALL related software from ${selectedTools.size} selected tools?`)) {
|
||||
if (selectedTools.size === 0) return showMessage('No meToCo selected', 'error');
|
||||
if (confirm(`Are you sure you want to clear ALL related software from ${selectedTools.size} selected meToCo?`)) {
|
||||
selectedTools.forEach(index => {
|
||||
delete yamlData.tools[index].related_software;
|
||||
delete yamlData.meToCo[index].related_software;
|
||||
});
|
||||
showMessage(`Cleared related software from ${selectedTools.size} tools`);
|
||||
showMessage(`Cleared related software from ${selectedTools.size} meToCo`);
|
||||
renderBulkGrid();
|
||||
}
|
||||
}
|
||||
|
||||
function bulkDelete() {
|
||||
if (selectedTools.size === 0) return showMessage('No tools selected', 'error');
|
||||
if (confirm(`Are you sure you want to delete ${selectedTools.size} selected tools? This action cannot be undone!`)) {
|
||||
if (selectedTools.size === 0) return showMessage('No meToCo selected', 'error');
|
||||
if (confirm(`Are you sure you want to delete ${selectedTools.size} selected meToCo? This action cannot be undone!`)) {
|
||||
const indicesToDelete = Array.from(selectedTools).sort((a, b) => b - a);
|
||||
indicesToDelete.forEach(index => yamlData.tools.splice(index, 1));
|
||||
indicesToDelete.forEach(index => yamlData.meToCo.splice(index, 1));
|
||||
selectedTools.clear();
|
||||
showMessage(`Deleted ${indicesToDelete.length} tools successfully!`);
|
||||
showMessage(`Deleted ${indicesToDelete.length} meToCo successfully!`);
|
||||
updateStats();
|
||||
renderBulkGrid();
|
||||
updateKnowledgeToolSelect();
|
||||
@@ -1743,9 +1743,9 @@
|
||||
const select = document.getElementById('knowledgeToolSelect');
|
||||
select.innerHTML = '<option value="">Choose a tool or concept...</option>';
|
||||
|
||||
if (!yamlData?.tools) return;
|
||||
if (!yamlData?.meToCo) return;
|
||||
|
||||
yamlData.tools.forEach((tool, index) => {
|
||||
yamlData.meToCo.forEach((tool, index) => {
|
||||
const option = document.createElement('option');
|
||||
option.value = index;
|
||||
option.textContent = `${tool.icon ? tool.icon + ' ' : ''}${tool.name} (${tool.type || 'software'})`;
|
||||
@@ -1762,7 +1762,7 @@
|
||||
return;
|
||||
}
|
||||
|
||||
const tool = yamlData.tools[index];
|
||||
const tool = yamlData.meToCo[index];
|
||||
const template = createCC24MarkdownTemplate(tool);
|
||||
|
||||
document.getElementById('markdownContent').value = template;
|
||||
@@ -1781,10 +1781,10 @@ title: "${tool.name}"
|
||||
description: "${tool.description.split('\n')[0].trim()}"
|
||||
last_updated: ${new Date().toISOString().split('T')[0]}
|
||||
tool_name: "${tool.name}"
|
||||
related_tools: ${JSON.stringify([...(tool.related_concepts || []), ...(tool.related_software || [])])}
|
||||
related_meToCo: ${JSON.stringify([...(tool.related_concepts || []), ...(tool.related_software || [])])}
|
||||
author: "CC24-Team"
|
||||
difficulty: "${tool.skillLevel || 'intermediate'}"
|
||||
categories: ${tool.type === 'concept' ? '["concepts"]' : tool.type === 'method' ? '["methods"]' : '["tools"]'}
|
||||
categories: ${tool.type === 'concept' ? '["concepts"]' : tool.type === 'method' ? '["methods"]' : '["meToCo"]'}
|
||||
tags: ${tool.tags ? JSON.stringify(tool.tags) : '[]'}
|
||||
published: true
|
||||
---
|
||||
@@ -1871,7 +1871,7 @@ TODO: Füge weitere nützliche Links und Ressourcen hinzu.
|
||||
const content = document.getElementById('markdownContent').value;
|
||||
const select = document.getElementById('knowledgeToolSelect');
|
||||
const index = parseInt(select.value);
|
||||
const tool = yamlData.tools[index];
|
||||
const tool = yamlData.meToCo[index];
|
||||
|
||||
const toolSlug = tool.name.toLowerCase()
|
||||
.replace(/[^a-z0-9\s-]/g, '')
|
||||
@@ -1909,13 +1909,13 @@ TODO: Füge weitere nützliche Links und Ressourcen hinzu.
|
||||
const validationResults = [];
|
||||
|
||||
// Check required sections
|
||||
if (!yamlData.tools) validationResults.push('❌ Missing tools section');
|
||||
if (!yamlData.meToCo) validationResults.push('❌ Missing meToCo section');
|
||||
if (!yamlData.domains) validationResults.push('❌ Missing domains section');
|
||||
if (!yamlData.phases) validationResults.push('❌ Missing phases section');
|
||||
if (!yamlData.scenarios) validationResults.push('⚠️ Missing scenarios section (for reference)');
|
||||
|
||||
// Validate tools
|
||||
yamlData.tools?.forEach((tool, index) => {
|
||||
// Validate meToCo
|
||||
yamlData.meToCo?.forEach((tool, index) => {
|
||||
if (!tool.name) validationResults.push(`❌ Tool ${index + 1}: Missing name`);
|
||||
if (!tool.description) validationResults.push(`❌ Tool ${index + 1}: Missing description`);
|
||||
if (!tool.skillLevel) validationResults.push(`❌ Tool ${index + 1}: Missing skillLevel`);
|
||||
@@ -1936,9 +1936,9 @@ TODO: Füge weitere nützliche Links und Ressourcen hinzu.
|
||||
// Validate related_software references
|
||||
if (tool.related_software && tool.related_software.length > 0) {
|
||||
tool.related_software.forEach(relatedName => {
|
||||
const exists = yamlData.tools.some(t => t.name === relatedName);
|
||||
const exists = yamlData.meToCo.some(t => t.name === relatedName);
|
||||
if (!exists) {
|
||||
validationResults.push(`⚠️ Tool ${index + 1}: Related software "${relatedName}" not found in tools`);
|
||||
validationResults.push(`⚠️ Tool ${index + 1}: Related software "${relatedName}" not found in meToCo`);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -2000,7 +2000,7 @@ TODO: Füge weitere nützliche Links und Ressourcen hinzu.
|
||||
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = 'tools.json';
|
||||
a.download = 'meToCo.json';
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
document.body.removeChild(a);
|
||||
|
||||
Reference in New Issue
Block a user