@hubspot/cli 8.0.3-experimental.0 → 8.0.4-experimental.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -13,7 +13,7 @@ import { getHasMigratableThemes, migrateThemes2025_2, } from '../../lib/theme/mi
13
13
  import { hasFeature } from '../../lib/hasFeature.js';
14
14
  import { FEATURES } from '../../lib/constants.js';
15
15
  import { trackCommandMetadataUsage, trackCommandUsage, } from '../../lib/usageTracking.js';
16
- const { v2025_2 } = PLATFORM_VERSIONS;
16
+ const { v2025_2, v2026_3 } = PLATFORM_VERSIONS;
17
17
  const command = 'migrate';
18
18
  const describe = commands.project.migrate.describe;
19
19
  async function handler(args) {
@@ -67,7 +67,7 @@ function projectMigrateBuilder(yargs) {
67
67
  yargs
68
68
  .option('platform-version', {
69
69
  type: 'string',
70
- choices: [v2025_2],
70
+ choices: [v2025_2, v2026_3],
71
71
  default: v2025_2,
72
72
  })
73
73
  .option('unstable', {
package/lang/en.d.ts CHANGED
@@ -43,6 +43,11 @@ export declare const commands: {
43
43
  checkOutConfig: (configPath: string) => string;
44
44
  pressEnterToInstall: (accountName: string) => string;
45
45
  pressKeyToExit: string;
46
+ installingApp: (appName: string, accountName: string) => string;
47
+ installInstructions: string;
48
+ browserFailedToOpen: (url: string) => string;
49
+ pollingTimeout: (minutes: number) => string;
50
+ pressEnterToContinueSetup: string;
46
51
  prompts: {
47
52
  selectOptionV2: string;
48
53
  options: {
package/lang/en.js CHANGED
@@ -51,6 +51,11 @@ export const commands = {
51
51
  checkOutConfig: (configPath) => `Check out ${chalk.cyan(configPath)} for the full configuration.`,
52
52
  pressEnterToInstall: (accountName) => `? Press ${chalk.bold('<enter>')} to continue installing and previewing this app in ${chalk.bold(accountName)}`,
53
53
  pressKeyToExit: `Press any key to exit...`,
54
+ installingApp: (appName, accountName) => `Installing ${chalk.bold(appName)} in ${chalk.bold(accountName)}...`,
55
+ installInstructions: `We'll take you to your HubSpot account and walk you through installing your app.`,
56
+ browserFailedToOpen: (url) => `⚠️ Failed to open browser automatically. Please open this URL manually:\n${chalk.cyan(url)}`,
57
+ pollingTimeout: (minutes) => `⚠️ Installation polling timed out after ${minutes} minutes. The app may still be installing in the background.`,
58
+ pressEnterToContinueSetup: `Press ${chalk.bold('<enter>')} to continue with card setup...`,
54
59
  prompts: {
55
60
  selectOptionV2: 'Choose a component type to get started',
56
61
  options: {
@@ -3076,7 +3081,7 @@ export const lib = {
3076
3081
  updateSucceeded: (latestVersion) => `Successfully updated HubSpot CLI to version ${chalk.bold(latestVersion)}`,
3077
3082
  notInstalledGlobally: 'Cannot auto-update the HubSpot CLI because NPM is not installed globally',
3078
3083
  updateFailed: (latestVersion) => `Failed to update HubSpot CLI to version ${chalk.bold(latestVersion)}`,
3079
- enableAutoUpdatesMessage: `The HubSpot CLI can automatically keep itself up to date.\n\nThis helps ensure compatibility with the HubSpot platform. You can change this later at any time.\n\nRun${uiCommandReference('hs config set --allow-auto-updates=true')}`,
3084
+ enableAutoUpdatesMessage: `The HubSpot CLI can automatically keep itself up to date.\n\nThis helps ensure compatibility with the HubSpot platform. You can change this later at any time.\n\nRun ${uiCommandReference('hs config set --allow-auto-updates=true')}`,
3080
3085
  },
3081
3086
  },
3082
3087
  projectProfiles: {
@@ -35,3 +35,16 @@ export declare function uploadAndDeployAction({ accountId, projectDest, }: {
35
35
  projectDest: string;
36
36
  }): Promise<UploadAndDeployResult>;
37
37
  export declare function trackGetStartedUsage(params: Record<string, unknown>, accountId: number): Promise<void>;
38
+ export type PollAppInstallationOptions = {
39
+ accountId: number;
40
+ projectId: number;
41
+ appUid: string;
42
+ requiredScopes?: string[];
43
+ optionalScopes?: string[];
44
+ timeoutMs?: number;
45
+ intervalMs?: number;
46
+ onTimeout?: () => void;
47
+ };
48
+ export declare function pollAppInstallation({ accountId, projectId, appUid, requiredScopes, optionalScopes, timeoutMs, // 2 minutes
49
+ intervalMs, // 2 seconds
50
+ onTimeout, }: PollAppInstallationOptions): Promise<void>;
@@ -1,6 +1,7 @@
1
1
  import fs from 'fs-extra';
2
2
  import path from 'path';
3
3
  import { fetchPublicAppsForPortal } from '@hubspot/local-dev-lib/api/appsDev';
4
+ import { fetchAppInstallationData } from '@hubspot/local-dev-lib/api/localDevAuth';
4
5
  import { fetchProject } from '@hubspot/local-dev-lib/api/projects';
5
6
  import { getConfigAccountEnvironment } from '@hubspot/local-dev-lib/config';
6
7
  import { cloneGithubRepo } from '@hubspot/local-dev-lib/github';
@@ -144,3 +145,55 @@ export async function uploadAndDeployAction({ accountId, projectDest, }) {
144
145
  export function trackGetStartedUsage(params, accountId) {
145
146
  return trackCommandMetadataUsage('get-started', params, accountId);
146
147
  }
148
+ export async function pollAppInstallation({ accountId, projectId, appUid, requiredScopes = [], optionalScopes = [], timeoutMs = 2 * 60 * 1000, // 2 minutes
149
+ intervalMs = 2000, // 2 seconds
150
+ onTimeout, }) {
151
+ return new Promise((resolve, reject) => {
152
+ let consecutiveErrors = 0;
153
+ const MAX_CONSECUTIVE_ERRORS = 5;
154
+ let pollInterval = null;
155
+ let pollTimeout = null;
156
+ const cleanup = () => {
157
+ if (pollInterval) {
158
+ clearTimeout(pollInterval);
159
+ pollInterval = null;
160
+ }
161
+ if (pollTimeout) {
162
+ clearTimeout(pollTimeout);
163
+ pollTimeout = null;
164
+ }
165
+ };
166
+ pollTimeout = setTimeout(() => {
167
+ cleanup();
168
+ if (onTimeout) {
169
+ onTimeout();
170
+ }
171
+ resolve(); // Resolve instead of reject to allow continuing with timeout state
172
+ }, timeoutMs);
173
+ const poll = async () => {
174
+ try {
175
+ const { data } = await fetchAppInstallationData(accountId, projectId, appUid, requiredScopes, optionalScopes);
176
+ // Reset error counter on successful fetch
177
+ consecutiveErrors = 0;
178
+ if (data.isInstalledWithScopeGroups) {
179
+ cleanup();
180
+ resolve();
181
+ }
182
+ else if (pollInterval) {
183
+ pollInterval = setTimeout(poll, intervalMs);
184
+ }
185
+ }
186
+ catch (error) {
187
+ consecutiveErrors++;
188
+ if (consecutiveErrors >= MAX_CONSECUTIVE_ERRORS) {
189
+ cleanup();
190
+ reject(new Error(`Failed to check app installation status after ${MAX_CONSECUTIVE_ERRORS} consecutive errors`, { cause: error }));
191
+ }
192
+ else if (pollInterval !== null) {
193
+ pollInterval = setTimeout(poll, intervalMs);
194
+ }
195
+ }
196
+ };
197
+ pollInterval = setTimeout(poll, 0);
198
+ });
199
+ }
@@ -4,6 +4,6 @@
4
4
  *
5
5
  * We are unable to reliably support versions of projects that are newer than any given CLI release
6
6
  * */
7
- export declare const LATEST_SUPPORTED_PLATFORM_VERSION = "2026.03";
7
+ export declare const LATEST_SUPPORTED_PLATFORM_VERSION: string;
8
8
  export declare function isV2Project(platformVersion?: string | null): boolean;
9
9
  export declare function isUnsupportedPlatformVersion(platformVersion?: string | null): boolean;
@@ -1,10 +1,11 @@
1
+ import { PLATFORM_VERSIONS } from '@hubspot/local-dev-lib/constants/projects';
1
2
  /**
2
3
  * Used to surface warnings when users attempt to interact with new platform versions
3
4
  * that were released after this version of the CLI was released.
4
5
  *
5
6
  * We are unable to reliably support versions of projects that are newer than any given CLI release
6
7
  * */
7
- export const LATEST_SUPPORTED_PLATFORM_VERSION = '2026.03';
8
+ export const LATEST_SUPPORTED_PLATFORM_VERSION = PLATFORM_VERSIONS.v2026_3;
8
9
  function parsePlatformVersion(platformVersion) {
9
10
  const [year, minor] = platformVersion.split(/[.-]/);
10
11
  return {
@@ -84,14 +84,14 @@ export class GetBuildLogsTool extends Tool {
84
84
  if (allLogs.length === 0) {
85
85
  return formatTextContents(absoluteCurrentWorkingDirectory, `No logs found for build #${buildId} in project '${projectName}'.`);
86
86
  }
87
- const filteredLogs = filterLogsByLevel(allLogs, logLevel || 'ALL');
87
+ const resolvedLogLevel = logLevel || 'ALL';
88
+ const filteredLogs = filterLogsByLevel(allLogs, resolvedLogLevel);
88
89
  let output;
89
90
  if (filteredLogs.length === 0) {
90
- // No logs match filter, show all logs instead
91
- output = `No ${logLevel} level logs found for build #${buildId} in '${projectName}'.\nShowing all logs instead:\n\n${formatLogs(allLogs)}`;
91
+ output = `No ${resolvedLogLevel} level logs found for build #${buildId} in '${projectName}'.\nShowing all logs instead:\n\n${formatLogs(allLogs)}`;
92
92
  }
93
93
  else {
94
- output = `Logs for build #${buildId} in '${projectName}' (${logLevel} level):\n\n${formatLogs(filteredLogs)}`;
94
+ output = `Logs for build #${buildId} in '${projectName}' (${resolvedLogLevel} level):\n\n${formatLogs(filteredLogs)}`;
95
95
  }
96
96
  return formatTextContents(absoluteCurrentWorkingDirectory, output);
97
97
  }
@@ -1,5 +1,4 @@
1
1
  import { GetApiUsagePatternsByAppIdTool } from '../GetApiUsagePatternsByAppIdTool.js';
2
- import { z } from 'zod';
3
2
  import { getConfigDefaultAccountIfExists } from '@hubspot/local-dev-lib/config';
4
3
  import { http } from '@hubspot/local-dev-lib/http';
5
4
  import { isHubSpotHttpError } from '@hubspot/local-dev-lib/errors/index';
@@ -52,37 +51,6 @@ describe('mcp-server/tools/project/GetApiUsagePatternsByAppIdTool', () => {
52
51
  expect(result).toBe(mockRegisteredTool);
53
52
  });
54
53
  });
55
- describe('input validation', () => {
56
- const inputSchema = z.object({
57
- appId: z
58
- .string()
59
- .describe('The application ID to get API usage patterns for.'),
60
- startDate: z
61
- .string()
62
- .regex(/^\d{4}-\d{2}-\d{2}$/, 'Start date must be in YYYY-MM-DD format')
63
- .optional()
64
- .describe('Start date for the usage patterns query in ISO 8601 format (e.g., 2025-01-01).'),
65
- endDate: z
66
- .string()
67
- .regex(/^\d{4}-\d{2}-\d{2}$/, 'End date must be in YYYY-MM-DD format')
68
- .optional()
69
- .describe('End date for the usage patterns query in ISO 8601 format (e.g., 2025-12-31).'),
70
- });
71
- it('should validate date format correctly', () => {
72
- const validInput = {
73
- appId: '12345',
74
- startDate: '2025-01-01',
75
- endDate: '2025-12-31',
76
- };
77
- const invalidInput = {
78
- appId: '12345',
79
- startDate: '2025-1-1',
80
- endDate: '2025-12-31T00:00:00Z',
81
- };
82
- expect(() => inputSchema.parse(validInput)).not.toThrow();
83
- expect(() => inputSchema.parse(invalidInput)).toThrow();
84
- });
85
- });
86
54
  describe('handler', () => {
87
55
  const input = {
88
56
  absoluteCurrentWorkingDirectory: '/test/dir',
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "@hubspot/cli",
3
- "version": "8.0.3-experimental.0",
3
+ "version": "8.0.4-experimental.0",
4
4
  "description": "The official CLI for developing on HubSpot",
5
5
  "license": "Apache-2.0",
6
6
  "repository": "https://github.com/HubSpot/hubspot-cli",
7
7
  "type": "module",
8
8
  "dependencies": {
9
9
  "@hubspot/cms-dev-server": "1.2.16",
10
- "@hubspot/local-dev-lib": "5.1.1",
10
+ "@hubspot/local-dev-lib": "0.7.1-experimental.0",
11
11
  "@hubspot/project-parsing-lib": "0.12.0",
12
12
  "@hubspot/serverless-dev-runtime": "7.0.7",
13
13
  "@hubspot/ui-extensions-dev-server": "1.1.8",
@@ -1,12 +1,15 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { sanitizeFileName, untildify } from '@hubspot/local-dev-lib/path';
3
3
  import { useApp, useFocus, useInput } from 'ink';
4
+ import open from 'open';
4
5
  import { useCallback, useEffect, useReducer } from 'react';
5
6
  import { commands } from '../../../lang/en.js';
6
- import { createProjectAction, trackGetStartedUsage, uploadAndDeployAction, } from '../../../lib/getStartedV2Actions.js';
7
+ import { createProjectAction, pollAppInstallation, trackGetStartedUsage, uploadAndDeployAction, } from '../../../lib/getStartedV2Actions.js';
8
+ import { validateProjectDirectory } from '../../../lib/prompts/projectNameAndDestPrompt.js';
7
9
  import { uiAccountDescription } from '../../../lib/ui/index.js';
8
10
  import { ACTION_STATUSES, GET_STARTED_FLOW_STEPS, } from '../../lib/constants.js';
9
11
  import { flowReducer } from './reducer.js';
12
+ import { InstallationScreen } from './screens/InstallationScreen.js';
10
13
  import { ProjectSetupScreen } from './screens/ProjectSetupScreen.js';
11
14
  import { UploadScreen } from './screens/UploadScreen.js';
12
15
  import { getProject } from './selectors.js';
@@ -44,6 +47,7 @@ export function GetStartedFlow({ derivedAccountId, initialName, initialDest, })
44
47
  statuses: {
45
48
  create: initialName ? ACTION_STATUSES.RUNNING : ACTION_STATUSES.IDLE,
46
49
  upload: ACTION_STATUSES.IDLE,
50
+ installApp: ACTION_STATUSES.IDLE,
47
51
  },
48
52
  });
49
53
  const [state, dispatch] = useReducer(flowReducer, getInitialState());
@@ -68,6 +72,16 @@ export function GetStartedFlow({ derivedAccountId, initialName, initialDest, })
68
72
  dispatch({ type: 'SET_STEP', payload: GET_STARTED_FLOW_STEPS.DEST_INPUT });
69
73
  }, []);
70
74
  const handleDestSubmit = useCallback(async () => {
75
+ const validationResult = validateProjectDirectory(project.destination);
76
+ if (validationResult !== true) {
77
+ dispatch({
78
+ type: 'SET_DEST_ERROR',
79
+ payload: typeof validationResult === 'string'
80
+ ? validationResult
81
+ : commands.getStarted.v2.unknownError,
82
+ });
83
+ return;
84
+ }
71
85
  dispatch({ type: 'SET_STEP', payload: GET_STARTED_FLOW_STEPS.CREATING });
72
86
  try {
73
87
  await createProjectAction({
@@ -108,6 +122,57 @@ export function GetStartedFlow({ derivedAccountId, initialName, initialDest, })
108
122
  dispatch({ type: 'UPLOAD_ERROR', payload: errorMessage });
109
123
  }
110
124
  }, [derivedAccountId, project.destination]);
125
+ const handlePollInstallation = useCallback(async () => {
126
+ const uploadApp = project.uploadResult?.app;
127
+ const projectId = project.uploadResult?.projectId;
128
+ if (!projectId || !uploadApp?.uid) {
129
+ dispatch({
130
+ type: 'INSTALL_APP_ERROR',
131
+ payload: commands.getStarted.v2.unknownError,
132
+ });
133
+ return;
134
+ }
135
+ try {
136
+ await pollAppInstallation({
137
+ accountId: derivedAccountId,
138
+ projectId,
139
+ appUid: uploadApp.uid,
140
+ requiredScopes: uploadApp.config?.auth?.requiredScopes,
141
+ optionalScopes: uploadApp.config?.auth?.optionalScopes,
142
+ onTimeout: () => {
143
+ dispatch({ type: 'SET_POLLING_TIMED_OUT', payload: true });
144
+ },
145
+ });
146
+ dispatch({ type: 'INSTALL_APP_DONE' });
147
+ }
148
+ catch (error) {
149
+ dispatch({
150
+ type: 'INSTALL_APP_ERROR',
151
+ payload: error instanceof Error
152
+ ? error.message
153
+ : commands.getStarted.v2.unknownError,
154
+ });
155
+ }
156
+ }, [project.uploadResult, derivedAccountId]);
157
+ const handleBrowserOpen = useCallback(async (shouldOpen) => {
158
+ await trackGetStartedUsage({
159
+ step: 'open-install-page',
160
+ type: shouldOpen ? 'opened' : 'declined',
161
+ }, derivedAccountId);
162
+ if (shouldOpen && project.uploadResult?.installUrl) {
163
+ try {
164
+ await open(project.uploadResult.installUrl, { url: true });
165
+ }
166
+ catch (error) {
167
+ dispatch({
168
+ type: 'SET_BROWSER_FAILED_URL',
169
+ payload: project.uploadResult.installUrl,
170
+ });
171
+ }
172
+ }
173
+ dispatch({ type: 'START_INSTALL_APP' });
174
+ await handlePollInstallation();
175
+ }, [project.uploadResult, derivedAccountId, handlePollInstallation]);
111
176
  const handleNameChange = useCallback((value) => {
112
177
  dispatch({ type: 'SET_PROJECT_NAME', payload: value });
113
178
  }, []);
@@ -116,7 +181,8 @@ export function GetStartedFlow({ derivedAccountId, initialName, initialDest, })
116
181
  }, []);
117
182
  useInput((_, key) => {
118
183
  const hasError = state.statuses.create === ACTION_STATUSES.ERROR ||
119
- state.statuses.upload === ACTION_STATUSES.ERROR;
184
+ state.statuses.upload === ACTION_STATUSES.ERROR ||
185
+ state.statuses.installApp === ACTION_STATUSES.ERROR;
120
186
  if (hasError) {
121
187
  exit();
122
188
  return;
@@ -126,11 +192,22 @@ export function GetStartedFlow({ derivedAccountId, initialName, initialDest, })
126
192
  if (state.step === GET_STARTED_FLOW_STEPS.COMPLETE) {
127
193
  handleUploadStart();
128
194
  }
195
+ else if (state.step === GET_STARTED_FLOW_STEPS.OPEN_APP_PROMPT) {
196
+ handleBrowserOpen(true);
197
+ }
198
+ else if (state.step === GET_STARTED_FLOW_STEPS.INSTALLING_APP &&
199
+ state.statuses.installApp === ACTION_STATUSES.DONE) {
200
+ // Ready for card setup - will be handled in PR3
201
+ exit();
202
+ }
129
203
  });
130
204
  if (state.step === GET_STARTED_FLOW_STEPS.UPLOADING ||
131
205
  state.step === GET_STARTED_FLOW_STEPS.OPEN_APP_PROMPT) {
132
206
  return _jsx(UploadScreen, { state: state, accountName: accountName });
133
207
  }
208
+ if (state.step === GET_STARTED_FLOW_STEPS.INSTALLING_APP) {
209
+ return _jsx(InstallationScreen, { state: state, accountName: accountName });
210
+ }
134
211
  // Show project setup screen for initial flow
135
212
  return (_jsx(ProjectSetupScreen, { state: state, onSelectOption: handleSelect, onNameChange: handleNameChange, onNameSubmit: handleNameSubmit, onDestChange: handleDestChange, onDestSubmit: handleDestSubmit }));
136
213
  }
@@ -14,6 +14,7 @@ export type AppState = {
14
14
  export type ActionStatuses = {
15
15
  create: ActionStatus;
16
16
  upload: ActionStatus;
17
+ installApp: ActionStatus;
17
18
  };
18
19
  export type FlowState = {
19
20
  step: FlowStep;
@@ -21,6 +22,9 @@ export type FlowState = {
21
22
  app: AppState;
22
23
  statuses: ActionStatuses;
23
24
  error?: string;
25
+ destError?: string;
26
+ browserFailedUrl?: string;
27
+ pollingTimedOut?: boolean;
24
28
  };
25
29
  type FlowAction = {
26
30
  type: 'SET_STEP';
@@ -37,6 +41,9 @@ type FlowAction = {
37
41
  } | {
38
42
  type: 'SET_ERROR';
39
43
  payload: string;
44
+ } | {
45
+ type: 'SET_DEST_ERROR';
46
+ payload: string;
40
47
  } | {
41
48
  type: 'CLEAR_ERROR';
42
49
  } | {
@@ -54,6 +61,19 @@ type FlowAction = {
54
61
  } | {
55
62
  type: 'UPLOAD_ERROR';
56
63
  payload: string;
64
+ } | {
65
+ type: 'START_INSTALL_APP';
66
+ } | {
67
+ type: 'INSTALL_APP_DONE';
68
+ } | {
69
+ type: 'INSTALL_APP_ERROR';
70
+ payload: string;
71
+ } | {
72
+ type: 'SET_BROWSER_FAILED_URL';
73
+ payload: string;
74
+ } | {
75
+ type: 'SET_POLLING_TIMED_OUT';
76
+ payload: boolean;
57
77
  };
58
78
  export declare function flowReducer(state: FlowState, action: FlowAction): FlowState;
59
79
  export {};
@@ -17,6 +17,13 @@ export function flowReducer(state, action) {
17
17
  return {
18
18
  ...state,
19
19
  project: { ...state.project, destination: action.payload },
20
+ destError: undefined,
21
+ };
22
+ case 'SET_DEST_ERROR':
23
+ return {
24
+ ...state,
25
+ step: GET_STARTED_FLOW_STEPS.DEST_INPUT,
26
+ destError: action.payload,
20
27
  };
21
28
  case 'SET_ERROR':
22
29
  return { ...state, error: action.payload };
@@ -66,6 +73,35 @@ export function flowReducer(state, action) {
66
73
  statuses: { ...state.statuses, upload: ACTION_STATUSES.ERROR },
67
74
  error: action.payload,
68
75
  };
76
+ case 'START_INSTALL_APP':
77
+ return {
78
+ ...state,
79
+ step: GET_STARTED_FLOW_STEPS.INSTALLING_APP,
80
+ statuses: { ...state.statuses, installApp: ACTION_STATUSES.RUNNING },
81
+ error: undefined,
82
+ pollingTimedOut: false,
83
+ };
84
+ case 'INSTALL_APP_DONE':
85
+ return {
86
+ ...state,
87
+ statuses: { ...state.statuses, installApp: ACTION_STATUSES.DONE },
88
+ };
89
+ case 'INSTALL_APP_ERROR':
90
+ return {
91
+ ...state,
92
+ statuses: { ...state.statuses, installApp: ACTION_STATUSES.ERROR },
93
+ error: action.payload,
94
+ };
95
+ case 'SET_BROWSER_FAILED_URL':
96
+ return {
97
+ ...state,
98
+ browserFailedUrl: action.payload,
99
+ };
100
+ case 'SET_POLLING_TIMED_OUT':
101
+ return {
102
+ ...state,
103
+ pollingTimedOut: action.payload,
104
+ };
69
105
  default:
70
106
  return state;
71
107
  }
@@ -0,0 +1,7 @@
1
+ import { FlowState } from '../reducer.js';
2
+ type InstallationScreenProps = {
3
+ state: FlowState;
4
+ accountName: string;
5
+ };
6
+ export declare function InstallationScreen({ state, accountName, }: InstallationScreenProps): import("react/jsx-runtime").JSX.Element;
7
+ export {};
@@ -0,0 +1,16 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Box, Text } from 'ink';
3
+ import { commands } from '../../../../lang/en.js';
4
+ import { ActionSection } from '../../ActionSection.js';
5
+ import { BoxWithTitle } from '../../BoxWithTitle.js';
6
+ import { INK_COLORS } from '../../../styles.js';
7
+ import { getProject } from '../selectors.js';
8
+ import { ACTION_STATUSES, GET_STARTED_FLOW_STEPS, } from '../../../lib/constants.js';
9
+ export function InstallationScreen({ state, accountName, }) {
10
+ const project = getProject(state);
11
+ const titleText = commands.getStarted.v2.startTitle;
12
+ // If we get to the installation screen, the app is uploaded and we have the name
13
+ const appName = project.uploadResult?.app?.config.name;
14
+ return (_jsx(BoxWithTitle, { flexGrow: 1, title: "hs get-started", borderColor: INK_COLORS.HUBSPOT_ORANGE, titleBackgroundColor: INK_COLORS.HUBSPOT_ORANGE, children: _jsxs(Box, { flexDirection: "column", rowGap: 1, children: [_jsx(Text, { bold: true, children: titleText }), _jsx(Text, { children: commands.getStarted.v2.installInstructions }), _jsx(ActionSection, { status: state.statuses.installApp, statusText: commands.getStarted.v2.installingApp(appName, accountName) }), state.browserFailedUrl && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(Text, { color: INK_COLORS.WARNING_YELLOW, children: commands.getStarted.v2.browserFailedToOpen(state.browserFailedUrl) }) })), state.pollingTimedOut && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(Text, { color: INK_COLORS.WARNING_YELLOW, children: commands.getStarted.v2.pollingTimeout(2) }) })), state.step === GET_STARTED_FLOW_STEPS.INSTALLING_APP &&
15
+ state.statuses.installApp === ACTION_STATUSES.DONE && (_jsx(Text, { children: commands.getStarted.v2.pressEnterToContinueSetup }))] }) }));
16
+ }
@@ -35,5 +35,6 @@ export function ProjectSetupScreen({ state, onSelectOption, onNameChange, onName
35
35
  return (_jsx(BoxWithTitle, { flexGrow: 1, title: "hs get-started", borderColor: INK_COLORS.HUBSPOT_ORANGE, titleBackgroundColor: INK_COLORS.HUBSPOT_ORANGE, children: _jsxs(Box, { flexDirection: "column", rowGap: 1, children: [_jsx(Text, { bold: true, children: titleText }), state.step === GET_STARTED_FLOW_STEPS.SELECT ? (_jsxs(_Fragment, { children: [_jsx(Text, { children: overviewText }), _jsx(Text, { children: projectsText }), _jsxs(Box, { flexDirection: "row", flexWrap: "wrap", columnGap: 1, children: [_jsx(Text, { color: INK_COLORS.HUBSPOT_TEAL, children: "?" }), _jsx(Text, { children: selectPrompt })] }), _jsx(SelectInput, { items: GET_STARTED_FLOW_OPTIONS, onSelect: onSelectOption })] })) : (_jsxs(Box, { flexDirection: "row", flexWrap: "wrap", columnGap: 1, children: [_jsx(Text, { color: INK_COLORS.HUBSPOT_TEAL, children: "?" }), _jsx(Text, { children: `${selectPrompt}` }), _jsx(Text, { color: INK_COLORS.INFO_BLUE, children: state.app.selectedLabel })] })), _jsxs(ActionSection, { status: state.statuses.create, statusText: runningProjectCreateText, errorMessage: state.statuses.create === ACTION_STATUSES.ERROR
36
36
  ? `${state.error}\n\n${commands.getStarted.v2.pressKeyToExit}`
37
37
  : undefined, children: [state.step !== GET_STARTED_FLOW_STEPS.SELECT && (_jsx(InputField, { flag: "name", prompt: "Enter your project name", value: project.name, isEditing: state.step === GET_STARTED_FLOW_STEPS.NAME_INPUT, onChange: onNameChange, onSubmit: onNameSubmit })), state.step !== GET_STARTED_FLOW_STEPS.SELECT &&
38
- state.step !== GET_STARTED_FLOW_STEPS.NAME_INPUT && (_jsx(InputField, { flag: "dest", prompt: "Choose where to create the project", value: project.destination, isEditing: state.step === GET_STARTED_FLOW_STEPS.DEST_INPUT, onChange: onDestChange, onSubmit: onDestSubmit }))] }), state.step === GET_STARTED_FLOW_STEPS.COMPLETE && (_jsxs(Box, { flexDirection: "row", flexWrap: "wrap", columnGap: 1, children: [_jsx(Text, { color: INK_COLORS.HUBSPOT_TEAL, children: "?" }), _jsx(Text, { children: commands.getStarted.v2.pressEnterToContinueDeploy(state.app.selectedLabel) })] }))] }) }));
38
+ state.step !== GET_STARTED_FLOW_STEPS.NAME_INPUT && (_jsxs(_Fragment, { children: [_jsx(InputField, { flag: "dest", prompt: "Choose where to create the project", value: project.destination, isEditing: state.step === GET_STARTED_FLOW_STEPS.DEST_INPUT, onChange: onDestChange, onSubmit: onDestSubmit }), state.destError &&
39
+ state.step === GET_STARTED_FLOW_STEPS.DEST_INPUT && (_jsx(Text, { color: INK_COLORS.ALERT_RED, children: state.destError }))] }))] }), state.step === GET_STARTED_FLOW_STEPS.COMPLETE && (_jsxs(Box, { flexDirection: "row", flexWrap: "wrap", columnGap: 1, children: [_jsx(Text, { color: INK_COLORS.HUBSPOT_TEAL, children: "?" }), _jsx(Text, { children: commands.getStarted.v2.pressEnterToContinueDeploy(state.app.selectedLabel) })] }))] }) }));
39
40
  }
@@ -12,5 +12,6 @@ export declare const GET_STARTED_FLOW_STEPS: {
12
12
  readonly INSTALLING: "installing";
13
13
  readonly UPLOADING: "uploading";
14
14
  readonly OPEN_APP_PROMPT: "open-app-prompt";
15
+ readonly INSTALLING_APP: "installing-app";
15
16
  readonly COMPLETE: "complete";
16
17
  };
@@ -12,5 +12,6 @@ export const GET_STARTED_FLOW_STEPS = {
12
12
  INSTALLING: 'installing',
13
13
  UPLOADING: 'uploading',
14
14
  OPEN_APP_PROMPT: 'open-app-prompt',
15
+ INSTALLING_APP: 'installing-app',
15
16
  COMPLETE: 'complete',
16
17
  };