@hubspot/cli 7.8.0-experimental.0 → 7.8.1-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.
- package/bin/cli.js +0 -2
- package/commands/getStarted.d.ts +1 -1
- package/commands/getStarted.js +64 -16
- package/commands/mcp/setup.js +8 -0
- package/commands/project/dev/unifiedFlow.js +1 -1
- package/commands/project/migrate.js +30 -21
- package/lang/en.d.ts +4 -1
- package/lang/en.js +5 -1
- package/lib/__tests__/hasFeature.test.js +145 -7
- package/lib/app/__tests__/migrate.test.js +14 -51
- package/lib/app/migrate.d.ts +2 -8
- package/lib/app/migrate.js +5 -80
- package/lib/constants.d.ts +3 -0
- package/lib/constants.js +3 -0
- package/lib/dependencyManagement.d.ts +0 -5
- package/lib/dependencyManagement.js +0 -9
- package/lib/hasFeature.js +6 -0
- package/lib/links.d.ts +1 -0
- package/lib/links.js +10 -3
- package/lib/mcp/setup.js +1 -1
- package/lib/projects/create/v3.js +3 -2
- package/lib/projects/localDev/helpers/project.d.ts +2 -2
- package/lib/projects/localDev/helpers/project.js +5 -6
- package/lib/theme/__tests__/migrate.test.d.ts +1 -0
- package/lib/theme/__tests__/migrate.test.js +233 -0
- package/lib/theme/migrate.d.ts +13 -0
- package/lib/theme/migrate.js +90 -0
- package/lib/ui/SpinniesManager.js +105 -8
- package/lib/usageTracking.js +2 -2
- package/mcp-server/tools/cms/HsCreateFunctionTool.js +1 -1
- package/mcp-server/tools/cms/HsCreateModuleTool.js +1 -1
- package/mcp-server/tools/cms/HsCreateTemplateTool.js +1 -1
- package/mcp-server/tools/cms/HsFunctionLogsTool.js +2 -2
- package/mcp-server/tools/cms/HsListFunctionsTool.js +1 -1
- package/mcp-server/tools/cms/HsListTool.js +1 -1
- package/mcp-server/tools/cms/__tests__/HsCreateFunctionTool.test.js +1 -1
- package/mcp-server/tools/cms/__tests__/HsCreateModuleTool.test.js +1 -1
- package/mcp-server/tools/cms/__tests__/HsCreateTemplateTool.test.js +1 -1
- package/mcp-server/tools/cms/__tests__/HsFunctionLogsTool.test.js +2 -2
- package/mcp-server/tools/cms/__tests__/HsListFunctionsTool.test.js +1 -1
- package/mcp-server/tools/cms/__tests__/HsListTool.test.js +1 -1
- package/mcp-server/tools/project/AddFeatureToProjectTool.d.ts +3 -3
- package/mcp-server/tools/project/AddFeatureToProjectTool.js +3 -3
- package/mcp-server/tools/project/CreateProjectTool.d.ts +3 -3
- package/mcp-server/tools/project/CreateProjectTool.js +5 -5
- package/mcp-server/tools/project/DeployProjectTool.js +1 -1
- package/mcp-server/tools/project/DocFetchTool.js +2 -2
- package/mcp-server/tools/project/DocsSearchTool.d.ts +4 -1
- package/mcp-server/tools/project/DocsSearchTool.js +7 -7
- package/mcp-server/tools/project/GetConfigValuesTool.d.ts +4 -1
- package/mcp-server/tools/project/GetConfigValuesTool.js +11 -5
- package/mcp-server/tools/project/GuidedWalkthroughTool.js +1 -1
- package/mcp-server/tools/project/UploadProjectTools.js +2 -2
- package/mcp-server/tools/project/ValidateProjectTool.js +1 -1
- package/mcp-server/tools/project/__tests__/AddFeatureToProjectTool.test.js +1 -1
- package/mcp-server/tools/project/__tests__/CreateProjectTool.test.js +1 -1
- package/mcp-server/tools/project/__tests__/DeployProjectTool.test.js +1 -1
- package/mcp-server/tools/project/__tests__/DocFetchTool.test.js +2 -2
- package/mcp-server/tools/project/__tests__/DocsSearchTool.test.js +14 -12
- package/mcp-server/tools/project/__tests__/GetConfigValuesTool.test.js +9 -8
- package/mcp-server/tools/project/__tests__/GuidedWalkthroughTool.test.js +1 -1
- package/mcp-server/tools/project/__tests__/UploadProjectTools.test.js +1 -1
- package/mcp-server/tools/project/__tests__/ValidateProjectTool.test.js +1 -1
- package/mcp-server/tools/project/constants.d.ts +1 -1
- package/mcp-server/tools/project/constants.js +9 -3
- package/mcp-server/utils/__tests__/cliConfig.test.d.ts +1 -0
- package/mcp-server/utils/__tests__/cliConfig.test.js +110 -0
- package/mcp-server/utils/cliConfig.d.ts +1 -0
- package/mcp-server/utils/cliConfig.js +12 -0
- package/package.json +2 -7
- package/ui/components/HorizontalSelectPrompt.js +1 -1
- package/commands/getStartedV2.d.ts +0 -9
- package/commands/getStartedV2.js +0 -39
- package/ui/components/Ascii.d.ts +0 -10
- package/ui/components/Ascii.js +0 -11
- package/ui/views/GetStarted.d.ts +0 -7
- package/ui/views/GetStarted.js +0 -157
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { getAccountIdFromCliConfig } from '../cliConfig.js';
|
|
2
|
+
import { configFileExists, findConfig, getAccountId, loadConfig, } from '@hubspot/local-dev-lib/config';
|
|
3
|
+
vi.mock('@hubspot/local-dev-lib/config');
|
|
4
|
+
const mockConfigFileExists = configFileExists;
|
|
5
|
+
const mockFindConfig = findConfig;
|
|
6
|
+
const mockGetAccountId = getAccountId;
|
|
7
|
+
const mockLoadConfig = loadConfig;
|
|
8
|
+
describe('mcp-server/utils/cliConfig', () => {
|
|
9
|
+
const mockWorkingDirectory = '/test/working/directory';
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
vi.clearAllMocks();
|
|
12
|
+
});
|
|
13
|
+
describe('getAccountIdFromCliConfig', () => {
|
|
14
|
+
it('should load global config when it exists and return account ID', () => {
|
|
15
|
+
const expectedAccountId = 12345;
|
|
16
|
+
mockConfigFileExists.mockReturnValue(true);
|
|
17
|
+
mockGetAccountId.mockReturnValue(expectedAccountId);
|
|
18
|
+
const result = getAccountIdFromCliConfig(mockWorkingDirectory);
|
|
19
|
+
expect(mockConfigFileExists).toHaveBeenCalledWith(true);
|
|
20
|
+
expect(mockLoadConfig).toHaveBeenCalledWith('');
|
|
21
|
+
expect(mockFindConfig).not.toHaveBeenCalled();
|
|
22
|
+
expect(mockGetAccountId).toHaveBeenCalledWith(undefined);
|
|
23
|
+
expect(result).toBe(expectedAccountId);
|
|
24
|
+
});
|
|
25
|
+
it('should load local config when global config does not exist and return account ID', () => {
|
|
26
|
+
const expectedAccountId = 67890;
|
|
27
|
+
const localConfigPath = '/path/to/local/config';
|
|
28
|
+
mockConfigFileExists.mockReturnValue(false);
|
|
29
|
+
mockFindConfig.mockReturnValue(localConfigPath);
|
|
30
|
+
mockGetAccountId.mockReturnValue(expectedAccountId);
|
|
31
|
+
const result = getAccountIdFromCliConfig(mockWorkingDirectory);
|
|
32
|
+
expect(mockConfigFileExists).toHaveBeenCalledWith(true);
|
|
33
|
+
expect(mockFindConfig).toHaveBeenCalledWith(mockWorkingDirectory);
|
|
34
|
+
expect(mockLoadConfig).toHaveBeenCalledWith(localConfigPath);
|
|
35
|
+
expect(mockGetAccountId).toHaveBeenCalledWith(undefined);
|
|
36
|
+
expect(result).toBe(expectedAccountId);
|
|
37
|
+
});
|
|
38
|
+
it('should pass accountNameOrId parameter to getAccountId when provided as string', () => {
|
|
39
|
+
const expectedAccountId = 11111;
|
|
40
|
+
const accountName = 'test-account';
|
|
41
|
+
mockConfigFileExists.mockReturnValue(true);
|
|
42
|
+
mockGetAccountId.mockReturnValue(expectedAccountId);
|
|
43
|
+
const result = getAccountIdFromCliConfig(mockWorkingDirectory, accountName);
|
|
44
|
+
expect(mockConfigFileExists).toHaveBeenCalledWith(true);
|
|
45
|
+
expect(mockLoadConfig).toHaveBeenCalledWith('');
|
|
46
|
+
expect(mockGetAccountId).toHaveBeenCalledWith(accountName);
|
|
47
|
+
expect(result).toBe(expectedAccountId);
|
|
48
|
+
});
|
|
49
|
+
it('should pass accountNameOrId parameter to getAccountId when provided as number', () => {
|
|
50
|
+
const expectedAccountId = 22222;
|
|
51
|
+
const accountId = 22222;
|
|
52
|
+
mockConfigFileExists.mockReturnValue(true);
|
|
53
|
+
mockGetAccountId.mockReturnValue(expectedAccountId);
|
|
54
|
+
const result = getAccountIdFromCliConfig(mockWorkingDirectory, accountId);
|
|
55
|
+
expect(mockConfigFileExists).toHaveBeenCalledWith(true);
|
|
56
|
+
expect(mockLoadConfig).toHaveBeenCalledWith('');
|
|
57
|
+
expect(mockGetAccountId).toHaveBeenCalledWith(accountId);
|
|
58
|
+
expect(result).toBe(expectedAccountId);
|
|
59
|
+
});
|
|
60
|
+
it('should return null when getAccountId returns null', () => {
|
|
61
|
+
mockConfigFileExists.mockReturnValue(true);
|
|
62
|
+
mockGetAccountId.mockReturnValue(null);
|
|
63
|
+
const result = getAccountIdFromCliConfig(mockWorkingDirectory);
|
|
64
|
+
expect(mockConfigFileExists).toHaveBeenCalledWith(true);
|
|
65
|
+
expect(mockLoadConfig).toHaveBeenCalledWith('');
|
|
66
|
+
expect(mockGetAccountId).toHaveBeenCalledWith(undefined);
|
|
67
|
+
expect(result).toBeNull();
|
|
68
|
+
});
|
|
69
|
+
it('should handle findConfig returning null by passing null to loadConfig', () => {
|
|
70
|
+
const expectedAccountId = 33333;
|
|
71
|
+
mockConfigFileExists.mockReturnValue(false);
|
|
72
|
+
mockFindConfig.mockReturnValue(null);
|
|
73
|
+
mockGetAccountId.mockReturnValue(expectedAccountId);
|
|
74
|
+
const result = getAccountIdFromCliConfig(mockWorkingDirectory);
|
|
75
|
+
expect(mockConfigFileExists).toHaveBeenCalledWith(true);
|
|
76
|
+
expect(mockFindConfig).toHaveBeenCalledWith(mockWorkingDirectory);
|
|
77
|
+
expect(mockLoadConfig).toHaveBeenCalledWith(null);
|
|
78
|
+
expect(mockGetAccountId).toHaveBeenCalledWith(undefined);
|
|
79
|
+
expect(result).toBe(expectedAccountId);
|
|
80
|
+
});
|
|
81
|
+
it('should work with local config when provided with account name parameter', () => {
|
|
82
|
+
const expectedAccountId = 44444;
|
|
83
|
+
const accountName = 'local-test-account';
|
|
84
|
+
const localConfigPath = '/path/to/local/config';
|
|
85
|
+
mockConfigFileExists.mockReturnValue(false);
|
|
86
|
+
mockFindConfig.mockReturnValue(localConfigPath);
|
|
87
|
+
mockGetAccountId.mockReturnValue(expectedAccountId);
|
|
88
|
+
const result = getAccountIdFromCliConfig(mockWorkingDirectory, accountName);
|
|
89
|
+
expect(mockConfigFileExists).toHaveBeenCalledWith(true);
|
|
90
|
+
expect(mockFindConfig).toHaveBeenCalledWith(mockWorkingDirectory);
|
|
91
|
+
expect(mockLoadConfig).toHaveBeenCalledWith(localConfigPath);
|
|
92
|
+
expect(mockGetAccountId).toHaveBeenCalledWith(accountName);
|
|
93
|
+
expect(result).toBe(expectedAccountId);
|
|
94
|
+
});
|
|
95
|
+
it('should work with local config when provided with account ID parameter', () => {
|
|
96
|
+
const expectedAccountId = 55555;
|
|
97
|
+
const accountId = 55555;
|
|
98
|
+
const localConfigPath = '/path/to/local/config';
|
|
99
|
+
mockConfigFileExists.mockReturnValue(false);
|
|
100
|
+
mockFindConfig.mockReturnValue(localConfigPath);
|
|
101
|
+
mockGetAccountId.mockReturnValue(expectedAccountId);
|
|
102
|
+
const result = getAccountIdFromCliConfig(mockWorkingDirectory, accountId);
|
|
103
|
+
expect(mockConfigFileExists).toHaveBeenCalledWith(true);
|
|
104
|
+
expect(mockFindConfig).toHaveBeenCalledWith(mockWorkingDirectory);
|
|
105
|
+
expect(mockLoadConfig).toHaveBeenCalledWith(localConfigPath);
|
|
106
|
+
expect(mockGetAccountId).toHaveBeenCalledWith(accountId);
|
|
107
|
+
expect(result).toBe(expectedAccountId);
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function getAccountIdFromCliConfig(absolutePathToWorkingDirectory: string, accountNameOrId?: string | number): number | null;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { configFileExists, findConfig, getAccountId, loadConfig, } from '@hubspot/local-dev-lib/config';
|
|
2
|
+
export function getAccountIdFromCliConfig(absolutePathToWorkingDirectory, accountNameOrId) {
|
|
3
|
+
const globalConfigExists = configFileExists(true);
|
|
4
|
+
if (globalConfigExists) {
|
|
5
|
+
loadConfig('');
|
|
6
|
+
}
|
|
7
|
+
else {
|
|
8
|
+
const configPath = findConfig(absolutePathToWorkingDirectory);
|
|
9
|
+
loadConfig(configPath);
|
|
10
|
+
}
|
|
11
|
+
return getAccountId(accountNameOrId);
|
|
12
|
+
}
|
package/package.json
CHANGED
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hubspot/cli",
|
|
3
|
-
"version": "7.8.
|
|
3
|
+
"version": "7.8.1-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/local-dev-lib": "3.18.0",
|
|
10
|
-
"@hubspot/project-parsing-lib": "0.8.
|
|
10
|
+
"@hubspot/project-parsing-lib": "0.8.5-beta.0",
|
|
11
11
|
"@hubspot/serverless-dev-runtime": "7.0.6",
|
|
12
12
|
"@hubspot/theme-preview-dev-server": "0.0.10",
|
|
13
13
|
"@hubspot/ui-extensions-dev-server": "0.9.8",
|
|
14
|
-
"@inkjs/ui": "^2.0.0",
|
|
15
14
|
"archiver": "7.0.1",
|
|
16
15
|
"boxen": "8.0.1",
|
|
17
16
|
"chalk": "5.4.1",
|
|
@@ -19,12 +18,9 @@
|
|
|
19
18
|
"cli-cursor": "3.1.0",
|
|
20
19
|
"cli-progress": "3.12.0",
|
|
21
20
|
"express": "4.21.2",
|
|
22
|
-
"figlet": "^1.8.2",
|
|
23
|
-
"figures": "^6.1.0",
|
|
24
21
|
"findup-sync": "4.0.0",
|
|
25
22
|
"fs-extra": "8.1.0",
|
|
26
23
|
"ink": "5.2.1",
|
|
27
|
-
"ink-link": "^4.1.0",
|
|
28
24
|
"inquirer": "12.7.0",
|
|
29
25
|
"js-yaml": "4.1.0",
|
|
30
26
|
"moment": "2.30.1",
|
|
@@ -43,7 +39,6 @@
|
|
|
43
39
|
"@types/archiver": "^6.0.3",
|
|
44
40
|
"@types/cli-progress": "^3.11.6",
|
|
45
41
|
"@types/express": "^5.0.0",
|
|
46
|
-
"@types/figlet": "^1.7.0",
|
|
47
42
|
"@types/findup-sync": "^4.0.5",
|
|
48
43
|
"@types/fs-extra": "^11.0.4",
|
|
49
44
|
"@types/inquirer": "^9.0.8",
|
|
@@ -26,5 +26,5 @@ export function HorizontalSelectPrompt({ defaultOption, options, onSelect, promp
|
|
|
26
26
|
onSelect(options[selectedIndex]);
|
|
27
27
|
}
|
|
28
28
|
});
|
|
29
|
-
return (_jsxs(Box, { ...CONTAINER_STYLES, flexDirection: "column", marginTop: 1, width: "100%", justifyContent: "
|
|
29
|
+
return (_jsxs(Box, { ...CONTAINER_STYLES, flexDirection: "column", marginTop: 1, width: "100%", alignSelf: "center", justifyContent: "center", children: [prompt && (_jsx(Box, { marginBottom: 1, children: _jsx(Text, { children: prompt }) })), _jsx(Box, { flexDirection: "row", justifyContent: "center", flexWrap: "wrap", width: "100%", gap: 1, children: options.map((option, index) => (_jsx(Box, { children: _jsx(Text, { backgroundColor: index === selectedIndex ? INK_COLORS.INFO_BLUE : undefined, bold: index === selectedIndex, children: ` ${option} ` }) }, index))) }), _jsx(Box, { marginTop: 1, alignSelf: "center", justifyContent: "center", children: _jsx(Text, { dimColor: true, children: "Use arrow keys to navigate, Enter to select" }) })] }));
|
|
30
30
|
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { AccountArgs, YargsCommandModule, CommonArgs, ConfigArgs, EnvironmentArgs } from '../types/Yargs.js';
|
|
2
|
-
export declare const command = "get-started-v2";
|
|
3
|
-
export declare const describe: undefined;
|
|
4
|
-
export type GetStartedArgs = CommonArgs & ConfigArgs & AccountArgs & EnvironmentArgs & {
|
|
5
|
-
name?: string;
|
|
6
|
-
dest?: string;
|
|
7
|
-
};
|
|
8
|
-
declare const getStartedV2Command: YargsCommandModule<unknown, GetStartedArgs>;
|
|
9
|
-
export default getStartedV2Command;
|
package/commands/getStartedV2.js
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import { commands } from '../lang/en.js';
|
|
2
|
-
import { makeYargsBuilder } from '../lib/yargsUtils.js';
|
|
3
|
-
import { getGetStarted } from '../ui/views/GetStarted.js';
|
|
4
|
-
import { render } from 'ink';
|
|
5
|
-
export const command = 'get-started-v2';
|
|
6
|
-
export const describe = undefined;
|
|
7
|
-
async function handler(args) {
|
|
8
|
-
render(getGetStarted({ args }));
|
|
9
|
-
}
|
|
10
|
-
function getStartedBuilder(yargs) {
|
|
11
|
-
yargs.options({
|
|
12
|
-
name: {
|
|
13
|
-
describe: commands.getStarted.options.name.describe,
|
|
14
|
-
type: 'string',
|
|
15
|
-
},
|
|
16
|
-
dest: {
|
|
17
|
-
describe: commands.getStarted.options.dest.describe,
|
|
18
|
-
type: 'string',
|
|
19
|
-
},
|
|
20
|
-
'template-source': {
|
|
21
|
-
describe: commands.getStarted.options.templateSource.describe,
|
|
22
|
-
type: 'string',
|
|
23
|
-
},
|
|
24
|
-
});
|
|
25
|
-
return yargs;
|
|
26
|
-
}
|
|
27
|
-
const builder = makeYargsBuilder(getStartedBuilder, command, commands.getStarted.verboseDescribe, {
|
|
28
|
-
useGlobalOptions: true,
|
|
29
|
-
useAccountOptions: true,
|
|
30
|
-
useConfigOptions: true,
|
|
31
|
-
useEnvironmentOptions: true,
|
|
32
|
-
});
|
|
33
|
-
const getStartedV2Command = {
|
|
34
|
-
command,
|
|
35
|
-
describe,
|
|
36
|
-
handler,
|
|
37
|
-
builder,
|
|
38
|
-
};
|
|
39
|
-
export default getStartedV2Command;
|
package/ui/components/Ascii.d.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import figlet from 'figlet';
|
|
3
|
-
type AsciiProps = {
|
|
4
|
-
font?: figlet.Fonts;
|
|
5
|
-
horizontalLayout?: figlet.KerningMethods;
|
|
6
|
-
verticalLayout?: figlet.KerningMethods;
|
|
7
|
-
text?: string;
|
|
8
|
-
};
|
|
9
|
-
export declare function Ascii({ font, horizontalLayout, verticalLayout, text, }: AsciiProps): React.ReactNode;
|
|
10
|
-
export default Ascii;
|
package/ui/components/Ascii.js
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import figlet from 'figlet';
|
|
3
|
-
import { Box, Text } from 'ink';
|
|
4
|
-
export function Ascii({ font = 'Slant Relief', horizontalLayout = 'default', verticalLayout = 'default', text = '', }) {
|
|
5
|
-
return (_jsx(Box, { alignSelf: "center", children: _jsx(Text, { color: "#FF7A59", children: figlet.textSync(text, {
|
|
6
|
-
font,
|
|
7
|
-
horizontalLayout,
|
|
8
|
-
verticalLayout,
|
|
9
|
-
}) }) }));
|
|
10
|
-
}
|
|
11
|
-
export default Ascii;
|
package/ui/views/GetStarted.d.ts
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import { ArgumentsCamelCase } from 'yargs';
|
|
2
|
-
import { GetStartedArgs } from '../../commands/getStarted.js';
|
|
3
|
-
export type GetStartedProps = {
|
|
4
|
-
args: ArgumentsCamelCase<GetStartedArgs>;
|
|
5
|
-
};
|
|
6
|
-
export declare function getGetStarted(props: GetStartedProps): React.ReactNode;
|
|
7
|
-
export declare function GetStarted({ args }: GetStartedProps): React.ReactNode;
|
package/ui/views/GetStarted.js
DELETED
|
@@ -1,157 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import { useState, useEffect } from 'react';
|
|
3
|
-
import fs from 'fs-extra';
|
|
4
|
-
import { useTerminalSize } from '../lib/useTerminalSize.js';
|
|
5
|
-
import { uiAccountDescription } from '../../lib/ui/index.js';
|
|
6
|
-
import { Box, Text } from 'ink';
|
|
7
|
-
import figures from 'figures';
|
|
8
|
-
import { AlertBox, InfoBox, } from '../components/StatusMessageBoxes.js';
|
|
9
|
-
import { commands } from '../../lang/en.js';
|
|
10
|
-
import Ascii from '../components/Ascii.js';
|
|
11
|
-
import { HorizontalSelectPrompt } from '../components/HorizontalSelectPrompt.js';
|
|
12
|
-
import { INK_COLORS } from '../styles.js';
|
|
13
|
-
import { TextInput, Spinner, ConfirmInput, ThemeProvider, extendTheme, defaultTheme, Badge, } from '@inkjs/ui';
|
|
14
|
-
import { getCwd } from '@hubspot/local-dev-lib/path';
|
|
15
|
-
import path from 'path';
|
|
16
|
-
import { cloneGithubRepo } from '@hubspot/local-dev-lib/github';
|
|
17
|
-
import { HUBSPOT_PROJECT_COMPONENTS_GITHUB_PATH, PROJECT_CONFIG_FILE, } from '../../lib/constants.js';
|
|
18
|
-
import { getProjectConfig, validateProjectConfig, writeProjectConfig, } from '../../lib/projects/config.js';
|
|
19
|
-
import { getProjectPackageJsonLocations, installPackages, } from '../../lib/dependencyManagement.js';
|
|
20
|
-
import { handleProjectUpload } from '../../lib/projects/upload.js';
|
|
21
|
-
import { useV3Api } from '../../lib/projects/platformVersion.js';
|
|
22
|
-
import { pollProjectBuildAndDeploy } from '../../lib/projects/pollProjectBuildAndDeploy.js';
|
|
23
|
-
import { getProjectBuildDetailUrl, getProjectDeployDetailUrl, } from '../../lib/projects/urls.js';
|
|
24
|
-
import { BoxWithTitle } from '../components/BoxWithTitle.js';
|
|
25
|
-
export function getGetStarted(props) {
|
|
26
|
-
return _jsx(GetStarted, { ...props });
|
|
27
|
-
}
|
|
28
|
-
const customTheme = extendTheme(defaultTheme, {
|
|
29
|
-
components: {
|
|
30
|
-
Spinner: {
|
|
31
|
-
styles: {
|
|
32
|
-
frame: () => ({
|
|
33
|
-
color: '#FF7A59',
|
|
34
|
-
}),
|
|
35
|
-
},
|
|
36
|
-
},
|
|
37
|
-
},
|
|
38
|
-
});
|
|
39
|
-
export function GetStarted({ args }) {
|
|
40
|
-
const { derivedAccountId } = args;
|
|
41
|
-
const toolTips = [
|
|
42
|
-
'Run hs doctor to diagnose common cli installation problems',
|
|
43
|
-
'Use hs project add to quickly add new features to your project',
|
|
44
|
-
'Unified apps are coming to the cli soon',
|
|
45
|
-
'Use hs test-account create to create and seed test accounts',
|
|
46
|
-
];
|
|
47
|
-
const accountName = uiAccountDescription(derivedAccountId);
|
|
48
|
-
const { columns, rows } = useTerminalSize();
|
|
49
|
-
const templateSource = 'robrown-hubspot/hubspot-project-components-ua-app-objects-beta';
|
|
50
|
-
const projectTemplate = {
|
|
51
|
-
name: 'private-app-get-started-template',
|
|
52
|
-
label: 'CRM getting started project with private apps',
|
|
53
|
-
path: 'projects/private-app-get-started-template',
|
|
54
|
-
};
|
|
55
|
-
const repo = templateSource || HUBSPOT_PROJECT_COMPONENTS_GITHUB_PATH;
|
|
56
|
-
const cloneRepo = async () => {
|
|
57
|
-
await cloneGithubRepo(repo, projectSource, {
|
|
58
|
-
sourceDir: projectTemplate.path,
|
|
59
|
-
tag: undefined,
|
|
60
|
-
hideLogs: true,
|
|
61
|
-
});
|
|
62
|
-
setIsCloned(true);
|
|
63
|
-
};
|
|
64
|
-
const [projectType, setProjectType] = useState('');
|
|
65
|
-
const [showProjectTypeError, setShowProjectTypeError] = useState(false);
|
|
66
|
-
const [projectName, setProjectName] = useState('');
|
|
67
|
-
const [projectSource, setProjectSource] = useState('');
|
|
68
|
-
const [isCloned, setIsCloned] = useState(false);
|
|
69
|
-
const [isConfigUpdated, setIsConfigUpdated] = useState(false);
|
|
70
|
-
const [areDepsInstalled, setAreDepsInstalled] = useState(false);
|
|
71
|
-
const [isUploading, setIsUploading] = useState(null);
|
|
72
|
-
const [isUploaded, setIsUploaded] = useState(false);
|
|
73
|
-
const [projectPollResult, setProjectPollResult] = useState(null);
|
|
74
|
-
useEffect(() => {
|
|
75
|
-
if (projectType === 'CMS') {
|
|
76
|
-
setShowProjectTypeError(true);
|
|
77
|
-
}
|
|
78
|
-
else {
|
|
79
|
-
setShowProjectTypeError(false);
|
|
80
|
-
}
|
|
81
|
-
}, [projectType]);
|
|
82
|
-
const updateProjectConfig = () => {
|
|
83
|
-
const projectConfigPath = path.join(projectSource, PROJECT_CONFIG_FILE);
|
|
84
|
-
const parsedConfigFile = JSON.parse(fs.readFileSync(projectConfigPath).toString());
|
|
85
|
-
writeProjectConfig(projectConfigPath, {
|
|
86
|
-
...parsedConfigFile,
|
|
87
|
-
name: projectName,
|
|
88
|
-
});
|
|
89
|
-
setIsConfigUpdated(true);
|
|
90
|
-
};
|
|
91
|
-
const installDeps = async () => {
|
|
92
|
-
const installLocations = await getProjectPackageJsonLocations(projectSource);
|
|
93
|
-
await installPackages({
|
|
94
|
-
installLocations: installLocations,
|
|
95
|
-
});
|
|
96
|
-
setAreDepsInstalled(true);
|
|
97
|
-
};
|
|
98
|
-
useEffect(() => {
|
|
99
|
-
if (projectSource && !isCloned) {
|
|
100
|
-
setTimeout(() => {
|
|
101
|
-
cloneRepo();
|
|
102
|
-
}, 500);
|
|
103
|
-
}
|
|
104
|
-
if (projectSource && isCloned) {
|
|
105
|
-
setTimeout(() => {
|
|
106
|
-
updateProjectConfig();
|
|
107
|
-
}, 500);
|
|
108
|
-
}
|
|
109
|
-
}, [projectSource, isCloned]);
|
|
110
|
-
useEffect(() => {
|
|
111
|
-
if (isConfigUpdated && !areDepsInstalled) {
|
|
112
|
-
setTimeout(() => {
|
|
113
|
-
installDeps();
|
|
114
|
-
}, 500);
|
|
115
|
-
}
|
|
116
|
-
}, [isConfigUpdated]);
|
|
117
|
-
const uploadProject = async () => {
|
|
118
|
-
const { projectConfig: newProjectConfig, projectDir: newProjectDir } = await getProjectConfig(projectSource);
|
|
119
|
-
validateProjectConfig(newProjectConfig, newProjectDir);
|
|
120
|
-
const { result, uploadError } = await handleProjectUpload({
|
|
121
|
-
accountId: derivedAccountId,
|
|
122
|
-
projectConfig: newProjectConfig,
|
|
123
|
-
projectDir: newProjectDir,
|
|
124
|
-
callbackFunc: pollProjectBuildAndDeploy,
|
|
125
|
-
uploadMessage: 'Initial upload from get-started command',
|
|
126
|
-
forceCreate: true, // Auto-create project on HubSpot
|
|
127
|
-
isUploadCommand: false,
|
|
128
|
-
sendIR: useV3Api(newProjectConfig.platformVersion),
|
|
129
|
-
skipValidation: false,
|
|
130
|
-
});
|
|
131
|
-
if (result) {
|
|
132
|
-
setIsUploaded(true);
|
|
133
|
-
setProjectPollResult(result);
|
|
134
|
-
}
|
|
135
|
-
};
|
|
136
|
-
const [toolTipIndex, setToolTipIndex] = useState(0);
|
|
137
|
-
useEffect(() => {
|
|
138
|
-
const interval = setInterval(() => {
|
|
139
|
-
setToolTipIndex(prevIndex => (prevIndex + 1) % toolTips.length);
|
|
140
|
-
}, 5000);
|
|
141
|
-
return () => clearInterval(interval);
|
|
142
|
-
}, []);
|
|
143
|
-
useEffect(() => {
|
|
144
|
-
if (isUploading === true) {
|
|
145
|
-
setTimeout(() => {
|
|
146
|
-
uploadProject();
|
|
147
|
-
}, 500);
|
|
148
|
-
}
|
|
149
|
-
}, [isUploading]);
|
|
150
|
-
return (_jsx(ThemeProvider, { theme: customTheme, children: _jsxs(Box, { flexDirection: "column", width: columns, height: rows, children: [_jsx(Ascii, { text: "HubSpot CLI", font: "Standard" }), _jsx(InfoBox, { title: commands.getStarted.startTitle, message: commands.getStarted.startDescription +
|
|
151
|
-
'\n' +
|
|
152
|
-
commands.getStarted.guideOverview(accountName) }), projectType !== 'App' && (_jsxs(Box, { flexDirection: "column", gap: 0, children: [_jsx(HorizontalSelectPrompt, { prompt: commands.getStarted.prompts.selectOption, options: ['App', 'CMS'], onSelect: setProjectType, defaultOption: 'App' }), showProjectTypeError && (_jsx(AlertBox, { title: "Bad Choice", message: "I didn't hook up the CMS flow for this demo" }))] })), projectType === 'App' && (_jsx(_Fragment, { children: _jsxs(Box, { flexDirection: "column", padding: 1, gap: 1, borderStyle: "round", borderColor: "#FF7A59", children: [_jsxs(Box, { flexDirection: "row", width: "100%", gap: 1, children: [_jsxs(Box, { flexDirection: "row", flexBasis: "50%", gap: 1, children: [_jsx(Text, { color: "#FF7A59", children: "Project Name:" }), projectName === '' ? (_jsx(TextInput, { placeholder: "give your project a name", onSubmit: setProjectName })) : (_jsx(Text, { children: projectName }))] }), _jsxs(Box, { flexDirection: "row", flexBasis: "50%", gap: 1, children: [_jsx(Text, { color: "#FF7A59", children: "Project Source:" }), projectSource === '' && projectName !== '' ? (_jsx(TextInput, { defaultValue: path.resolve(getCwd(), projectName), placeholder: path.resolve(getCwd(), projectName), onSubmit: setProjectSource })) : (_jsx(Text, { children: projectSource }))] })] }), projectSource && (_jsx(Box, { flexDirection: "row", width: "100%", gap: 1, children: isCloned ? (_jsxs(Text, { color: INK_COLORS.SUCCESS_GREEN, children: [figures.tick, " Project downloaded"] })) : (_jsx(Spinner, { type: "dots", label: "Downloading project" })) })), projectSource && isCloned && (_jsx(Box, { flexDirection: "row", width: "100%", gap: 1, children: isConfigUpdated ? (_jsxs(Text, { color: INK_COLORS.SUCCESS_GREEN, children: [figures.tick, " Project config updated"] })) : (_jsx(Spinner, { type: "dots", label: "Updating project config" })) })), isConfigUpdated && (_jsxs(Box, { flexDirection: "column", width: "100%", gap: 0, children: [_jsxs(Box, { flexDirection: "row", width: "100%", gap: 1, children: [_jsx(Badge, { color: INK_COLORS.SUCCESS_GREEN, children: "Success" }), _jsx(Text, { children: commands.project.create.logs.success(projectName, projectSource) })] }), _jsx(Text, { children: commands.getStarted.prompts.projectCreated.title }), _jsx(Text, { children: commands.getStarted.prompts.projectCreated.description })] })), isConfigUpdated && (_jsx(Box, { flexDirection: "row", width: "100%", gap: 1, children: areDepsInstalled ? (_jsxs(Text, { color: INK_COLORS.SUCCESS_GREEN, children: [figures.tick, " Project dependencies installed"] })) : (_jsx(Spinner, { type: "dots", label: "Installing project dependencies" })) })), areDepsInstalled && isUploading === null && (_jsxs(Box, { flexDirection: "row", width: "100%", gap: 1, children: [_jsx(Text, { color: INK_COLORS.WARNING_YELLOW, children: "Would you like to upload your project to HubSpot?" }), isUploading === null ? (_jsx(ConfirmInput, { onConfirm: () => {
|
|
153
|
-
setIsUploading(true);
|
|
154
|
-
}, onCancel: () => {
|
|
155
|
-
setIsUploading(false);
|
|
156
|
-
} })) : (_jsx(Text, { color: INK_COLORS.SUCCESS_GREEN, children: isUploading }))] })), isUploading === true && (_jsx(Box, { flexDirection: "row", width: "100%", gap: 1, children: isUploaded ? (_jsxs(Text, { color: INK_COLORS.SUCCESS_GREEN, children: [figures.tick, " Project uploaded, built, and deployed"] })) : (_jsx(Spinner, { type: "dots", label: "Uploading, building, and deploying project" })) })), projectPollResult && (_jsxs(Box, { flexDirection: "column", width: "100%", gap: 1, children: [_jsxs(Box, { flexDirection: "row", alignSelf: "center", width: "100%", gap: 1, children: [_jsx(Text, { color: "#FF7A59", children: "View build in HubSpot:" }), _jsx(Text, { color: INK_COLORS.INFO_BLUE, children: getProjectBuildDetailUrl(projectName, projectPollResult.buildId, derivedAccountId) })] }), _jsxs(Box, { flexDirection: "row", alignSelf: "center", width: "100%", gap: 1, children: [_jsx(Text, { color: "#FF7A59", children: "View deploy in HubSpot:" }), _jsx(Text, { color: INK_COLORS.INFO_BLUE, children: getProjectDeployDetailUrl(projectName, projectPollResult.deployResult?.deployId || 0, derivedAccountId) })] })] }))] }) })), _jsx(BoxWithTitle, { title: "Tips", message: toolTips[toolTipIndex], borderColor: "gray" })] }) }));
|
|
157
|
-
}
|