diff --git a/package-lock.json b/package-lock.json index 2e010a0..5e68e70 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,15 +17,15 @@ "@types/jest": "^29.5.11", "@types/node": "^20.11.5", "@types/vscode": "^1.85.0", - "@typescript-eslint/eslint-plugin": "^6.14.0", + "@typescript-eslint/eslint-plugin": "^6.19.1", "@typescript-eslint/parser": "^6.14.0", "@vscode/test-electron": "^2.3.8", "chai": "^4.3.10", - "eslint": "^8.55.0", + "eslint": "^8.56.0", "jest": "^29.7.0", "ts-jest": "^29.1.1", "ts-loader": "^9.5.1", - "typescript": "^5.3.2", + "typescript": "^5.3.3", "webpack": "^5.89.0", "webpack-cli": "^5.1.4" }, @@ -33,7 +33,7 @@ "vscode": "^1.60.0" }, "peerDependencies": { - "mcdev": "^6.0.0" + "mcdev": ">=5.2.0" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -977,9 +977,9 @@ } }, "node_modules/@eslint/js": { - "version": "8.55.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.55.0.tgz", - "integrity": "sha512-qQfo2mxH5yVom1kacMtZZJFVdW+E70mqHMJvVg6WTLo+VBuQJ4TojZlfWBjK0ve5BdEeNAVxOsl/nvNMpJOaJA==", + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.56.0.tgz", + "integrity": "sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -1720,16 +1720,16 @@ "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.14.0.tgz", - "integrity": "sha512-1ZJBykBCXaSHG94vMMKmiHoL0MhNHKSVlcHVYZNw+BKxufhqQVTOawNpwwI1P5nIFZ/4jLVop0mcY6mJJDFNaw==", + "version": "6.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.19.1.tgz", + "integrity": "sha512-roQScUGFruWod9CEyoV5KlCYrubC/fvG8/1zXuT0WTcxX87GnMMmnksMwSg99lo1xiKrBzw2icsJPMAw1OtKxg==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.14.0", - "@typescript-eslint/type-utils": "6.14.0", - "@typescript-eslint/utils": "6.14.0", - "@typescript-eslint/visitor-keys": "6.14.0", + "@typescript-eslint/scope-manager": "6.19.1", + "@typescript-eslint/type-utils": "6.19.1", + "@typescript-eslint/utils": "6.19.1", + "@typescript-eslint/visitor-keys": "6.19.1", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -1754,6 +1754,53 @@ } } }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/scope-manager": { + "version": "6.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.19.1.tgz", + "integrity": "sha512-4CdXYjKf6/6aKNMSly/BP4iCSOpvMmqtDzRtqFyyAae3z5kkqEjKndR5vDHL8rSuMIIWP8u4Mw4VxLyxZW6D5w==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.19.1", + "@typescript-eslint/visitor-keys": "6.19.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/types": { + "version": "6.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.19.1.tgz", + "integrity": "sha512-6+bk6FEtBhvfYvpHsDgAL3uo4BfvnTnoge5LrrCj2eJN8g3IJdLTD4B/jK3Q6vo4Ql/Hoip9I8aB6fF+6RfDqg==", + "dev": true, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/visitor-keys": { + "version": "6.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.19.1.tgz", + "integrity": "sha512-gkdtIO+xSO/SmI0W68DBg4u1KElmIUo3vXzgHyGPs6cxgB0sa3TlptRAAE0hUY1hM6FcDKEv7aIwiTGm76cXfQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.19.1", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, "node_modules/@typescript-eslint/parser": { "version": "6.14.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.14.0.tgz", @@ -1800,13 +1847,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.14.0.tgz", - "integrity": "sha512-x6OC9Q7HfYKqjnuNu5a7kffIYs3No30isapRBJl1iCHLitD8O0lFbRcVGiOcuyN837fqXzPZ1NS10maQzZMKqw==", + "version": "6.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.19.1.tgz", + "integrity": "sha512-0vdyld3ecfxJuddDjACUvlAeYNrHP/pDeQk2pWBR2ESeEzQhg52DF53AbI9QCBkYE23lgkhLCZNkHn2hEXXYIg==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "6.14.0", - "@typescript-eslint/utils": "6.14.0", + "@typescript-eslint/typescript-estree": "6.19.1", + "@typescript-eslint/utils": "6.19.1", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" }, @@ -1826,6 +1873,88 @@ } } }, + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": { + "version": "6.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.19.1.tgz", + "integrity": "sha512-6+bk6FEtBhvfYvpHsDgAL3uo4BfvnTnoge5LrrCj2eJN8g3IJdLTD4B/jK3Q6vo4Ql/Hoip9I8aB6fF+6RfDqg==", + "dev": true, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": { + "version": "6.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.19.1.tgz", + "integrity": "sha512-aFdAxuhzBFRWhy+H20nYu19+Km+gFfwNO4TEqyszkMcgBDYQjmPJ61erHxuT2ESJXhlhrO7I5EFIlZ+qGR8oVA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.19.1", + "@typescript-eslint/visitor-keys": "6.19.1", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "9.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/visitor-keys": { + "version": "6.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.19.1.tgz", + "integrity": "sha512-gkdtIO+xSO/SmI0W68DBg4u1KElmIUo3vXzgHyGPs6cxgB0sa3TlptRAAE0hUY1hM6FcDKEv7aIwiTGm76cXfQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.19.1", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/@typescript-eslint/types": { "version": "6.14.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.14.0.tgz", @@ -1867,17 +1996,17 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.14.0.tgz", - "integrity": "sha512-XwRTnbvRr7Ey9a1NT6jqdKX8y/atWG+8fAIu3z73HSP8h06i3r/ClMhmaF/RGWGW1tHJEwij1uEg2GbEmPYvYg==", + "version": "6.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.19.1.tgz", + "integrity": "sha512-JvjfEZuP5WoMqwh9SPAPDSHSg9FBHHGhjPugSRxu5jMfjvBpq5/sGTD+9M9aQ5sh6iJ8AY/Kk/oUYVEMAPwi7w==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.14.0", - "@typescript-eslint/types": "6.14.0", - "@typescript-eslint/typescript-estree": "6.14.0", + "@typescript-eslint/scope-manager": "6.19.1", + "@typescript-eslint/types": "6.19.1", + "@typescript-eslint/typescript-estree": "6.19.1", "semver": "^7.5.4" }, "engines": { @@ -1891,6 +2020,105 @@ "eslint": "^7.0.0 || ^8.0.0" } }, + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/scope-manager": { + "version": "6.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.19.1.tgz", + "integrity": "sha512-4CdXYjKf6/6aKNMSly/BP4iCSOpvMmqtDzRtqFyyAae3z5kkqEjKndR5vDHL8rSuMIIWP8u4Mw4VxLyxZW6D5w==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.19.1", + "@typescript-eslint/visitor-keys": "6.19.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/types": { + "version": "6.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.19.1.tgz", + "integrity": "sha512-6+bk6FEtBhvfYvpHsDgAL3uo4BfvnTnoge5LrrCj2eJN8g3IJdLTD4B/jK3Q6vo4Ql/Hoip9I8aB6fF+6RfDqg==", + "dev": true, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": { + "version": "6.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.19.1.tgz", + "integrity": "sha512-aFdAxuhzBFRWhy+H20nYu19+Km+gFfwNO4TEqyszkMcgBDYQjmPJ61erHxuT2ESJXhlhrO7I5EFIlZ+qGR8oVA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.19.1", + "@typescript-eslint/visitor-keys": "6.19.1", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "9.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/visitor-keys": { + "version": "6.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.19.1.tgz", + "integrity": "sha512-gkdtIO+xSO/SmI0W68DBg4u1KElmIUo3vXzgHyGPs6cxgB0sa3TlptRAAE0hUY1hM6FcDKEv7aIwiTGm76cXfQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.19.1", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/@typescript-eslint/visitor-keys": { "version": "6.14.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.14.0.tgz", @@ -3807,15 +4035,15 @@ } }, "node_modules/eslint": { - "version": "8.55.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.55.0.tgz", - "integrity": "sha512-iyUUAM0PCKj5QpwGfmCAG9XXbZCWsqP/eWAWrG/W0umvjuLRBECwSFdt+rCntju0xEH7teIABPwXpahftIaTdA==", + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.56.0.tgz", + "integrity": "sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.55.0", + "@eslint/js": "8.56.0", "@humanwhocodes/config-array": "^0.11.13", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", @@ -8448,9 +8676,9 @@ } }, "node_modules/typescript": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.2.tgz", - "integrity": "sha512-6l+RyNy7oAHDfxC4FzSJcz9vnjTKxrLpDG5M2Vu4SHRVNg6xzqZp6LYSR9zjqQTu8DU/f5xwxUdADOkbrIX2gQ==", + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", + "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", "dev": true, "bin": { "tsc": "bin/tsc", diff --git a/package.json b/package.json index 139ea84..698cb97 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "Accenture Salesforce Marketing Cloud DevTools Vscode Extension", "version": "0.0.1", "peerDependencies": { - "mcdev": "^6.0.0" + "mcdev": ">=5.2.0" }, "repository": { "type": "git", @@ -29,6 +29,10 @@ { "command": "sfmc-devtools-vscext.devtoolsCMDeploy", "title": "mcdev: Deploy" + }, + { + "command": "sfmc-devtools-vscext.devtoolsCMCopyToBU", + "title": "mcdev: Copy to Business Unit" } ], "menus": { @@ -39,8 +43,35 @@ "group": "devtools" }, { - "when": "resourcePath =~ /deploy/ || (resourcePath =~ /retrieve/ && (resourceLangId == json || resourceLangId == html || resourceLangId == sql || resourceLangId == markdown))", + "when": "resourcePath =~ /deploy/ || (resourcePath =~ /retrieve/ && (resourceExtname == '.json' || resourceExtname == '.html' || resourceExtname == '.sql' || resourceLangId == 'markdown'))", + "command": "sfmc-devtools-vscext.devtoolsCMDeploy", + "group": "devtools" + }, + { + "when": "(resourcePath =~ /retrieve/ || resourcePath =~ /deploy/) && resourceFilename != 'retrieve' && resourceFilename != 'deploy'", + "command": "sfmc-devtools-vscext.devtoolsCMCopyToBU", + "group": "devtools" + } + ], + "commandPalette": [ + { + "command": "sfmc-devtools-vscext.devtoolsCMRetrieve", + "when": "false" + }, + { "command": "sfmc-devtools-vscext.devtoolsCMDeploy", + "when": "false" + } + ], + "editor/title/context": [ + { + "when": "resourcePath =~ /retrieve/", + "command": "sfmc-devtools-vscext.devtoolsCMRetrieve", + "group": "devtools" + }, + { + "when": "resourcePath =~ /deploy/ || (resourcePath =~ /retrieve/ && (resourceLangId == json || resourceLangId == html || resourceLangId == sql || resourceLangId == markdown || resourceLangId == ssjs))", + "command": "sfmc-devtools-vscext.devtoolsCMDeploy", "group": "devtools" } ] @@ -61,15 +92,15 @@ "@types/jest": "^29.5.11", "@types/node": "^20.11.5", "@types/vscode": "^1.85.0", - "@typescript-eslint/eslint-plugin": "^6.14.0", + "@typescript-eslint/eslint-plugin": "^6.19.1", "@typescript-eslint/parser": "^6.14.0", "@vscode/test-electron": "^2.3.8", "chai": "^4.3.10", - "eslint": "^8.55.0", + "eslint": "^8.56.0", "jest": "^29.7.0", "ts-jest": "^29.1.1", "ts-loader": "^9.5.1", - "typescript": "^5.3.2", + "typescript": "^5.3.3", "webpack": "^5.89.0", "webpack-cli": "^5.1.4" }, @@ -78,4 +109,4 @@ "@vscode/codicons": "^0.0.35", "winston": "^3.11.0" } -} +} \ No newline at end of file diff --git a/src/config/containers.config.ts b/src/config/containers.config.ts index 9dff48b..ae99a28 100644 --- a/src/config/containers.config.ts +++ b/src/config/containers.config.ts @@ -12,9 +12,10 @@ export const containersConfig: { statusBarDevToolsInitializeTitle: string, statusBarDevToolsInitializeCommand: string, contextMenuRetrieveCommand: string, - contextMenuDeployCommand: string + contextMenuDeployCommand: string, + contextMenuCopyToBUCommand: string } = { - statusBarDevToolsName: "devtoolsmcdev", + statusBarDevToolsName: "mcdev", statusBarDevToolsTitle: "mcdev", statusBarDevToolsCommand: "sfmc-devtools-vscext.devtoolsSBMcdev", statusBarDevToolsCredentialBUName: "devtoolscredentialbu", @@ -27,5 +28,6 @@ export const containersConfig: { statusBarDevToolsInitializeTitle: "Initialize", statusBarDevToolsInitializeCommand: "sfmc-devtools-vscext.devtoolsSBInitialize", contextMenuRetrieveCommand: "sfmc-devtools-vscext.devtoolsCMRetrieve", - contextMenuDeployCommand: "sfmc-devtools-vscext.devtoolsCMDeploy" + contextMenuDeployCommand: "sfmc-devtools-vscext.devtoolsCMDeploy", + contextMenuCopyToBUCommand: "sfmc-devtools-vscext.devtoolsCMCopyToBU" }; \ No newline at end of file diff --git a/src/config/main.config.ts b/src/config/main.config.ts index 62af963..78c8a1f 100644 --- a/src/config/main.config.ts +++ b/src/config/main.config.ts @@ -1,6 +1,7 @@ export const mainConfig: { credentialsFilename: string, requiredFiles: string[], + fileExtensions: string[], allPlaceholder: string, messages: { selectedCredentialsBU: string, @@ -12,15 +13,17 @@ export const mainConfig: { initiatingDevTools: string, runningCommand: string, successRunningCommand: string, - failureRunningCommand: string + failureRunningCommand: string, + } } = { credentialsFilename: ".mcdevrc.json", requiredFiles: [".mcdevrc.json", ".mcdev-auth.json"], + fileExtensions: ["meta.json", "meta.sql", "meta.html", "meta.ssjs", "doc.md"], allPlaceholder: "*All*", messages: { - selectedCredentialsBU: "Please select a Credential/BU before running the command", - selectCredential: "Select all or one of the credentials below...", + selectedCredentialsBU: "Select a Credential/BU before running the command", + selectCredential: "Select one of the credentials below...", selectBusinessUnit: "Select all or one of the business units below...", selectCommandType: "Select one DevTools command type...", selectCommand: "Select one DevTools Command...", diff --git a/src/devtools/commands/DevToolsAdminCommands.ts b/src/devtools/commands/DevToolsAdminCommands.ts index 866c543..f39da1e 100644 --- a/src/devtools/commands/DevToolsAdminCommands.ts +++ b/src/devtools/commands/DevToolsAdminCommands.ts @@ -9,10 +9,10 @@ class DevToolsAdminCommands extends DevToolsCommands { private commandMethods: { [key: string]: ( config: DevToolsCommandSetting, - args: {[key: string]: any }, + args: {[key: string]: string | string[] | boolean }, path: string, - handleResult: (result?: any) => void) - => void + commandHandlers: { [key: string]: (args?: any) => void } + ) => void } = {}; constructor(){ super(); @@ -29,12 +29,12 @@ class DevToolsAdminCommands extends DevToolsCommands { commandConfig, commandArgs, commandPath, - commandResultHandler + commandHandlers }: DevToolsCommandRunner = commandRunner; log("debug", `Running DevTools Admin Command for id '${commandId}'.`); if(commandId in this.commandMethods){ - this.commandMethods[commandId](commandConfig, commandArgs, commandPath, commandResultHandler); + this.commandMethods[commandId](commandConfig, commandArgs, commandPath, commandHandlers); }else{ log("error", `DevTools Admin Command method for id '${commandId}' is not implemented.`); } @@ -42,7 +42,12 @@ class DevToolsAdminCommands extends DevToolsCommands { setMetadataTypes(_: SupportedMetadataTypes[]): void {} - async init(config: DevToolsCommandSetting, _: {[key: string]: any}, path: string, handleResult: (result?: any) => void){ + async init( + config: DevToolsCommandSetting, + _: {[key: string]: string | string[] | boolean}, + path: string, + { handleCommandResult }: { [key: string]: (args?: any) => void }){ + log("info", `Running DevTools Admin Command: Init...`); const initArgs: {[key: string]: string } = {}; if("command" in config && config.command){ @@ -67,39 +72,49 @@ class DevToolsAdminCommands extends DevToolsCommands { // Checks if the command is still missing so required parameter if(this.hasPlaceholders(commandConfigured)){ log("debug", `Required Parameters missing from Init command: ${commandConfigured}`); + handleCommandResult({ success: false, cancelled: true }); return; } log("debug", `Init final command: ${commandConfigured}`); - await this.executeCommand(commandConfigured, path, true); - handleResult(); + const commandResult: string | number = await this.executeCommand(commandConfigured, path, true); + if(typeof(commandResult) === "number"){ + handleCommandResult({ success: commandResult === 0, cancelled: false }); + } }else{ log("error", "DevToolsAdminCommand_Init: Command is empty or missing the configuration."); } } - async explainTypes(config: DevToolsCommandSetting, args: {[key: string]: any }, path: string, handleResult: (result: any) => void){ - try{ - log("info", `Running DevTools Admin Command: Explain Types...`); - if("command" in config && config.command){ - const commandConfigured: string | undefined = - await this.configureCommandWithParameters( - config, - args, - [] - ); - log("debug", `Explain types final command: ${commandConfigured}`); - const commandResult = await this.executeCommand( - commandConfigured, - path, - !("json" in args)); - handleResult(commandResult); - }else{ - log("error", "DevToolsAdminCommand_explainTypes: Command is empty or missing the configuration."); + async explainTypes( + config: DevToolsCommandSetting, + args: {[key: string]: string | string[] | boolean }, + path: string, + { handleCommandResult }: { [key: string]: (args?: any) => void }){ + + try{ + log("info", `Running DevTools Admin Command: Explain Types...`); + if("command" in config && config.command){ + const commandConfigured: string | undefined = + await this.configureCommandWithParameters( + config, + args, + [] + ); + log("debug", `Explain types final command: ${commandConfigured}`); + const commandResult: string | number = await this.executeCommand( + commandConfigured, + path, + !("json" in args)); + if(typeof(commandResult) === "string"){ + handleCommandResult({ success: commandResult.length > 0, data: commandResult}); + } + }else{ + log("error", "DevToolsAdminCommand_explainTypes: Command is empty or missing some configuration."); + } + }catch(error){ + log("error", `DevToolsAdminCommand_explainTypes Error: ${error}`); } - }catch(error){ - log("error", `DevToolsAdminCommand_explainTypes Error: ${error}`); - } } } diff --git a/src/devtools/commands/DevToolsCommands.ts b/src/devtools/commands/DevToolsCommands.ts index 04227a9..918af25 100644 --- a/src/devtools/commands/DevToolsCommands.ts +++ b/src/devtools/commands/DevToolsCommands.ts @@ -30,16 +30,10 @@ abstract class DevToolsCommands { resolve(code); } if(error){ - log("error", - `[DevToolsCommands_executeCommand] Exit Code: ${error}` - ); + log("error", `[DevToolsCommands_executeCommand] Exit Code: ${error}`); } if(output){ - if(showOnTerminal){ - log("info", output); - }else{ - resolve(output); - } + showOnTerminal ? log("info", output) : resolve(output); } }, }); @@ -48,7 +42,7 @@ abstract class DevToolsCommands { async configureCommandWithParameters( config: DevToolsCommandSetting, - args: {[key: string]: string }, + args: {[key: string]: string | string[] | boolean }, mdTypes: SupportedMetadataTypes[]): Promise { log("debug", `ConfigureCommandWithParameters: ${JSON.stringify(config)}`); @@ -57,7 +51,7 @@ abstract class DevToolsCommands { if("requiredParams" in config && config.requiredParams.length){ for(const param of config.requiredParams){ if(param in args && args[param]){ - command = command.replace(`{{${param}}}`, args[param]); + command = command.replace(`{{${param}}}`, args[param] as string); }else{ // Requests user if(param.toLowerCase() === "mdtypes" && mdTypes.length){ @@ -79,7 +73,7 @@ abstract class DevToolsCommands { ? `--${param}` : ""; } - command = command.replace(`{{${param}}}`, param in args ? args[param] : ""); + command = command.replace(`{{${param}}}`, param in args ? args[param] as string : ""); }); } return command; @@ -145,28 +139,35 @@ abstract class DevToolsCommands { "etypes", path, { json: true }, - ((result: any) => { - // Parses the list of supported mtdata types - const parsedResult: SupportedMetadataTypes[] = JSON.parse(result); - if(parsedResult && parsedResult.length){ - // Sends the supported mtdata types to each DevTools Command - Object.keys(this.commandMap).forEach((key: string) => { - const devToolCommand: DevToolsCommands = - this.commandMap[key]; - devToolCommand.setMetadataTypes(parsedResult); - }); - }else{ - log("error", "DevToolsCommands_init: Failed to parse supported metadata type result."); + { + handleCommandResult: ({ success, data }: { success: boolean, data: string}) => { + if(success){ + // Parses the list of supported mtdata types + const parsedResult: SupportedMetadataTypes[] = JSON.parse(data); + if(parsedResult && parsedResult.length){ + // Sends the supported mtdata types to each DevTools Command + Object.keys(this.commandMap).forEach((key: string) => { + const devToolCommand: DevToolsCommands = + this.commandMap[key]; + devToolCommand.setMetadataTypes(parsedResult); + }); + }else{ + log("error", "DevToolsCommands_init: Failed to parse supported metadata type result."); + } + }else{ + log("error", "DevToolsCommands_init: Admin Command etypes failed."); + } + } } - })); + ); } static async runCommand( - typeId: string, + typeId: string | null, commandId: string, commandPath: string, - args: any, - handleResult: (result: any) => void) { + args: {[key: string]: string | string[] | boolean}, + commandHandlers: {[key: string]: (args?: any) => void}){ // When the DevTools command type is unknown to the application if(!typeId && commandId){ const [{ id }]: { id: string }[] = @@ -186,7 +187,7 @@ abstract class DevToolsCommands { } if(this.commandMap){ - if(typeId in this.commandMap){ + if(typeId && typeId in this.commandMap){ const [ commandConfig ]: DevToolsCommandSetting[] = this.getCommandsListByType(typeId) .filter((commandSetting: DevToolsCommandSetting) => commandSetting.id === commandId); @@ -198,7 +199,7 @@ abstract class DevToolsCommands { commandConfig, commandArgs: args, commandPath, - commandResultHandler: handleResult + commandHandlers: commandHandlers }); return; } diff --git a/src/devtools/commands/DevToolsStandardCommands.ts b/src/devtools/commands/DevToolsStandardCommands.ts index c728a04..be4f2b3 100644 --- a/src/devtools/commands/DevToolsStandardCommands.ts +++ b/src/devtools/commands/DevToolsStandardCommands.ts @@ -9,10 +9,10 @@ class DevToolsStandardCommands extends DevToolsCommands { private commandMethods: { [key: string]: ( config: DevToolsCommandSetting, - args: {[key: string]: any }, + args: {[key: string]: string | string[] | boolean }, path: string, - handleResult: (result: any) => void) - => void + commandHandlers: { [key: string]: (args?: any) => void } + ) => void } = {}; private metadataTypes: SupportedMetadataTypes[] = []; constructor(){ @@ -30,12 +30,12 @@ class DevToolsStandardCommands extends DevToolsCommands { commandConfig, commandArgs, commandPath, - commandResultHandler + commandHandlers }: DevToolsCommandRunner = commandRunner; log("debug", `Running DevTools Standard Command for id '${commandId}'.`); if(commandId in this.commandMethods){ - this.commandMethods[commandId](commandConfig, commandArgs, commandPath, commandResultHandler); + this.commandMethods[commandId](commandConfig, commandArgs, commandPath, commandHandlers); }else{ log("error", `DevTools Standard Command method for id '${commandId}' is not implemented.`); } @@ -45,7 +45,12 @@ class DevToolsStandardCommands extends DevToolsCommands { this.metadataTypes = mdTypes; } - async retrieve(config: DevToolsCommandSetting, args: {[key: string]: string }, path: string, handleResult: (result: any) => void){ + async retrieve( + config: DevToolsCommandSetting, + args: {[key: string]: string | string[] | boolean }, + path: string, + { handleCommandResult, loadingNotification }: { [key: string]: (args?: any) => void }){ + log("info", `Running DevTools Standard Command: Retrieve...`); if("command" in config && config.command){ // Gets that metadata types that are supported for retrieve @@ -63,18 +68,27 @@ class DevToolsStandardCommands extends DevToolsCommands { // Checks if the command is still missing so required parameter if(this.hasPlaceholders(commandConfigured)){ log("debug", `Required Parameters missing from Retrieve command: ${commandConfigured}`); + handleCommandResult({ success: false, cancelled: true }); return; } log("debug", `Retrieve Command configured: ${commandConfigured}`); - const commandResult: Promise = this.executeCommand(commandConfigured, path, true); - handleResult(commandResult); + loadingNotification(); + const commandResult: string | number = await this.executeCommand(commandConfigured, path, true); + if(typeof(commandResult) === "number"){ + handleCommandResult({ success: commandResult === 0, cancelled: false }); + } }else{ log("error", "DevToolsStandardCommand_retrieve: Command is empty or missing the configuration."); } } - async deploy(config: DevToolsCommandSetting, args: {[key: string]: any }, path: string, handleResult: (result: any) => void){ + async deploy( + config: DevToolsCommandSetting, + args: {[key: string]: string | string[] | boolean }, + path: string, + { handleCommandResult, loadingNotification }: { [key: string]: (args?: any) => void }){ + log("info", `Running DevTools Standard Command: Deploy...`); if("command" in config && config.command){ // Gets that metadata types that are supported for deploy @@ -92,12 +106,16 @@ class DevToolsStandardCommands extends DevToolsCommands { // Checks if the command is still missing so required parameter if(this.hasPlaceholders(commandConfigured)){ log("debug", `Required Parameters missing from Deploy command: ${commandConfigured}`); + handleCommandResult({ success: false, cancelled: true }); return; } log("debug", `Deploy Command configured: ${commandConfigured}`); - const commandResult: Promise = this.executeCommand(commandConfigured, path, true); - handleResult(commandResult); + loadingNotification(); + const commandResult: string | number = await this.executeCommand(commandConfigured, path, true); + if(typeof(commandResult) === "number"){ + handleCommandResult({ success: commandResult === 0, cancelled: false }); + } }else{ log("error", "DevToolsStandardCommand_deploy: Command is empty or missing the configuration."); } diff --git a/src/devtools/commands/commands.config.json b/src/devtools/commands/commands.config.json index b9c3dca..39abc9b 100644 --- a/src/devtools/commands/commands.config.json +++ b/src/devtools/commands/commands.config.json @@ -23,7 +23,7 @@ { "id":"etypes", "title": "Explain Types", - "command": "mcdev explainTypes {{json}}", + "command": "mcdev explainTypes {{json}} --skipInteraction", "requiredParams": [], "optionalParams": ["json"], "description": "Explains metadata types that can be retrieved.", @@ -40,7 +40,7 @@ { "id":"retrieve", "title": "Retrieve", - "command": "mcdev retrieve {{bu}} {{mdtypes}} {{key}}", + "command": "mcdev retrieve {{bu}} {{mdtypes}} {{key}} --skipInteraction", "requiredParams": ["bu", "mdtypes"], "optionalParams": ["key"], "description": "Retrieves metadata of a business unit.", @@ -49,7 +49,7 @@ { "id":"deploy", "title": "Deploy", - "command": "mcdev deploy {{bu}} {{mdtypes}} {{key}} {{fromRetrieve}}", + "command": "mcdev deploy {{bu}} {{mdtypes}} {{key}} {{fromRetrieve}} --skipInteraction", "requiredParams": ["bu", "mdtypes"], "optionalParams": ["key", "fromRetrieve"], "description": "Deploys local metadata to a business unit.", @@ -73,10 +73,10 @@ "isAvailable": false, "requireCredentials": false, "commands": [ - {"id":"rtemp", "title": "Retrieve As Template", "command": "mcdev delete", "requiredParams": [], "optionalParams": [], "description": "Retrieves a specific metadata file by name from the server for templating.", "isAvailable": false}, - {"id":"btemp", "title": "Build Template", "command": "mcdev delete", "requiredParams": [], "optionalParams": [], "description": "Builds a template out of a specific metadata file already in your retrieve folder.", "isAvailable": false}, - {"id":"bdef", "title": "Build Definition", "command": "mcdev delete", "requiredParams": [], "optionalParams": [], "description": "Builds metadata definition based on template.", "isAvailable": false}, - {"id":"bdefbulk", "title": "Build Definition Bulk", "command": "mcdev delete", "requiredParams": [], "optionalParams": [], "description": "Builds metadata definition based on template en bulk.", "isAvailable": false} + {"id":"rtemp", "title": "Retrieve As Template", "command": "", "requiredParams": [], "optionalParams": [], "description": "Retrieves a specific metadata file by name from the server for templating.", "isAvailable": false}, + {"id":"btemp", "title": "Build Template", "command": "", "requiredParams": [], "optionalParams": [], "description": "Builds a template out of a specific metadata file already in your retrieve folder.", "isAvailable": false}, + {"id":"bdef", "title": "Build Definition", "command": "", "requiredParams": [], "optionalParams": [], "description": "Builds metadata definition based on template.", "isAvailable": false}, + {"id":"bdefbulk", "title": "Build Definition Bulk", "command": "", "requiredParams": [], "optionalParams": [], "description": "Builds metadata definition based on template en bulk.", "isAvailable": false} ] } } \ No newline at end of file diff --git a/src/devtools/containers.ts b/src/devtools/containers.ts index 64dd305..10b9486 100644 --- a/src/devtools/containers.ts +++ b/src/devtools/containers.ts @@ -2,7 +2,7 @@ import { containersConfig } from "../config/containers.config"; import { devtoolsMain } from "./main"; import { ExtensionContext, editorContext } from "../editor/context"; import { StatusBarItem, editorContainers } from "../editor/containers"; -import { editorCommands } from "../editor/commands"; +import { Uri, editorCommands } from "../editor/commands"; import { editorWorkspace } from "../editor/workspace"; import { log } from "../editor/output"; @@ -16,7 +16,7 @@ enum StatusBarIcon { let statusBarContainer: StatusBarItem | StatusBarItem[]; function activateStatusBar(/*isDevtoolsProject: boolean, commandPrefix: string*/): void { - log("info", "Activating Status Bar Options..."); + log("debug", "Activating Status Bar Options..."); const { subscriptions }: ExtensionContext = editorContext.get(); // Gets the command prefix for @@ -117,7 +117,7 @@ function activateStatusBar(/*isDevtoolsProject: boolean, commandPrefix: string*/ function modifyStatusBar(statusBarId: string, action: keyof typeof StatusBarIcon): void { if(statusBarContainer && Array.isArray(statusBarContainer)){ const [ statusBar ] = statusBarContainer.filter( - (sb: StatusBarItem) => sb.name === `devtools${statusBarId}` + (sb: StatusBarItem) => sb.name?.toLowerCase() === `${statusBarId.toLowerCase()}` ); if(statusBar){ @@ -168,12 +168,14 @@ function getCredentialsBUName(commandPrefix: string): string | undefined { function activateContextMenuCommands(){ [ containersConfig.contextMenuRetrieveCommand, - containersConfig.contextMenuDeployCommand + containersConfig.contextMenuDeployCommand, + containersConfig.contextMenuCopyToBUCommand ].forEach((command: string) => editorCommands.registerCommand({ command, - callbackAction: (_, ...files: any[]) => { - if(files.length && Array.isArray(files[0])){ - const filesPath: string[] = editorWorkspace.getFilesURIPath(files[0]); + callbackAction: (file: Uri, multipleFiles: Uri[]) => { + const files: Uri[] = !Array.isArray(multipleFiles) ? [file] : multipleFiles; + if(files.length){ + const filesPath: string[] = editorWorkspace.getFilesURIPath(files); const [ __, key ]: string[] = command.split(".devtools"); return devtoolsMain.handleContextMenuActions(key, filesPath); }else{ @@ -185,11 +187,12 @@ function activateContextMenuCommands(){ })); } -export { StatusBarIcon }; -export const devtoolsContainers = { +const devtoolsContainers = { activateStatusBar, modifyStatusBar, isCredentialBUSelected, getCredentialsBUName, activateContextMenuCommands -}; \ No newline at end of file +}; + +export { StatusBarIcon, devtoolsContainers }; \ No newline at end of file diff --git a/src/devtools/main.ts b/src/devtools/main.ts index ce97d73..4ff6a19 100644 --- a/src/devtools/main.ts +++ b/src/devtools/main.ts @@ -11,6 +11,7 @@ import { editorWorkspace } from "../editor/workspace"; import { editorOutput, log } from "../editor/output"; import { InstallDevToolsResponseOptions } from "../config/installer.config"; import { lib } from "../shared/utils/lib"; +import { file } from "../shared/utils/file"; async function initDevToolsExtension(): Promise{ @@ -40,14 +41,14 @@ async function initDevToolsExtension(): Promise{ } async function isADevToolsProject(projectName?: string): Promise { - log("info", "Checking if folder is a SFMC DevTools project..."); + log("debug", "Checking if folder is a SFMC DevTools project..."); log("debug", `DevTools files: [${mainConfig.requiredFiles}]`); const findMcdevFiles: boolean[] = await Promise.all(mainConfig.requiredFiles .map(async(filename: string) => editorWorkspace.isFileInFolder( `${projectName || '' }${filename}` ))); - log("info", + log("debug", `Folder ${findMcdevFiles.every((result: boolean) => result === true) ? 'is' : 'is not'} a SFMC DevTools project.` ); return findMcdevFiles.every((result: boolean) => result === true); @@ -127,6 +128,9 @@ function handleContextMenuActions(action: string, selectedFiles: string[]): void case "cmdeploy": handleDevToolsCMCommand("deploy", selectedFiles); break; + case "cmcopytobu": + handleCopyToBuCMCommand(selectedFiles); + break; default: log("error", `main_handleContextMenuActions: Invalid Context Menu Action '${action}'`); } @@ -294,7 +298,7 @@ async function handleDevToolsSBCommand(): Promise{ selectedCommandOption.id, editorWorkspace.getWorkspaceURIPath(), { bu: selectedCredentialBU.replace(mainConfig.allPlaceholder, "'*'") }, - (result: any) => log("info", result) + { handleCommandResult: (result: any) => log("info", result) } ); }else{ log("error", @@ -319,7 +323,7 @@ async function handleDevToolsSBCommand(): Promise{ selectedCommandOption.id, editorWorkspace.getWorkspaceURIPath(), {}, - (result: any) => log("info", result) + { handleCommandResult: (result: any) => log("info", result) } ); } } @@ -339,10 +343,18 @@ async function initialize(): Promise{ if(userResponse && InstallDevToolsResponseOptions[userResponse as keyof typeof InstallDevToolsResponseOptions]){ log("info", "Initializing SFMC DevTools project..."); - DevToolsCommands.runCommand("", "init", editorWorkspace.getWorkspaceURIPath(), [], () => { - log("info", "Reloading VSCode workspace window..."); - lib.waitTime(5000, () => editorWorkspace.reloadWorkspace()); - }); + DevToolsCommands.runCommand( + null, + "init", + editorWorkspace.getWorkspaceURIPath(), + {}, + { + handleCommandResult: () => { + log("info", "Reloading VSCode workspace window..."); + lib.waitTime(5000, () => editorWorkspace.reloadWorkspace()); + } + } + ); } } @@ -368,7 +380,7 @@ async function handleDevToolsCMCommand(action: string, selectedPaths: string[]): // Removes duplicate files (eg. some files have the same name with md and json) if(filesType.length){ filesType = lib.removeDuplicates( - lib.removeExtensionFromFile(filesType) + lib.removeExtensionFromFile(filesType, mainConfig.fileExtensions) ) as string[]; } @@ -408,14 +420,14 @@ async function handleDevToolsCMCommand(action: string, selectedPaths: string[]): log("debug", `Project path: ${projectPath}`); log("debug", `Context Menu path: ${cmPath}`); - log("info", `Project ${workspaceFolderPath === projectPath ? 'is': 'is not'} the workspace folder.`); + log("debug", `Project ${workspaceFolderPath === projectPath ? 'is': 'is not'} the workspace folder.`); // Check if context menu being triggered is from outside of the workspace folder if(workspaceFolderPath !== projectPath){ // Check if folder is a DevTools project const isSubFolderDevToolsProject: boolean = await isADevToolsProject( projectName + "/" ); - log("info", + log("debug", `SubFolder project '${projectPath}' ${ isSubFolderDevToolsProject ? 'is': 'is not'} a DevTools Project.` ); if(!isSubFolderDevToolsProject){ @@ -461,6 +473,9 @@ async function handleDevToolsCMCommand(action: string, selectedPaths: string[]): // if user selects a file inside a subfolder of asset // the key will be the name of the file keys = assetKey ? [ assetKey ] : []; + }else if(type === "folder" && keys.length){ + // Nested folders are not supported as keys for the metadata type folder + keys = []; } key = keys.length ? keys[0] : ""; @@ -502,7 +517,7 @@ async function handleDevToolsCMCommand(action: string, selectedPaths: string[]): for(const optionType of [filesType, folderType]){ if(optionType.length){ - const projectMap: {[key: string]: ProjectConfig} = + const projectMap: {[key: string]: ProjectConfig} = await configureArgsProject(action, optionType); await Promise.all(Object.keys(projectMap).map(async (projName: string) => { log("debug", `Running DevTools Command for project ${projName}`); @@ -524,29 +539,25 @@ async function handleDevToolsCMCommand(action: string, selectedPaths: string[]): await editorInput.handleInProgressMessage( "Notification", (progress) => { - progress.report({message: mainConfig.messages.runningCommand}); return new Promise(resolve => DevToolsCommands.runCommand( - "", + null, action, path, dtArgs, - async(dataResult: Promise) => - dataResult - .then((res: number) => { - devtoolsContainers.modifyStatusBar( - "mcdev", - !res ? 'success' : 'error' - ); - editorInput.handleShowNotificationMessage( - !res - ? 'info' - : 'error', - !res - ? mainConfig.messages.successRunningCommand - : mainConfig.messages.failureRunningCommand, - ); - resolve(); - }) + { + loadingNotification: () => progress.report({message: mainConfig.messages.runningCommand}), + handleCommandResult: ({ success, cancelled }: { success: boolean, cancelled: boolean }) => { + if(!cancelled){ + editorInput.handleShowNotificationMessage( + success ? "info" : "error", + success ? mainConfig.messages.successRunningCommand : + mainConfig.messages.failureRunningCommand + ); + devtoolsContainers.modifyStatusBar( "mcdev", success ? "success" : "error"); + resolve(); + } + } + } )); } ); @@ -559,6 +570,99 @@ async function handleDevToolsCMCommand(action: string, selectedPaths: string[]): } } +async function handleCopyToBuCMCommand(selectedPaths: string[]){ + try{ + const credentials: {[key: string]: string[]} | undefined = await getCredentialsBU(); + if(credentials){ + const instances: string[] = Object.keys(credentials); + const singleInstance: boolean = instances.length === 1; + let selectedInstance: string = singleInstance ? instances[0] : ""; + + if(!singleInstance){ + const instanceOptions: InputOptionsSettings[] = + instances.map((instance: string) => ({ id: instance, label: instance, detail: "" })); + const instanceResponse: InputOptionsSettings | undefined = + await editorInput.handleQuickPickSelection( + instanceOptions, + mainConfig.messages.selectCredential, + false + ) as InputOptionsSettings; + if(instanceResponse){ + selectedInstance = instanceResponse.id; + } + } + + if(selectedInstance){ + const buOptionsList: InputOptionsSettings[] = + credentials[selectedInstance].map((businessUnit: string) => ({ id: businessUnit, label: businessUnit, detail: "" })); + const buOptions: InputOptionsSettings[] | undefined = + await editorInput.handleQuickPickSelection(buOptionsList, mainConfig.messages.selectBusinessUnit, true) as InputOptionsSettings[]; + + if(buOptions){ + + type FileCopyConfig = { sourceFilePath: string; targetFilePath: string; }; + const buSelected: string[] = buOptions.map((bu: InputOptionsSettings) => bu.id); + + const filePathsConfigured: (FileCopyConfig | undefined)[] = + selectedPaths.map((path: string) => { + const [ _, fileInstancePath]: string[] = path.split(/\/retrieve\/|\/deploy\//); + + if(fileInstancePath){ + const [ _, businessUnit ]: string[] = fileInstancePath.split("/"); + + if(businessUnit){ + let paths: string[] = []; + + if(file.isPathADirectory(path)){ + paths = [...paths, path]; + }else{ + const [ currentFileExt ]: string[] = + mainConfig.fileExtensions.filter((fileExt: string) => path.endsWith(fileExt)); + if(currentFileExt){ + paths = [ + ...paths, + ...file.fileExists( + mainConfig.fileExtensions.map((fileExtension: string) => + path.replace(currentFileExt, fileExtension) + ) + ) + ]; + } + } + + return buSelected + .filter((buSelected: string) => buSelected !== businessUnit) + .map((buSelected: string) => + paths.map((keyFilePath: string) => + ({ + sourceFilePath: keyFilePath, + targetFilePath: keyFilePath + .replace(/\/retrieve\//, "/deploy/") + .replace(businessUnit, buSelected) + })) + ) + .flat(); + } + } + return undefined; + }) + .filter((filePath: FileCopyConfig[] | undefined) => filePath !== undefined) + .flat(); + + file.copyFile(filePathsConfigured as FileCopyConfig[], (error: any) => { + if(error !== null){ + log("error", `[main_handleCopyToBuCMCommand] Failed to copy file: ${error}`); + } + }); + } + } + }else{ + log("error", `[main_handleCopyToBuCMCommand] Failed to retrieve DevTools credentials.`); + } + }catch(error){ + log("error", `[main_handleCopyToBuCMCommand] Error: ${error}`); + } +} export const devtoolsMain = { initDevToolsExtension, diff --git a/src/editor/commands.ts b/src/editor/commands.ts index 68eb7e8..7efcce9 100644 --- a/src/editor/commands.ts +++ b/src/editor/commands.ts @@ -1,8 +1,8 @@ -import { commands } from "vscode"; +import { commands, Uri } from "vscode"; interface CommandRegister { command: string, - callbackAction: (reg: { path: string }) => void + callbackAction: (file: Uri, files: Uri[]) => void } function registerCommand(register: CommandRegister | CommandRegister[]): void { [register] @@ -20,7 +20,18 @@ function executeCommand(command: string | string[], args: (string | boolean | st ); } -export const editorCommands = { +function setCommandContext(command: string | string[], args: (string | boolean | number)[]){ + [command] + .flat() + .forEach( + (command: string) => commands.executeCommand('setContext', command, args) + ); +} + +const editorCommands = { registerCommand, - executeCommand -}; \ No newline at end of file + executeCommand, + setCommandContext +}; +export { Uri, editorCommands }; + diff --git a/src/editor/output.ts b/src/editor/output.ts index bd3de7b..1e49cd0 100644 --- a/src/editor/output.ts +++ b/src/editor/output.ts @@ -51,8 +51,9 @@ function log(level: keyof typeof LogLevel, output: string | number | object, log } } -export { log }; -export const editorOutput = { +const editorOutput = { initFileLogger, showOuputChannel -}; \ No newline at end of file +}; + +export { log, editorOutput }; \ No newline at end of file diff --git a/src/shared/interfaces/devToolsCommandRunner.ts b/src/shared/interfaces/devToolsCommandRunner.ts index ecb559f..f1f76bb 100644 --- a/src/shared/interfaces/devToolsCommandRunner.ts +++ b/src/shared/interfaces/devToolsCommandRunner.ts @@ -3,9 +3,9 @@ import DevToolsCommandSetting from "./devToolsCommandSetting"; interface DevToolsCommandRunner{ commandId: string, commandConfig: DevToolsCommandSetting, - commandArgs: { [key: string]: any }, + commandArgs: { [key: string]: string | string[] | boolean }, commandPath: string, - commandResultHandler: (result: any) => void + commandHandlers: { [key: string]: (args?: any) => void } } export default DevToolsCommandRunner; \ No newline at end of file diff --git a/src/shared/utils/file.ts b/src/shared/utils/file.ts index 7124479..de0431e 100644 --- a/src/shared/utils/file.ts +++ b/src/shared/utils/file.ts @@ -9,11 +9,49 @@ function readFileSync(path: string): string { } } +function fileExists(path: string | string[]): string[] { + try{ + return [path] + .flat() + .filter((path: string) => fs.existsSync(path.replace(/^\/[a-zA-Z]:/g, ""))); + }catch(error){ + throw error; + } +} + +function isPathADirectory(path: string): boolean { + try{ + return fs.lstatSync(path.replace(/^\/[a-zA-Z]:/g, "")).isDirectory(); + }catch(error){ + throw error; + } +} + function createFilePath(pathArray: string[]): string { return path.join(...pathArray); } +function copyFile(files: {sourceFilePath: string, targetFilePath: string}[], handleCopyFileError: (error: any) => void){ + try{ + files.forEach(({sourceFilePath, targetFilePath}: {sourceFilePath: string, targetFilePath: string}) => { + sourceFilePath = sourceFilePath.replace(/^\/[a-zA-Z]:/g, ""); + targetFilePath = targetFilePath.replace(/^\/[a-zA-Z]:/g, ""); + fs.cp( + sourceFilePath, + targetFilePath, + {recursive: true}, + (err) => handleCopyFileError(err) + ); + }); + }catch(error){ + throw error; + } +} + export const file = { createFilePath, - readFileSync + readFileSync, + copyFile, + fileExists, + isPathADirectory }; \ No newline at end of file diff --git a/src/shared/utils/lib.ts b/src/shared/utils/lib.ts index 43b0bdd..d3d47cc 100644 --- a/src/shared/utils/lib.ts +++ b/src/shared/utils/lib.ts @@ -53,17 +53,21 @@ function removeNonValues(array: (string | number)[]): (string | number)[]{ ); } -function removeExtensionFromFile(files: string | string[]): string[] { +function removeExtensionFromFile(files: string | string[], extensions: string[]): string[] { return [files] .flat() .map((file: string) => { const filePathSplit: string[] = file.split("/"); let fileName: string | undefined = filePathSplit.pop(); if(fileName){ - fileName = fileName.startsWith(".") - ? `.${fileName.substring(1).split(".")[0]}` - : fileName.split(".")[0]; - filePathSplit.push(fileName); + let [ extensionValue ] : string[] = extensions.filter((ext: string) => fileName?.endsWith(ext)); + if(extensionValue){ + const regex: RegExp = new RegExp(`(\\.(\\w|-)+-${extensionValue})`); + fileName = fileName.split(regex)[0]; + filePathSplit.push(fileName); + }else{ + throw Error(`[lib_removeExtensionFromFile]: Failed to get file extension for file ${file}`); + } }else{ throw Error(`[lib_removeExtensionFromFile]: Failed to get filename for file ${file}`); } diff --git a/src/shared/utils/terminal.ts b/src/shared/utils/terminal.ts index 16b282d..b7959d3 100644 --- a/src/shared/utils/terminal.ts +++ b/src/shared/utils/terminal.ts @@ -7,7 +7,7 @@ function executeTerminalCommand(commandRunner: TerminalCommandRunner): void { commandRunner.args, { shell: true, - cwd: commandRunner.cwd.replace("/c:", "") + cwd: commandRunner.cwd.replace(/^\/[a-zA-Z]:/g, "") } );