(xmlContent)
| 6945 | |
| 6946 | // Check if any selected files are 3MF files |
| 6947 | const has3MFFiles = filePaths.some(fp => { |
| 6948 | const ext = path.extname(fp).toLowerCase(); |
| 6949 | // Handle zip entries - check the entry path extension |
| 6950 | if (fp.includes('::')) { |
| 6951 | const entryPath = fp.split('::')[1]; |
| 6952 | return path.extname(entryPath).toLowerCase() === '.3mf'; |
| 6953 | } |
| 6954 | return ext === '.3mf'; |
| 6955 | }); |
| 6956 | |
| 6957 | // Add "Pull Metadata" option for 3MF files |
| 6958 | if (has3MFFiles) { |
| 6959 | menuItems.push({ |
| 6960 | label: 'Pull Metadata', |
| 6961 | click: async () => { |
| 6962 | try { |
| 6963 | // Filter to only 3MF files |
| 6964 | const threeMFFiles = filePaths.filter(fp => { |
| 6965 | const ext = path.extname(fp).toLowerCase(); |
| 6966 | if (fp.includes('::')) { |
| 6967 | const entryPath = fp.split('::')[1]; |
| 6968 | return path.extname(entryPath).toLowerCase() === '.3mf'; |
| 6969 | } |
| 6970 | return ext === '.3mf'; |
| 6971 | }); |
| 6972 | |
| 6973 | if (threeMFFiles.length === 0) { |
| 6974 | return; |
| 6975 | } |
| 6976 | |
| 6977 | // Check existing models to see if any have data that will be overwritten |
| 6978 | const modelsWithData = []; |
| 6979 | for (const filePath of threeMFFiles) { |
| 6980 | const model = getModelByFilePath(filePath, { includeThumbnail: true }); |
| 6981 | if (model) { |
| 6982 | const hasData = (model.designer && model.designer.trim()) || |
| 6983 | (model.parentModel && model.parentModel.trim()) || |
| 6984 | (model.notes && model.notes.trim()) || |
| 6985 | (model.license && model.license.trim()); |
| 6986 | if (hasData) { |
| 6987 | modelsWithData.push({ |
| 6988 | filePath, |
| 6989 | fileName: model.fileName || path.basename(filePath), |
no test coverage detected