@forge/cli

14.1.0-next.19-experimental-fd0ebbc14.1.0-next.32
out/command-line/register-app-commands.js
~out/command-line/register-app-commands.jsModified
+44−70
Index: package/out/command-line/register-app-commands.js
===================================================================
--- package/out/command-line/register-app-commands.js
+++ package/out/command-line/register-app-commands.js
@@ -5,8 +5,9 @@
 exports.templateMatchesProduct = templateMatchesProduct;
 exports.directoryNameFromAppName = directoryNameFromAppName;
 exports.createCommandHandler = createCommandHandler;
 exports.filterTemplatesByProduct = filterTemplatesByProduct;
+exports.getTemplateCompatibility = getTemplateCompatibility;
 exports.registerCommands = registerCommands;
 const tslib_1 = require("tslib");
 const fs_1 = tslib_1.__importDefault(require("fs"));
 const sanitize_filename_1 = tslib_1.__importDefault(require("sanitize-filename"));
@@ -41,11 +42,11 @@
     [TemplateContext.GLOBAL]: [TemplateContext.GLOBAL],
     [TemplateContext.AUTOMATION]: [TemplateContext.AUTOMATION],
     [TemplateContext.BITBUCKET]: [TemplateContext.BITBUCKET],
     [TemplateContext.COMPASS]: [TemplateContext.COMPASS],
-    [TemplateContext.CONFLUENCE]: [TemplateContext.CONFLUENCE],
+    [TemplateContext.CONFLUENCE]: [TemplateContext.CONFLUENCE, TemplateContext.GLOBAL],
     [TemplateContext.DASHBOARDS]: [TemplateContext.DASHBOARDS],
-    [TemplateContext.JIRA]: [TemplateContext.JIRA],
+    [TemplateContext.JIRA]: [TemplateContext.JIRA, TemplateContext.GLOBAL],
     [TemplateContext.JIRA_SERVICE_MANAGEMENT]: [TemplateContext.JIRA_SERVICE_MANAGEMENT],
     [TemplateContext.CUSTOMER_SERVICE_MANAGEMENT]: [TemplateContext.CUSTOMER_SERVICE_MANAGEMENT],
     [TemplateContext.TEAMWORK_GRAPH]: [TemplateContext.TEAMWORK_GRAPH],
     [TemplateContext.ROVO]: [TemplateContext.ROVO],
@@ -54,26 +55,29 @@
         TemplateContext.COMPASS,
         TemplateContext.CONFLUENCE,
         TemplateContext.DASHBOARDS,
         TemplateContext.JIRA,
-        TemplateContext.JIRA_SERVICE_MANAGEMENT
+        TemplateContext.JIRA_SERVICE_MANAGEMENT,
+        TemplateContext.GLOBAL
     ]
 };
+const CREATE_PRODUCTS = Object.values(TemplateContext).filter((context) => context !== TemplateContext.GLOBAL);
+const isGlobalTemplate = (name) => name.startsWith(`${TemplateContext.GLOBAL}-`);
+const isUiKitTemplate = (name) => name.includes('ui-kit') || (isGlobalTemplate(name) && name.split('-').includes('ui') && !name.includes('custom-ui'));
 exports.PRODUCT_OPTIONS_DISPLAY = {
-    [TemplateContext.GLOBAL]: 'Global (EAP)',
     [TemplateContext.CROSS_CONTEXT]: 'Multiple',
     [TemplateContext.AUTOMATION]: 'Automation',
     [TemplateContext.DASHBOARDS]: 'Dashboards',
     [TemplateContext.CUSTOMER_SERVICE_MANAGEMENT]: 'Customer Service Management'
 };
 exports.CATEGORY_PREDICATES = [
     [TemplateCategory.SHOW_ALL, (name) => !!name],
     [TemplateCategory.ROVO, (name) => name.includes('rovo')],
-    [TemplateCategory.UI_KIT_2, (name) => name.includes('ui-kit')],
+    [TemplateCategory.UI_KIT_2, isUiKitTemplate],
     [TemplateCategory.CUSTOM_UI, (name) => name.includes('custom-ui')],
     [
         TemplateCategory.BACKEND,
-        (name) => !!name && !name.includes('ui-kit') && !name.includes('custom-ui') && !name.includes('rovo') && name !== 'blank'
+        (name) => !!name && !isUiKitTemplate(name) && !name.includes('custom-ui') && !name.includes('rovo') && name !== 'blank'
     ]
 ];
 const MAX_NAME_LENGTH = 60;
 const createAppFeatures = ({ isPersonalApp }) => {
@@ -113,11 +117,12 @@
         const sortedCategories = categoryPredicates
             .filter(([category]) => categoryMap.has(category))
             .map(([category]) => category);
         const category = await ui.promptForFilterableList(cli_shared_1.Text.create.promptCategory, sortedCategories);
-        const categoryFilteredTemplates = filterTemplatesByCategory(categoryMap.get(category) ?? filteredTemplates, category);
+        const categoryTemplates = categoryMap.get(category) ?? filteredTemplates;
+        const categoryFilteredTemplates = filterTemplatesByCategory(categoryTemplates, category);
         const template = await ui.promptForFilterableList(cli_shared_1.Text.create.promptTemplate, categoryFilteredTemplates);
-        return { name: modifyTemplateByCategory(template, category), analytics: { category } };
+        return { name: categoryTemplates[categoryFilteredTemplates.indexOf(template)], analytics: { category } };
     }
     else {
         const templateName = await ui.promptForFilterableList(cli_shared_1.Text.create.promptTemplate, filteredTemplates);
         return {
@@ -235,9 +240,9 @@
     const args = {
         name,
         template,
         directory,
-        ...(selection.requiredContext && { requiredProduct: selection.requiredContext }),
+        ...(selection.compatibility && { compatibility: selection.compatibility }),
         ...(selectedDevSpace?.id && { developerSpaceId: selectedDevSpace?.id }),
         billingConsent,
         ...(appFeatures && { appFeatures })
     };
@@ -277,57 +282,17 @@
     }
     ensureValidNameLength(name);
     return { name, directory };
 }
-const handleGlobalTemplateSelection = async (ui, directory) => {
-    ui.info(cli_shared_1.Text.create.globalTemplateSelection);
-    const globalTemplates = [
-        'global-ui',
-        'global-ui-typescript',
-        'global-full-page-ui-kit',
-        'global-full-page-custom-ui'
-    ];
-    const selectedTemplate = await ui.promptForFilterableList(cli_shared_1.Text.create.promptGlobalTemplate, globalTemplates, {
-        format: (template) => {
-            switch (template) {
-                case 'global-ui':
-                    return 'Global UI (UI Kit)';
-                case 'global-ui-typescript':
-                    return 'Global UI (UI Kit, TypeScript)';
-                case 'global-full-page-ui-kit':
-                    return 'Global Full Page (UI Kit)';
-                case 'global-full-page-custom-ui':
-                    return 'Global Full Page (Custom UI)';
-                default:
-                    return template;
-            }
-        }
-    });
-    if (!directory) {
-        directory = selectedTemplate;
-        ensureDirectoryDoesntExist(directory);
-    }
-    const category = selectedTemplate.includes('custom-ui') ? TemplateCategory.CUSTOM_UI : TemplateCategory.UI_KIT_2;
-    return {
-        template: selectedTemplate,
-        analytics: {
-            category,
-            product: TemplateContext.GLOBAL
-        }
-    };
-};
 async function promptAndSelectTemplate(ui, createAppCommand, template, directory) {
     if (!template) {
         ui.info(cli_shared_1.Text.create.overviewTemplates);
         const templates = await ui.displayTemporaryMessage(() => createAppCommand.getAvailableTemplates(), cli_shared_1.Text.create.waitTemplates);
         const templatesWithoutCsuik = templates.filter((template) => !template.includes('csuik'));
-        const productOptions = await createAppCommand.filterAvailableProducts(Object.values(TemplateContext), TemplateContext.TEAMWORK_GRAPH, TemplateContext.CROSS_CONTEXT);
+        const productOptions = await createAppCommand.filterAvailableProducts(CREATE_PRODUCTS, TemplateContext.TEAMWORK_GRAPH, TemplateContext.CROSS_CONTEXT);
         const productName = await ui.promptForFilterableList(cli_shared_1.Text.create.promptProduct, productOptions, {
             format: formatProduct
         }, productOptions.length);
-        if (productName === TemplateContext.GLOBAL) {
-            return await handleGlobalTemplateSelection(ui, directory);
-        }
         const filteredTemplates = (PRODUCT_OPTIONS[productName] ?? [productName])
             .map((p) => filterTemplatesByProduct(templatesWithoutCsuik, p, productOptions))
             .flat();
         const uniqueTemplates = [...new Set(filteredTemplates.length ? filteredTemplates : templatesWithoutCsuik)];
@@ -335,15 +300,11 @@
         if (!directory) {
             directory = selectedTemplateName;
             ensureDirectoryDoesntExist(directory);
         }
-        let requiredContext = undefined;
-        if (productName === TemplateContext.CROSS_CONTEXT) {
-            requiredContext = productOptions.find((context) => templateMatchesProduct(context, selectedTemplateName, productOptions));
-        }
         return {
             template: selectedTemplateName,
-            requiredContext: requiredContext === TemplateContext.JIRA_SERVICE_MANAGEMENT ? TemplateContext.JIRA : requiredContext,
+            compatibility: getTemplateCompatibility(productName, selectedTemplateName, productOptions),
             analytics: {
                 ...selectedTemplateAnalytics,
                 product: productName
             }
@@ -354,29 +315,42 @@
         analytics: {}
     };
 }
 function filterTemplatesByProduct(templates, product, productOptions) {
-    return product === 'show-all'
-        ? templates
-        : templates.filter((template) => templateMatchesProduct(product, template, productOptions));
+    switch (product) {
+        case TemplateContext.SHOW_ALL:
+            return templates;
+        case TemplateContext.GLOBAL:
+            return templates.filter(isGlobalTemplate);
+        default:
+            return templates.filter((template) => templateMatchesProduct(product, template, productOptions));
+    }
 }
+function getTemplateCompatibility(productName, templateName, productOptions) {
+    switch (productName) {
+        case TemplateContext.JIRA:
+        case TemplateContext.CONFLUENCE:
+            return isGlobalTemplate(templateName) ? { [productName]: { required: true } } : undefined;
+        case TemplateContext.CROSS_CONTEXT: {
+            if (isGlobalTemplate(templateName)) {
+                return {};
+            }
+            const requiredContext = productOptions.find((context) => templateMatchesProduct(context, templateName, productOptions));
+            if (!requiredContext) {
+                return undefined;
+            }
+            const requiredProduct = requiredContext === TemplateContext.JIRA_SERVICE_MANAGEMENT ? TemplateContext.JIRA : requiredContext;
+            return { [requiredProduct]: { required: true } };
+        }
+        default:
+            return undefined;
+    }
+}
 function filterTemplatesByCategory(templates, category) {
     return category === TemplateCategory.SHOW_ALL
         ? templates
         : templates.map((name) => name.replace('-ui-kit', '').replace('-custom-ui', '').replace('-rovo', ''));
 }
-function modifyTemplateByCategory(template, category) {
-    switch (category) {
-        case TemplateCategory.UI_KIT_2:
-            return `${template}-ui-kit`;
-        case TemplateCategory.CUSTOM_UI:
-            return `${template}-custom-ui`;
-        case TemplateCategory.ROVO:
-            return `${template}-rovo`;
-        default:
-            return template;
-    }
-}
 async function registerCreateCommands(deps) {
     const { cmd, analyticsClientReporter, ui, commands: { createAppCommand }, services: { devSpaceService, statsigService } } = deps;
     const isDevSpaceSelectionEnabled = await statsigService.isDevSpaceSelectionEnabled();
     const createCommand = cmd