diff --git a/commands/project/dev.ts b/commands/project/dev.ts index 762028634..b77ce22cf 100644 --- a/commands/project/dev.ts +++ b/commands/project/dev.ts @@ -30,11 +30,10 @@ const { isAppDeveloperAccount, } = require('../../lib/accountTypes'); const { getValidEnv } = require('@hubspot/local-dev-lib/environment'); - +const { ComponentTypes } = require('../../types/Projects'); const { findProjectComponents, getProjectComponentTypes, - COMPONENT_TYPES, } = require('../../lib/projects/structure'); const { confirmDefaultAccountIsTarget, @@ -82,8 +81,8 @@ exports.handler = async options => { const components = await findProjectComponents(projectDir); const runnableComponents = components.filter(component => component.runnable); const componentTypes = getProjectComponentTypes(runnableComponents); - const hasPrivateApps = !!componentTypes[COMPONENT_TYPES.privateApp]; - const hasPublicApps = !!componentTypes[COMPONENT_TYPES.publicApp]; + const hasPrivateApps = !!componentTypes[ComponentTypes.PrivateApp]; + const hasPublicApps = !!componentTypes[ComponentTypes.PublicApp]; if (runnableComponents.length === 0) { logger.error( diff --git a/commands/theme/preview.ts b/commands/theme/preview.ts index c82f6dd46..5bbfdf027 100644 --- a/commands/theme/preview.ts +++ b/commands/theme/preview.ts @@ -20,10 +20,8 @@ const { ApiErrorContext, logError } = require('../../lib/errorHandlers/index'); const { handleExit, handleKeypress } = require('../../lib/process'); const { getThemeJSONPath } = require('@hubspot/local-dev-lib/cms/themes'); const { getProjectConfig } = require('../../lib/projects'); -const { - findProjectComponents, - COMPONENT_TYPES, -} = require('../../lib/projects/structure'); +const { findProjectComponents } = require('../../lib/projects/structure'); +const { ComponentTypes } = require('../../types/Projects'); const { preview } = require('@hubspot/theme-preview-dev-server'); const { hasFeature } = require('../../lib/hasFeature'); const i18nKey = 'commands.theme.subcommands.preview'; @@ -85,7 +83,7 @@ const determineSrcAndDest = async options => { if (!themeJsonPath) { const projectComponents = await findProjectComponents(projectDir); const themeComponents = projectComponents.filter( - c => c.type === COMPONENT_TYPES.hublTheme + c => c.type === ComponentTypes.HublTheme ); if (themeComponents.length === 0) { logger.error(i18n(`${i18nKey}.errors.noThemeComponents`)); diff --git a/lib/DevServerManager.ts b/lib/DevServerManager.ts index 66f7fc66a..90644e676 100644 --- a/lib/DevServerManager.ts +++ b/lib/DevServerManager.ts @@ -1,10 +1,5 @@ import { logger } from '@hubspot/local-dev-lib/logger'; import { Environment } from '@hubspot/local-dev-lib/types/Config'; -import { - COMPONENT_TYPES, - ComponentTypes, - Component, -} from './projects/structure'; import { i18n } from './lang'; import { promptUser } from './prompts/promptUtils'; import { DevModeInterface as UIEDevModeInterface } from '@hubspot/ui-extensions-dev-server'; @@ -18,7 +13,7 @@ import { getHubSpotWebsiteOrigin, } from '@hubspot/local-dev-lib/urls'; import { getAccountConfig } from '@hubspot/local-dev-lib/config'; -import { ProjectConfig } from '../types/Projects'; +import { ProjectConfig, ComponentTypes, Component } from '../types/Projects'; const i18nKey = 'lib.DevServerManager'; @@ -43,7 +38,7 @@ type DevServer = { }; type ComponentsByType = { - [key in ComponentTypes]: { [key: string]: Component }; + [key in ComponentTypes]?: { [key: string]: Component }; }; class DevServerManager { @@ -55,18 +50,14 @@ class DevServerManager { constructor() { this.initialized = false; this.started = false; - this.componentsByType = { - [COMPONENT_TYPES.privateApp]: {}, - [COMPONENT_TYPES.publicApp]: {}, - [COMPONENT_TYPES.hublTheme]: {}, - }; + this.componentsByType = {}; this.devServers = { [SERVER_KEYS.privateApp]: { - componentType: COMPONENT_TYPES.privateApp, + componentType: ComponentTypes.PrivateApp, serverInterface: UIEDevModeInterface, }, [SERVER_KEYS.publicApp]: { - componentType: COMPONENT_TYPES.publicApp, + componentType: ComponentTypes.PublicApp, serverInterface: UIEDevModeInterface, }, }; @@ -98,17 +89,17 @@ class DevServerManager { } arrangeComponentsByType(components: Component[]): ComponentsByType { - return components.reduce((acc, component) => { + return components.reduce((acc, component) => { if (!acc[component.type]) { acc[component.type] = {}; } if ('name' in component.config && component.config.name) { - acc[component.type][component.config.name] = component; + acc[component.type]![component.config.name] = component; } return acc; - }, {} as ComponentsByType); + }, {}); } async setup({ @@ -203,4 +194,7 @@ class DevServerManager { } } -export default new DevServerManager(); +const Manager = new DevServerManager(); + +export default Manager; +module.exports = Manager; diff --git a/lib/LocalDevManager.ts b/lib/LocalDevManager.ts index 5503f6c10..18af42151 100644 --- a/lib/LocalDevManager.ts +++ b/lib/LocalDevManager.ts @@ -22,11 +22,8 @@ const DevServerManager = require('./DevServerManager'); const { EXIT_CODES } = require('./enums/exitCodes'); const { getProjectDetailUrl } = require('./projects/urls'); const { getAccountHomeUrl } = require('./localDev'); -const { - CONFIG_FILES, - COMPONENT_TYPES, - getAppCardConfigs, -} = require('./projects/structure'); +const { CONFIG_FILES, getAppCardConfigs } = require('./projects/structure'); +const { ComponentTypes } = require('../types/Projects'); const { UI_COLORS, uiCommandReference, @@ -92,7 +89,7 @@ class LocalDevManager { return component.config.uid === appUid; }); - if (this.activeApp.type === COMPONENT_TYPES.publicApp) { + if (this.activeApp.type === ComponentTypes.PublicApp) { try { await this.setActivePublicAppData(); await this.checkActivePublicAppInstalls(); @@ -212,7 +209,7 @@ class LocalDevManager { ) ); - if (this.activeApp.type === COMPONENT_TYPES.publicApp) { + if (this.activeApp.type === ComponentTypes.PublicApp) { logger.log( uiLink( i18n(`${i18nKey}.viewTestAccountLink`), @@ -319,7 +316,7 @@ class LocalDevManager { let warning = reason; if (!reason) { warning = - this.activeApp.type === COMPONENT_TYPES.publicApp && + this.activeApp.type === ComponentTypes.PublicApp && this.publicAppActiveInstalls > 0 ? i18n(`${i18nKey}.uploadWarning.defaultPublicAppWarning`, { installCount: this.publicAppActiveInstalls, @@ -383,7 +380,7 @@ class LocalDevManager { const missingComponents = []; this.runnableComponents.forEach(({ type, config, path }) => { - if (Object.values(COMPONENT_TYPES).includes(type)) { + if (Object.values(ComponentTypes).includes(type)) { const cardConfigs = getAppCardConfigs(config, path); if (!deployedComponentNames.includes(config.name)) { @@ -423,7 +420,7 @@ class LocalDevManager { }); const configPaths = this.runnableComponents - .filter(({ type }) => Object.values(COMPONENT_TYPES).includes(type)) + .filter(({ type }) => Object.values(ComponentTypes).includes(type)) .map(component => { const appConfigPath = path.join( component.path, diff --git a/lib/projects/structure.ts b/lib/projects/structure.ts index fb2127e6a..d6ad0a903 100644 --- a/lib/projects/structure.ts +++ b/lib/projects/structure.ts @@ -1,89 +1,23 @@ import * as fs from 'fs'; import * as path from 'path'; -import { ValueOf } from '@hubspot/local-dev-lib/types/Utils'; import { walk } from '@hubspot/local-dev-lib/fs'; import { logger } from '@hubspot/local-dev-lib/logger'; import { logError } from '../errorHandlers/index'; - -type PrivateAppComponentConfig = { - name: string; - description: string; - uid: string; - scopes: Array; - public: boolean; - extensions?: { - crm: { - cards: Array<{ file: string }>; - }; - }; -}; - -type PublicAppComponentConfig = { - name: string; - uid: string; - description: string; - allowedUrls: Array; - auth: { - redirectUrls: Array; - requiredScopes: Array; - optionalScopes: Array; - conditionallyRequiredScopes: Array; - }; - support: { - supportEmail: string; - documentationUrl: string; - supportUrl: string; - supportPhone: string; - }; - extensions?: { - crm: { - cards: Array<{ file: string }>; - }; - }; - webhooks?: { - file: string; - }; -}; - -type AppCardComponentConfig = { - type: 'crm-card'; - data: { - title: string; - uid: string; - location: string; - module: { - file: string; - }; - objectTypes: Array<{ name: string }>; - }; -}; - -type GenericComponentConfig = - | PublicAppComponentConfig - | PrivateAppComponentConfig - | AppCardComponentConfig; - -export type Component = { - type: ComponentTypes; - config: GenericComponentConfig; - runnable: boolean; - path: string; -}; - -export const COMPONENT_TYPES = { - privateApp: 'private-app', - publicApp: 'public-app', - hublTheme: 'hubl-theme', -} as const; - -export type ComponentTypes = ValueOf; +import { + ComponentTypes, + Component, + GenericComponentConfig, + PublicAppComponentConfig, + PrivateAppComponentConfig, + AppCardComponentConfig, +} from '../../types/Projects'; export const CONFIG_FILES: { - [k in ValueOf]: string; + [k in ComponentTypes]: string; } = { - [COMPONENT_TYPES.privateApp]: 'app.json', - [COMPONENT_TYPES.publicApp]: 'public-app.json', - [COMPONENT_TYPES.hublTheme]: 'theme.json', + [ComponentTypes.PrivateApp]: 'app.json', + [ComponentTypes.PublicApp]: 'public-app.json', + [ComponentTypes.HublTheme]: 'theme.json', }; function getComponentTypeFromConfigFile( @@ -189,7 +123,7 @@ export async function findProjectComponents( if (parsedConfig) { const isLegacy = getIsLegacyApp(parsedConfig, dir); - const isHublTheme = base === CONFIG_FILES[COMPONENT_TYPES.hublTheme]; + const isHublTheme = base === CONFIG_FILES[ComponentTypes.HublTheme]; const componentType = getComponentTypeFromConfigFile(base); if (componentType) { diff --git a/types/Projects.ts b/types/Projects.ts index e6010faeb..0d7b9ac25 100644 --- a/types/Projects.ts +++ b/types/Projects.ts @@ -49,3 +49,74 @@ export type ProjectTemplateRepoConfig = { projects?: ProjectTemplate[]; components?: ComponentTemplate[]; }; + +export type PrivateAppComponentConfig = { + name: string; + description: string; + uid: string; + scopes: Array; + public: boolean; + extensions?: { + crm: { + cards: Array<{ file: string }>; + }; + }; +}; + +export type PublicAppComponentConfig = { + name: string; + uid: string; + description: string; + allowedUrls: Array; + auth: { + redirectUrls: Array; + requiredScopes: Array; + optionalScopes: Array; + conditionallyRequiredScopes: Array; + }; + support: { + supportEmail: string; + documentationUrl: string; + supportUrl: string; + supportPhone: string; + }; + extensions?: { + crm: { + cards: Array<{ file: string }>; + }; + }; + webhooks?: { + file: string; + }; +}; + +export type AppCardComponentConfig = { + type: 'crm-card'; + data: { + title: string; + uid: string; + location: string; + module: { + file: string; + }; + objectTypes: Array<{ name: string }>; + }; +}; + +export type GenericComponentConfig = + | PublicAppComponentConfig + | PrivateAppComponentConfig + | AppCardComponentConfig; + +export enum ComponentTypes { + PrivateApp = 'private-app', + PublicApp = 'public-app', + HublTheme = 'hubl-theme', +} + +export type Component = { + type: ComponentTypes; + config: GenericComponentConfig; + runnable: boolean; + path: string; +};