@hubspot/cli 7.8.11-experimental.0 → 7.8.12-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/commands/app/__tests__/install.test.d.ts +1 -0
- package/commands/app/__tests__/install.test.js +47 -0
- package/commands/app/install.d.ts +8 -0
- package/commands/app/install.js +122 -0
- package/commands/app.js +6 -1
- package/commands/project/migrate.js +14 -16
- package/commands/project/upload.d.ts +2 -2
- package/commands/project/upload.js +1 -1
- package/commands/testAccount/create.js +3 -0
- package/lang/en.d.ts +22 -0
- package/lang/en.js +22 -0
- package/lib/middleware/fireAlarmMiddleware.js +15 -17
- package/lib/projectProfiles.d.ts +1 -1
- package/lib/projectProfiles.js +10 -2
- package/lib/projects/structure.d.ts +2 -2
- package/lib/projects/upload.d.ts +2 -1
- package/lib/projects/upload.js +1 -0
- package/package.json +2 -2
- package/types/Yargs.d.ts +1 -1
- package/ui/components/BoxWithTitle.d.ts +8 -0
- package/ui/components/BoxWithTitle.js +9 -0
- package/ui/components/HorizontalSelectPrompt.d.ts +8 -0
- package/ui/components/HorizontalSelectPrompt.js +30 -0
- package/ui/components/StatusMessageBoxes.d.ts +12 -0
- package/ui/components/StatusMessageBoxes.js +31 -0
- package/ui/index.d.ts +1 -0
- package/ui/index.js +6 -0
- package/ui/lib/ui-testing-utils.d.ts +9 -0
- package/ui/lib/ui-testing-utils.js +47 -0
- package/ui/lib/useTerminalSize.d.ts +13 -0
- package/ui/lib/useTerminalSize.js +31 -0
- package/ui/styles.d.ts +18 -0
- package/ui/styles.js +18 -0
- package/ui/views/UiSandbox.d.ts +5 -0
- package/ui/views/UiSandbox.js +25 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import yargs from 'yargs';
|
|
2
|
+
import { addAccountOptions, addConfigOptions, addUseEnvironmentOptions, addGlobalOptions, addJSONOutputOptions, } from '../../../lib/commonOpts.js';
|
|
3
|
+
import installCommand from '../install.js';
|
|
4
|
+
vi.mock('../../../lib/commonOpts');
|
|
5
|
+
describe('commands/app/install', () => {
|
|
6
|
+
const yargsMock = yargs;
|
|
7
|
+
describe('command', () => {
|
|
8
|
+
it('should have the correct command structure', () => {
|
|
9
|
+
expect(installCommand.command).toEqual('install <test-account-id>');
|
|
10
|
+
});
|
|
11
|
+
});
|
|
12
|
+
describe('describe', () => {
|
|
13
|
+
it('should provide a description', () => {
|
|
14
|
+
expect(installCommand.describe).not.toBeDefined();
|
|
15
|
+
});
|
|
16
|
+
});
|
|
17
|
+
describe('builder', () => {
|
|
18
|
+
it('should support the correct options', () => {
|
|
19
|
+
installCommand.builder(yargsMock);
|
|
20
|
+
expect(addGlobalOptions).toHaveBeenCalledTimes(1);
|
|
21
|
+
expect(addGlobalOptions).toHaveBeenCalledWith(yargsMock);
|
|
22
|
+
expect(addAccountOptions).toHaveBeenCalledTimes(1);
|
|
23
|
+
expect(addAccountOptions).toHaveBeenCalledWith(yargsMock);
|
|
24
|
+
expect(addConfigOptions).toHaveBeenCalledTimes(1);
|
|
25
|
+
expect(addConfigOptions).toHaveBeenCalledWith(yargsMock);
|
|
26
|
+
expect(addUseEnvironmentOptions).toHaveBeenCalledTimes(1);
|
|
27
|
+
expect(addUseEnvironmentOptions).toHaveBeenCalledWith(yargsMock);
|
|
28
|
+
expect(addJSONOutputOptions).toHaveBeenCalledTimes(1);
|
|
29
|
+
expect(addJSONOutputOptions).toHaveBeenCalledWith(yargsMock);
|
|
30
|
+
expect(yargsMock.positional).toHaveBeenCalledTimes(1);
|
|
31
|
+
expect(yargsMock.positional).toHaveBeenCalledWith('test-account-id', expect.objectContaining({
|
|
32
|
+
type: 'number',
|
|
33
|
+
required: true,
|
|
34
|
+
describe: expect.any(String),
|
|
35
|
+
}));
|
|
36
|
+
expect(yargsMock.option).toHaveBeenCalledTimes(2);
|
|
37
|
+
expect(yargsMock.option).toHaveBeenCalledWith('app-uid', expect.objectContaining({
|
|
38
|
+
type: 'string',
|
|
39
|
+
describe: expect.any(String),
|
|
40
|
+
}));
|
|
41
|
+
expect(yargsMock.option).toHaveBeenCalledWith('project-name', expect.objectContaining({
|
|
42
|
+
type: 'string',
|
|
43
|
+
describe: expect.any(String),
|
|
44
|
+
}));
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
});
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { CommonArgs, ConfigArgs, AccountArgs, EnvironmentArgs, YargsCommandModule, JSONOutputArgs } from '../../types/Yargs.js';
|
|
2
|
+
type InstallAppArgs = CommonArgs & ConfigArgs & AccountArgs & EnvironmentArgs & JSONOutputArgs & {
|
|
3
|
+
appUid?: string;
|
|
4
|
+
projectName?: string;
|
|
5
|
+
testAccountId: number;
|
|
6
|
+
};
|
|
7
|
+
declare const installAppCommand: YargsCommandModule<unknown, InstallAppArgs>;
|
|
8
|
+
export default installAppCommand;
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { fetchDeveloperTestAccountOauthAppInstallStatus, installOauthAppIntoDeveloperTestAccount, } from '@hubspot/local-dev-lib/api/developerTestAccounts';
|
|
2
|
+
import { trackCommandUsage } from '../../lib/usageTracking.js';
|
|
3
|
+
import { commands } from '../../lang/en.js';
|
|
4
|
+
import { EXIT_CODES } from '../../lib/enums/exitCodes.js';
|
|
5
|
+
import { makeYargsBuilder } from '../../lib/yargsUtils.js';
|
|
6
|
+
import { APP_AUTH_TYPES } from '../../lib/constants.js';
|
|
7
|
+
import { uiLogger } from '../../lib/ui/logger.js';
|
|
8
|
+
import SpinniesManager from '../../lib/ui/SpinniesManager.js';
|
|
9
|
+
import { poll } from '../../lib/polling.js';
|
|
10
|
+
import { getProjectConfig, validateProjectConfig, } from '../../lib/projects/config.js';
|
|
11
|
+
import { handleTranslate } from '../../lib/projects/upload.js';
|
|
12
|
+
import { isAppIRNode } from '../../lib/projects/structure.js';
|
|
13
|
+
import { logError } from '../../lib/errorHandlers/index.js';
|
|
14
|
+
const command = 'install <test-account-id>';
|
|
15
|
+
const describe = undefined; // commands.app.subcommands.install.describe;
|
|
16
|
+
async function handler(args) {
|
|
17
|
+
const { derivedAccountId, appUid, projectName, testAccountId, formatOutputAsJson, } = args;
|
|
18
|
+
trackCommandUsage('app-install', {}, derivedAccountId);
|
|
19
|
+
const jsonOutput = {};
|
|
20
|
+
let targetProjectName = projectName;
|
|
21
|
+
let targetAppUid = appUid;
|
|
22
|
+
const { projectConfig, projectDir } = await getProjectConfig();
|
|
23
|
+
if (!targetProjectName) {
|
|
24
|
+
validateProjectConfig(projectConfig, projectDir);
|
|
25
|
+
targetProjectName = projectConfig?.name;
|
|
26
|
+
}
|
|
27
|
+
if (!targetProjectName) {
|
|
28
|
+
uiLogger.error(commands.app.subcommands.install.errors.mustSpecifyProjectName);
|
|
29
|
+
process.exit(EXIT_CODES.ERROR);
|
|
30
|
+
}
|
|
31
|
+
let isAppOauth = true;
|
|
32
|
+
if (!targetAppUid) {
|
|
33
|
+
const intermediateRepresentation = await handleTranslate(projectDir, projectConfig, derivedAccountId, true, undefined);
|
|
34
|
+
if (intermediateRepresentation) {
|
|
35
|
+
Object.values(intermediateRepresentation.intermediateNodesIndexedByUid).forEach(node => {
|
|
36
|
+
if (isAppIRNode(node)) {
|
|
37
|
+
targetAppUid = node.uid;
|
|
38
|
+
isAppOauth = node.config.auth.type === APP_AUTH_TYPES.OAUTH;
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
if (!targetAppUid) {
|
|
44
|
+
uiLogger.error(commands.app.subcommands.install.errors.noAppUidFound);
|
|
45
|
+
process.exit(EXIT_CODES.ERROR);
|
|
46
|
+
}
|
|
47
|
+
if (!isAppOauth) {
|
|
48
|
+
uiLogger.error(commands.app.subcommands.install.errors.appMustBeOauth);
|
|
49
|
+
process.exit(EXIT_CODES.ERROR);
|
|
50
|
+
}
|
|
51
|
+
try {
|
|
52
|
+
const { data } = await installOauthAppIntoDeveloperTestAccount(derivedAccountId, testAccountId, targetProjectName, targetAppUid);
|
|
53
|
+
if (data?.authCodes.length > 0) {
|
|
54
|
+
jsonOutput.authCode = data.authCodes[0].authCode;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
catch (err) {
|
|
58
|
+
logError(err);
|
|
59
|
+
process.exit(EXIT_CODES.ERROR);
|
|
60
|
+
}
|
|
61
|
+
SpinniesManager.init({
|
|
62
|
+
succeedColor: 'white',
|
|
63
|
+
});
|
|
64
|
+
SpinniesManager.add('installApp', {
|
|
65
|
+
text: commands.app.subcommands.install.polling.start,
|
|
66
|
+
});
|
|
67
|
+
let appInstallSucceeded = false;
|
|
68
|
+
try {
|
|
69
|
+
await poll(() => fetchDeveloperTestAccountOauthAppInstallStatus(derivedAccountId, targetProjectName, targetAppUid), {
|
|
70
|
+
successStates: ['SUCCESS'],
|
|
71
|
+
errorStates: [],
|
|
72
|
+
});
|
|
73
|
+
appInstallSucceeded = true;
|
|
74
|
+
}
|
|
75
|
+
catch (err) {
|
|
76
|
+
SpinniesManager.fail('installApp');
|
|
77
|
+
logError(err);
|
|
78
|
+
process.exit(EXIT_CODES.ERROR);
|
|
79
|
+
}
|
|
80
|
+
if (!appInstallSucceeded) {
|
|
81
|
+
SpinniesManager.fail('installApp');
|
|
82
|
+
process.exit(EXIT_CODES.ERROR);
|
|
83
|
+
}
|
|
84
|
+
SpinniesManager.succeed('installApp', {
|
|
85
|
+
text: commands.app.subcommands.install.polling.success,
|
|
86
|
+
});
|
|
87
|
+
if (formatOutputAsJson) {
|
|
88
|
+
uiLogger.json(jsonOutput);
|
|
89
|
+
}
|
|
90
|
+
process.exit(EXIT_CODES.SUCCESS);
|
|
91
|
+
}
|
|
92
|
+
function installAppBuilder(yargs) {
|
|
93
|
+
yargs.positional('test-account-id', {
|
|
94
|
+
describe: commands.app.subcommands.install.positionals.testAccountId,
|
|
95
|
+
required: true,
|
|
96
|
+
type: 'number',
|
|
97
|
+
});
|
|
98
|
+
yargs.option('app-uid', {
|
|
99
|
+
describe: commands.app.subcommands.install.options.appUid,
|
|
100
|
+
type: 'string',
|
|
101
|
+
});
|
|
102
|
+
yargs.option('project-name', {
|
|
103
|
+
describe: commands.app.subcommands.install.options.projectName,
|
|
104
|
+
type: 'string',
|
|
105
|
+
});
|
|
106
|
+
yargs.example('install 1234567890 --app-uid=my-app-uid --project-name=my-project', commands.app.subcommands.install.example);
|
|
107
|
+
return yargs;
|
|
108
|
+
}
|
|
109
|
+
const builder = makeYargsBuilder(installAppBuilder, command, commands.app.subcommands.install.describe, {
|
|
110
|
+
useGlobalOptions: true,
|
|
111
|
+
useAccountOptions: true,
|
|
112
|
+
useConfigOptions: true,
|
|
113
|
+
useEnvironmentOptions: true,
|
|
114
|
+
useJSONOutputOptions: true,
|
|
115
|
+
});
|
|
116
|
+
const installAppCommand = {
|
|
117
|
+
command,
|
|
118
|
+
describe,
|
|
119
|
+
handler,
|
|
120
|
+
builder,
|
|
121
|
+
};
|
|
122
|
+
export default installAppCommand;
|
package/commands/app.js
CHANGED
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
import migrateCommand from './app/migrate.js';
|
|
2
2
|
import appSecretCommand from './app/secret.js';
|
|
3
|
+
import installAppCommand from './app/install.js';
|
|
3
4
|
import { makeYargsBuilder } from '../lib/yargsUtils.js';
|
|
4
5
|
import { commands } from '../lang/en.js';
|
|
5
6
|
const command = ['app', 'apps'];
|
|
6
7
|
const describe = commands.app.describe;
|
|
7
8
|
function appBuilder(yargs) {
|
|
8
|
-
yargs
|
|
9
|
+
yargs
|
|
10
|
+
.command(migrateCommand)
|
|
11
|
+
.command(appSecretCommand)
|
|
12
|
+
.command(installAppCommand)
|
|
13
|
+
.demandCommand(1, '');
|
|
9
14
|
return yargs;
|
|
10
15
|
}
|
|
11
16
|
const builder = makeYargsBuilder(appBuilder, command, describe);
|
|
@@ -8,8 +8,8 @@ import { uiCommandReference } from '../../lib/ui/index.js';
|
|
|
8
8
|
import { commands, lib } from '../../lang/en.js';
|
|
9
9
|
import { uiLogger } from '../../lib/ui/logger.js';
|
|
10
10
|
import { logInBox } from '../../lib/ui/boxen.js';
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
import { renderInline } from '../../ui/index.js';
|
|
12
|
+
import { getWarningBox } from '../../ui/components/StatusMessageBoxes.js';
|
|
13
13
|
import { getHasMigratableThemes, migrateThemes2025_2, } from '../../lib/theme/migrate.js';
|
|
14
14
|
import { hasFeature } from '../../lib/hasFeature.js';
|
|
15
15
|
import { FEATURES } from '../../lib/constants.js';
|
|
@@ -24,20 +24,18 @@ async function handler(args) {
|
|
|
24
24
|
return process.exit(EXIT_CODES.ERROR);
|
|
25
25
|
}
|
|
26
26
|
if (projectConfig?.projectConfig) {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
// );
|
|
40
|
-
// }
|
|
27
|
+
if (!process.env.HUBSPOT_ENABLE_INK) {
|
|
28
|
+
await logInBox({
|
|
29
|
+
contents: lib.migrate.projectMigrationWarning,
|
|
30
|
+
options: { title: lib.migrate.projectMigrationWarningTitle },
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
await renderInline(getWarningBox({
|
|
35
|
+
title: lib.migrate.projectMigrationWarningTitle,
|
|
36
|
+
message: lib.migrate.projectMigrationWarning,
|
|
37
|
+
}));
|
|
38
|
+
}
|
|
41
39
|
}
|
|
42
40
|
const { derivedAccountId } = args;
|
|
43
41
|
try {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { CommonArgs, JSONOutputArgs, YargsCommandModule } from '../../types/Yargs.js';
|
|
2
|
-
type ProjectUploadArgs = CommonArgs & JSONOutputArgs & {
|
|
1
|
+
import { CommonArgs, EnvironmentArgs, JSONOutputArgs, YargsCommandModule } from '../../types/Yargs.js';
|
|
2
|
+
type ProjectUploadArgs = CommonArgs & JSONOutputArgs & EnvironmentArgs & {
|
|
3
3
|
forceCreate: boolean;
|
|
4
4
|
message: string;
|
|
5
5
|
m: string;
|
|
@@ -25,7 +25,7 @@ async function handler(args) {
|
|
|
25
25
|
validateProjectConfig(projectConfig, projectDir);
|
|
26
26
|
let targetAccountId;
|
|
27
27
|
if (useV3Api(projectConfig.platformVersion)) {
|
|
28
|
-
targetAccountId = await loadAndValidateProfile(projectConfig, projectDir, profile);
|
|
28
|
+
targetAccountId = await loadAndValidateProfile(projectConfig, projectDir, profile, args.useEnv);
|
|
29
29
|
}
|
|
30
30
|
targetAccountId = targetAccountId || derivedAccountId;
|
|
31
31
|
const accountConfig = getAccountConfig(targetAccountId);
|
|
@@ -75,6 +75,9 @@ async function handler(args) {
|
|
|
75
75
|
resultJson.personalAccessKey = createResult.personalAccessKey;
|
|
76
76
|
}
|
|
77
77
|
catch (err) {
|
|
78
|
+
SpinniesManager.fail('createTestAccount', {
|
|
79
|
+
text: commands.testAccount.create.polling.createFailure,
|
|
80
|
+
});
|
|
78
81
|
logError(err);
|
|
79
82
|
SpinniesManager.fail('createTestAccount', {
|
|
80
83
|
text: commands.testAccount.create.polling.createFailure,
|
package/lang/en.d.ts
CHANGED
|
@@ -1557,6 +1557,28 @@ ${string}`;
|
|
|
1557
1557
|
readonly app: {
|
|
1558
1558
|
readonly describe: "Commands for managing apps.";
|
|
1559
1559
|
readonly subcommands: {
|
|
1560
|
+
readonly install: {
|
|
1561
|
+
readonly describe: "Install an OAuth app into a test account.";
|
|
1562
|
+
readonly options: {
|
|
1563
|
+
readonly appUid: "The uid of the app to install";
|
|
1564
|
+
readonly projectName: "The name of the project that contains the app";
|
|
1565
|
+
};
|
|
1566
|
+
readonly positionals: {
|
|
1567
|
+
readonly testAccountId: "The id of the test account to install the app into";
|
|
1568
|
+
};
|
|
1569
|
+
readonly errors: {
|
|
1570
|
+
readonly mustSpecifyProjectName: `You must specify a project name. Use the ${string} flag to specify the project name or run this command from within a project directory.`;
|
|
1571
|
+
readonly noAppUidFound: `No app uid found. Please specify the app uid with the ${string} flag or run this command from within a project that contains an app.`;
|
|
1572
|
+
readonly appMustBeOauth: "This command only supports installing oauth apps. Please specify an app with oauth auth type.";
|
|
1573
|
+
};
|
|
1574
|
+
readonly polling: {
|
|
1575
|
+
readonly start: "Installing app...";
|
|
1576
|
+
readonly success: "App installed successfully";
|
|
1577
|
+
readonly failure: "App installation failed";
|
|
1578
|
+
readonly error: "Error installing app";
|
|
1579
|
+
};
|
|
1580
|
+
readonly example: "Install the app with uid my-app-uid from the project named \"my-project\" into the target account with id 1234567890";
|
|
1581
|
+
};
|
|
1560
1582
|
readonly secret: {
|
|
1561
1583
|
readonly describe: "Commands for managing secrets.";
|
|
1562
1584
|
readonly subcommands: {
|
package/lang/en.js
CHANGED
|
@@ -1555,6 +1555,28 @@ export const commands = {
|
|
|
1555
1555
|
app: {
|
|
1556
1556
|
describe: 'Commands for managing apps.',
|
|
1557
1557
|
subcommands: {
|
|
1558
|
+
install: {
|
|
1559
|
+
describe: 'Install an OAuth app into a test account.',
|
|
1560
|
+
options: {
|
|
1561
|
+
appUid: 'The uid of the app to install',
|
|
1562
|
+
projectName: 'The name of the project that contains the app',
|
|
1563
|
+
},
|
|
1564
|
+
positionals: {
|
|
1565
|
+
testAccountId: 'The id of the test account to install the app into',
|
|
1566
|
+
},
|
|
1567
|
+
errors: {
|
|
1568
|
+
mustSpecifyProjectName: `You must specify a project name. Use the ${uiCommandReference('--project-name')} flag to specify the project name or run this command from within a project directory.`,
|
|
1569
|
+
noAppUidFound: `No app uid found. Please specify the app uid with the ${uiCommandReference('--app-uid')} flag or run this command from within a project that contains an app.`,
|
|
1570
|
+
appMustBeOauth: 'This command only supports installing oauth apps. Please specify an app with oauth auth type.',
|
|
1571
|
+
},
|
|
1572
|
+
polling: {
|
|
1573
|
+
start: 'Installing app...',
|
|
1574
|
+
success: 'App installed successfully',
|
|
1575
|
+
failure: 'App installation failed',
|
|
1576
|
+
error: 'Error installing app',
|
|
1577
|
+
},
|
|
1578
|
+
example: 'Install the app with uid my-app-uid from the project named "my-project" into the target account with id 1234567890',
|
|
1579
|
+
},
|
|
1558
1580
|
secret: {
|
|
1559
1581
|
describe: 'Commands for managing secrets.',
|
|
1560
1582
|
subcommands: {
|
|
@@ -3,8 +3,8 @@ import { fetchFireAlarms } from '@hubspot/local-dev-lib/api/fireAlarm';
|
|
|
3
3
|
import { debugError } from '../errorHandlers/index.js';
|
|
4
4
|
import pkg from '../../package.json' with { type: 'json' };
|
|
5
5
|
import { logInBox } from '../ui/boxen.js';
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
import { renderInline } from '../../ui/index.js';
|
|
7
|
+
import { getWarningBox } from '../../ui/components/StatusMessageBoxes.js';
|
|
8
8
|
/*
|
|
9
9
|
* Versions can be formatted like this:
|
|
10
10
|
* =7.2.2 -> targets the exact version 7.2.2
|
|
@@ -100,22 +100,20 @@ async function logFireAlarms(accountId, command, version) {
|
|
|
100
100
|
}
|
|
101
101
|
return acc;
|
|
102
102
|
}, '');
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
103
|
+
if (!process.env.HUBSPOT_ENABLE_INK) {
|
|
104
|
+
await logInBox({
|
|
105
|
+
contents: notifications,
|
|
106
|
+
options: {
|
|
107
|
+
title: 'Notifications',
|
|
108
|
+
},
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
await renderInline(getWarningBox({
|
|
108
113
|
title: 'Notifications',
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
// await renderInline(
|
|
113
|
-
// getWarningBox({
|
|
114
|
-
// title: 'Notifications',
|
|
115
|
-
// message: notifications,
|
|
116
|
-
// })
|
|
117
|
-
// );
|
|
118
|
-
// }
|
|
114
|
+
message: notifications,
|
|
115
|
+
}));
|
|
116
|
+
}
|
|
119
117
|
}
|
|
120
118
|
}
|
|
121
119
|
export async function checkFireAlarms(argv) {
|
package/lib/projectProfiles.d.ts
CHANGED
|
@@ -4,4 +4,4 @@ export declare function logProfileHeader(profileName: string): void;
|
|
|
4
4
|
export declare function logProfileFooter(profile: HsProfileFile, includeVariables?: boolean): void;
|
|
5
5
|
export declare function loadProfile(projectConfig: ProjectConfig | null, projectDir: string | null, profileName: string): HsProfileFile | undefined;
|
|
6
6
|
export declare function exitIfUsingProfiles(projectConfig: ProjectConfig | null, projectDir: string | null): Promise<void>;
|
|
7
|
-
export declare function loadAndValidateProfile(projectConfig: ProjectConfig | null, projectDir: string | null, argsProfile: string | undefined): Promise<number | undefined>;
|
|
7
|
+
export declare function loadAndValidateProfile(projectConfig: ProjectConfig | null, projectDir: string | null, argsProfile: string | undefined, useEnv?: boolean): Promise<number | undefined>;
|
package/lib/projectProfiles.js
CHANGED
|
@@ -38,7 +38,12 @@ export function loadProfile(projectConfig, projectDir, profileName) {
|
|
|
38
38
|
uiLogger.error(lib.projectProfiles.loadProfile.errors.missingAccountId(profileFilename));
|
|
39
39
|
return;
|
|
40
40
|
}
|
|
41
|
-
return
|
|
41
|
+
return {
|
|
42
|
+
...profile,
|
|
43
|
+
accountId: process.env.HUBSPOT_ACCOUNT_ID
|
|
44
|
+
? Number(process.env.HUBSPOT_ACCOUNT_ID)
|
|
45
|
+
: profile.accountId,
|
|
46
|
+
};
|
|
42
47
|
}
|
|
43
48
|
catch (e) {
|
|
44
49
|
uiLogger.error(lib.projectProfiles.loadProfile.errors.failedToLoadProfile(profileFilename));
|
|
@@ -54,7 +59,7 @@ export async function exitIfUsingProfiles(projectConfig, projectDir) {
|
|
|
54
59
|
}
|
|
55
60
|
}
|
|
56
61
|
}
|
|
57
|
-
export async function loadAndValidateProfile(projectConfig, projectDir, argsProfile) {
|
|
62
|
+
export async function loadAndValidateProfile(projectConfig, projectDir, argsProfile, useEnv = false) {
|
|
58
63
|
if (argsProfile) {
|
|
59
64
|
logProfileHeader(argsProfile);
|
|
60
65
|
const profile = loadProfile(projectConfig, projectDir, argsProfile);
|
|
@@ -63,6 +68,9 @@ export async function loadAndValidateProfile(projectConfig, projectDir, argsProf
|
|
|
63
68
|
process.exit(EXIT_CODES.ERROR);
|
|
64
69
|
}
|
|
65
70
|
logProfileFooter(profile, true);
|
|
71
|
+
if (useEnv) {
|
|
72
|
+
return Number(process.env.HUBSPOT_ACCOUNT_ID);
|
|
73
|
+
}
|
|
66
74
|
return profile.accountId;
|
|
67
75
|
}
|
|
68
76
|
else {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ComponentTypes, Component, GenericComponentConfig, PublicAppComponentConfig, PrivateAppComponentConfig, AppCardComponentConfig } from '../../types/Projects.js';
|
|
2
|
-
import { IntermediateRepresentationNodeLocalDev } from '@hubspot/project-parsing-lib/src/lib/types.js';
|
|
2
|
+
import { IntermediateRepresentationNode, IntermediateRepresentationNodeLocalDev } from '@hubspot/project-parsing-lib/src/lib/types.js';
|
|
3
3
|
import { AppIRNode } from '../../types/ProjectComponents.js';
|
|
4
4
|
export declare const CONFIG_FILES: {
|
|
5
5
|
[k in ComponentTypes]: string;
|
|
@@ -15,4 +15,4 @@ export declare function getProjectComponentTypes(components: Array<Component>):
|
|
|
15
15
|
export declare function getComponentUid(component?: Component | null): string | null;
|
|
16
16
|
export declare function componentIsApp(component?: Component | null): component is Component<PublicAppComponentConfig | PrivateAppComponentConfig>;
|
|
17
17
|
export declare function componentIsPublicApp(component?: Component | null): component is Component<PublicAppComponentConfig>;
|
|
18
|
-
export declare function isAppIRNode(component: IntermediateRepresentationNodeLocalDev): component is AppIRNode;
|
|
18
|
+
export declare function isAppIRNode(component: IntermediateRepresentationNodeLocalDev | IntermediateRepresentationNode): component is AppIRNode;
|
package/lib/projects/upload.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { FileResult } from 'tmp';
|
|
2
|
+
import { IntermediateRepresentation } from '@hubspot/project-parsing-lib';
|
|
2
3
|
import { ProjectConfig } from '../../types/Projects.js';
|
|
3
4
|
type ProjectUploadCallbackFunction<T> = (accountId: number, projectConfig: ProjectConfig, tempFile: FileResult, buildId: number) => Promise<T>;
|
|
4
5
|
type ProjectUploadResult<T> = {
|
|
@@ -20,5 +21,5 @@ type HandleProjectUploadArg<T> = {
|
|
|
20
21
|
export declare function handleProjectUpload<T>({ accountId, projectConfig, projectDir, callbackFunc, profile, uploadMessage, forceCreate, isUploadCommand, sendIR, skipValidation, }: HandleProjectUploadArg<T>): Promise<ProjectUploadResult<T>>;
|
|
21
22
|
export declare function validateSourceDirectory(srcDir: string, projectConfig: ProjectConfig): void;
|
|
22
23
|
export declare function validateNoHSMetaMismatch(srcDir: string, projectConfig: ProjectConfig): Promise<void>;
|
|
23
|
-
export declare function handleTranslate(projectDir: string, projectConfig: ProjectConfig, accountId: number, skipValidation: boolean, profile: string | undefined): Promise<
|
|
24
|
+
export declare function handleTranslate(projectDir: string, projectConfig: ProjectConfig, accountId: number, skipValidation: boolean, profile: string | undefined): Promise<IntermediateRepresentation | undefined>;
|
|
24
25
|
export {};
|
package/lib/projects/upload.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hubspot/cli",
|
|
3
|
-
"version": "7.8.
|
|
3
|
+
"version": "7.8.12-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",
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
"express": "4.21.2",
|
|
21
21
|
"findup-sync": "4.0.0",
|
|
22
22
|
"fs-extra": "8.1.0",
|
|
23
|
+
"ink": "5.2.1",
|
|
23
24
|
"inquirer": "12.7.0",
|
|
24
25
|
"js-yaml": "4.1.0",
|
|
25
26
|
"moment": "2.30.1",
|
|
@@ -55,7 +56,6 @@
|
|
|
55
56
|
"eslint": "^8.56.0",
|
|
56
57
|
"eslint-plugin-import": "^2.31.0",
|
|
57
58
|
"husky": "^4.3.8",
|
|
58
|
-
"ink": "5.2.1",
|
|
59
59
|
"lint-staged": "^10.5.4",
|
|
60
60
|
"madge": "^8.0.0",
|
|
61
61
|
"mock-stdin": "^1.0.0",
|
package/types/Yargs.d.ts
CHANGED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export interface BoxWithTitleProps {
|
|
2
|
+
title: string;
|
|
3
|
+
message: string;
|
|
4
|
+
titleBackgroundColor?: string;
|
|
5
|
+
borderColor?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function getBoxWithTitle(props: BoxWithTitleProps): React.ReactNode;
|
|
8
|
+
export declare function BoxWithTitle({ title, message, titleBackgroundColor, borderColor, }: BoxWithTitleProps): React.ReactNode;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Box, Text } from 'ink';
|
|
3
|
+
import { CONTAINER_STYLES } from '../styles.js';
|
|
4
|
+
export function getBoxWithTitle(props) {
|
|
5
|
+
return _jsx(BoxWithTitle, { ...props });
|
|
6
|
+
}
|
|
7
|
+
export function BoxWithTitle({ title, message, titleBackgroundColor, borderColor, }) {
|
|
8
|
+
return (_jsxs(Box, { ...CONTAINER_STYLES, borderStyle: "round", borderColor: borderColor, children: [_jsx(Box, { position: "absolute", marginTop: -2, paddingX: 0, alignSelf: "flex-start", justifyContent: "center", alignItems: "center", children: _jsx(Text, { backgroundColor: titleBackgroundColor, bold: true, children: ` ${title} ` }) }), _jsx(Box, { justifyContent: "center", alignItems: "center", children: _jsx(Text, { children: message }) })] }));
|
|
9
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export interface HorizontalSelectPromptProps {
|
|
2
|
+
defaultOption?: string;
|
|
3
|
+
options: string[];
|
|
4
|
+
onSelect: (value: string) => void;
|
|
5
|
+
prompt?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function getHorizontalSelectPrompt(props: HorizontalSelectPromptProps): React.ReactNode;
|
|
8
|
+
export declare function HorizontalSelectPrompt({ defaultOption, options, onSelect, prompt, }: HorizontalSelectPromptProps): React.ReactNode;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Box, Text, useInput } from 'ink';
|
|
3
|
+
import { useState } from 'react';
|
|
4
|
+
import { CONTAINER_STYLES, INK_COLORS } from '../styles.js';
|
|
5
|
+
export function getHorizontalSelectPrompt(props) {
|
|
6
|
+
return _jsx(HorizontalSelectPrompt, { ...props });
|
|
7
|
+
}
|
|
8
|
+
export function HorizontalSelectPrompt({ defaultOption, options, onSelect, prompt, }) {
|
|
9
|
+
const [selectedIndex, setSelectedIndex] = useState(defaultOption && options.indexOf(defaultOption) !== -1
|
|
10
|
+
? options.indexOf(defaultOption)
|
|
11
|
+
: 0);
|
|
12
|
+
const moveRight = () => {
|
|
13
|
+
setSelectedIndex(prev => (prev < options.length - 1 ? prev + 1 : 0));
|
|
14
|
+
};
|
|
15
|
+
const moveLeft = () => {
|
|
16
|
+
setSelectedIndex(prev => (prev > 0 ? prev - 1 : options.length - 1));
|
|
17
|
+
};
|
|
18
|
+
useInput((_, key) => {
|
|
19
|
+
if (key.leftArrow) {
|
|
20
|
+
moveLeft();
|
|
21
|
+
}
|
|
22
|
+
else if (key.rightArrow) {
|
|
23
|
+
moveRight();
|
|
24
|
+
}
|
|
25
|
+
else if (key.return) {
|
|
26
|
+
onSelect(options[selectedIndex]);
|
|
27
|
+
}
|
|
28
|
+
});
|
|
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
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface StatusMessageBoxProps {
|
|
2
|
+
title: string;
|
|
3
|
+
message: string;
|
|
4
|
+
}
|
|
5
|
+
export declare function getWarningBox(props: StatusMessageBoxProps): React.ReactNode;
|
|
6
|
+
export declare function WarningBox({ title, message, }: StatusMessageBoxProps): React.ReactNode;
|
|
7
|
+
export declare function getAlertBox(props: StatusMessageBoxProps): React.ReactNode;
|
|
8
|
+
export declare function AlertBox({ title, message, }: StatusMessageBoxProps): React.ReactNode;
|
|
9
|
+
export declare function getSuccessBox(props: StatusMessageBoxProps): React.ReactNode;
|
|
10
|
+
export declare function SuccessBox({ title, message, }: StatusMessageBoxProps): React.ReactNode;
|
|
11
|
+
export declare function getInfoBox(props: StatusMessageBoxProps): React.ReactNode;
|
|
12
|
+
export declare function InfoBox({ title, message, }: StatusMessageBoxProps): React.ReactNode;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { INK_COLORS } from '../styles.js';
|
|
3
|
+
import { BoxWithTitle } from './BoxWithTitle.js';
|
|
4
|
+
export function getWarningBox(props) {
|
|
5
|
+
return _jsx(WarningBox, { ...props });
|
|
6
|
+
}
|
|
7
|
+
export function WarningBox({ title, message, }) {
|
|
8
|
+
const color = INK_COLORS.WARNING_YELLOW;
|
|
9
|
+
return (_jsx(BoxWithTitle, { title: title, message: message, titleBackgroundColor: color, borderColor: color }));
|
|
10
|
+
}
|
|
11
|
+
export function getAlertBox(props) {
|
|
12
|
+
return _jsx(AlertBox, { ...props });
|
|
13
|
+
}
|
|
14
|
+
export function AlertBox({ title, message, }) {
|
|
15
|
+
const color = INK_COLORS.ALERT_RED;
|
|
16
|
+
return (_jsx(BoxWithTitle, { title: title, message: message, titleBackgroundColor: color, borderColor: color }));
|
|
17
|
+
}
|
|
18
|
+
export function getSuccessBox(props) {
|
|
19
|
+
return _jsx(SuccessBox, { ...props });
|
|
20
|
+
}
|
|
21
|
+
export function SuccessBox({ title, message, }) {
|
|
22
|
+
const color = INK_COLORS.SUCCESS_GREEN;
|
|
23
|
+
return (_jsx(BoxWithTitle, { title: title, message: message, titleBackgroundColor: color, borderColor: color }));
|
|
24
|
+
}
|
|
25
|
+
export function getInfoBox(props) {
|
|
26
|
+
return _jsx(InfoBox, { ...props });
|
|
27
|
+
}
|
|
28
|
+
export function InfoBox({ title, message, }) {
|
|
29
|
+
const color = INK_COLORS.INFO_BLUE;
|
|
30
|
+
return (_jsx(BoxWithTitle, { title: title, message: message, titleBackgroundColor: color, borderColor: color }));
|
|
31
|
+
}
|
package/ui/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function renderInline(component: React.ReactNode): Promise<void>;
|
package/ui/index.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export type ComponentPropPair = {
|
|
2
|
+
component: React.ReactNode;
|
|
3
|
+
signature: string;
|
|
4
|
+
};
|
|
5
|
+
/**
|
|
6
|
+
* These components will be used by the sandbox ui. Please add any new components here.
|
|
7
|
+
*/
|
|
8
|
+
export declare const populatedComponents: Record<string, ComponentPropPair>;
|
|
9
|
+
export declare function getComponentOptions(): string[];
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { getSuccessBox, getInfoBox, getWarningBox, getAlertBox, } from '../components/StatusMessageBoxes.js';
|
|
2
|
+
import { getBoxWithTitle } from '../components/BoxWithTitle.js';
|
|
3
|
+
import { SuccessBox, InfoBox, WarningBox, AlertBox, } from '../components/StatusMessageBoxes.js';
|
|
4
|
+
import { BoxWithTitle } from '../components/BoxWithTitle.js';
|
|
5
|
+
/**
|
|
6
|
+
* These components will be used by the sandbox ui. Please add any new components here.
|
|
7
|
+
*/
|
|
8
|
+
export const populatedComponents = {
|
|
9
|
+
SuccessBox: {
|
|
10
|
+
component: getSuccessBox({
|
|
11
|
+
title: 'Success',
|
|
12
|
+
message: 'This is a success message',
|
|
13
|
+
}),
|
|
14
|
+
signature: SuccessBox.toString(),
|
|
15
|
+
},
|
|
16
|
+
InfoBox: {
|
|
17
|
+
component: getInfoBox({
|
|
18
|
+
title: 'Info',
|
|
19
|
+
message: 'This is an info message',
|
|
20
|
+
}),
|
|
21
|
+
signature: InfoBox.toString(),
|
|
22
|
+
},
|
|
23
|
+
WarningBox: {
|
|
24
|
+
component: getWarningBox({
|
|
25
|
+
title: 'Warning',
|
|
26
|
+
message: 'This is a warning message',
|
|
27
|
+
}),
|
|
28
|
+
signature: WarningBox.toString(),
|
|
29
|
+
},
|
|
30
|
+
AlertBox: {
|
|
31
|
+
component: getAlertBox({
|
|
32
|
+
title: 'Alert',
|
|
33
|
+
message: 'This is an alert message',
|
|
34
|
+
}),
|
|
35
|
+
signature: AlertBox.toString(),
|
|
36
|
+
},
|
|
37
|
+
BoxWithTitle: {
|
|
38
|
+
component: getBoxWithTitle({
|
|
39
|
+
title: 'Title',
|
|
40
|
+
message: 'This is a box with a title',
|
|
41
|
+
}),
|
|
42
|
+
signature: BoxWithTitle.toString(),
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
export function getComponentOptions() {
|
|
46
|
+
return Object.keys(populatedComponents);
|
|
47
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This hook is used to get the current terminal size.
|
|
3
|
+
* It will return the current terminal size, and if a component is using this hook to set height/width,
|
|
4
|
+
* it will re-render when the terminal size changes.
|
|
5
|
+
* ONLY USE THIS HOOK WITH SCREENS. THIS HOOK WILL DESTROY ANY PRIOR LOG OUTPUT IF USED TO SET HEIGHT/WIDTH.
|
|
6
|
+
* @param minHeight - The minimum height of the terminal.
|
|
7
|
+
* @param minWidth - The minimum width of the terminal.
|
|
8
|
+
* @returns The current terminal size.
|
|
9
|
+
*/
|
|
10
|
+
export declare function useTerminalSize(minHeight?: number, minWidth?: number): {
|
|
11
|
+
columns: number;
|
|
12
|
+
rows: number;
|
|
13
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { useStdout } from 'ink';
|
|
2
|
+
import { useEffect, useState } from 'react';
|
|
3
|
+
/**
|
|
4
|
+
* This hook is used to get the current terminal size.
|
|
5
|
+
* It will return the current terminal size, and if a component is using this hook to set height/width,
|
|
6
|
+
* it will re-render when the terminal size changes.
|
|
7
|
+
* ONLY USE THIS HOOK WITH SCREENS. THIS HOOK WILL DESTROY ANY PRIOR LOG OUTPUT IF USED TO SET HEIGHT/WIDTH.
|
|
8
|
+
* @param minHeight - The minimum height of the terminal.
|
|
9
|
+
* @param minWidth - The minimum width of the terminal.
|
|
10
|
+
* @returns The current terminal size.
|
|
11
|
+
*/
|
|
12
|
+
export function useTerminalSize(minHeight, minWidth) {
|
|
13
|
+
const { stdout } = useStdout();
|
|
14
|
+
const [size, setSize] = useState({
|
|
15
|
+
columns: Math.max(stdout.columns, minWidth ?? 0),
|
|
16
|
+
rows: Math.max(stdout.rows, minHeight ?? 0),
|
|
17
|
+
});
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
const handleResize = () => {
|
|
20
|
+
setSize({
|
|
21
|
+
columns: Math.max(stdout.columns, minWidth ?? 0),
|
|
22
|
+
rows: Math.max(stdout.rows, minHeight ?? 0),
|
|
23
|
+
});
|
|
24
|
+
};
|
|
25
|
+
stdout.on('resize', handleResize);
|
|
26
|
+
return () => {
|
|
27
|
+
stdout.off('resize', handleResize);
|
|
28
|
+
};
|
|
29
|
+
}, [stdout]);
|
|
30
|
+
return size;
|
|
31
|
+
}
|
package/ui/styles.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export declare const CONTAINER_STYLES: {
|
|
2
|
+
readonly padding: 1;
|
|
3
|
+
readonly marginY: 0.5;
|
|
4
|
+
readonly flexDirection: "column";
|
|
5
|
+
readonly flexWrap: "wrap";
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* Any color that can be used well in both WHITE and BLACK terminals.
|
|
9
|
+
* This is a best effort to ensure that the color is good looking in both
|
|
10
|
+
* light and dark modes.
|
|
11
|
+
*/
|
|
12
|
+
export declare const INK_COLORS: {
|
|
13
|
+
ALERT_RED: string;
|
|
14
|
+
SUCCESS_GREEN: string;
|
|
15
|
+
INFO_BLUE: string;
|
|
16
|
+
WARNING_YELLOW: string;
|
|
17
|
+
WHITE: string;
|
|
18
|
+
};
|
package/ui/styles.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export const CONTAINER_STYLES = {
|
|
2
|
+
padding: 1,
|
|
3
|
+
marginY: 0.5,
|
|
4
|
+
flexDirection: 'column',
|
|
5
|
+
flexWrap: 'wrap',
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* Any color that can be used well in both WHITE and BLACK terminals.
|
|
9
|
+
* This is a best effort to ensure that the color is good looking in both
|
|
10
|
+
* light and dark modes.
|
|
11
|
+
*/
|
|
12
|
+
export const INK_COLORS = {
|
|
13
|
+
ALERT_RED: '#fc7272',
|
|
14
|
+
SUCCESS_GREEN: '#4deb7a',
|
|
15
|
+
INFO_BLUE: '#4dcbeb',
|
|
16
|
+
WARNING_YELLOW: '#EEB117',
|
|
17
|
+
WHITE: 'white',
|
|
18
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Box, Text } from 'ink';
|
|
3
|
+
import { useState } from 'react';
|
|
4
|
+
import { HorizontalSelectPrompt } from '../components/HorizontalSelectPrompt.js';
|
|
5
|
+
import { getComponentOptions, populatedComponents, } from '../lib/ui-testing-utils.js';
|
|
6
|
+
import { useTerminalSize } from '../lib/useTerminalSize.js';
|
|
7
|
+
import { CONTAINER_STYLES } from '../styles.js';
|
|
8
|
+
export function getUiSandbox(props) {
|
|
9
|
+
return _jsx(UiSandbox, { ...props });
|
|
10
|
+
}
|
|
11
|
+
export function UiSandbox({ componentName }) {
|
|
12
|
+
const componentOptions = getComponentOptions();
|
|
13
|
+
const [selectedComponent, setSelectedComponent] = useState(componentName ? populatedComponents[componentName] : undefined);
|
|
14
|
+
const mapStringToComponent = (str) => {
|
|
15
|
+
setSelectedComponent(populatedComponents[str] || undefined);
|
|
16
|
+
};
|
|
17
|
+
const getFunctionArguments = (signature) => {
|
|
18
|
+
const startIndex = signature.indexOf('(');
|
|
19
|
+
const endIndex = signature.indexOf(')');
|
|
20
|
+
const functionArgs = signature.slice(startIndex, endIndex + 1);
|
|
21
|
+
return functionArgs;
|
|
22
|
+
};
|
|
23
|
+
const size = useTerminalSize(20);
|
|
24
|
+
return (_jsxs(Box, { flexDirection: "column", height: size.rows, children: [_jsx(HorizontalSelectPrompt, { defaultOption: componentName, options: componentOptions, onSelect: mapStringToComponent }), selectedComponent?.component, selectedComponent?.signature && (_jsxs(Box, { ...CONTAINER_STYLES, gap: 1, borderStyle: "classic", children: [_jsx(Text, { children: "Signature:" }), _jsx(Text, { children: getFunctionArguments(selectedComponent?.signature) })] }))] }));
|
|
25
|
+
}
|