@mittwald/cli 1.0.0-alpha.11 → 1.0.0-alpha.13
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/README.md +1136 -579
- package/dist/esm/DeleteBaseCommand.js +1 -1
- package/dist/esm/Helpers.d.ts +1 -0
- package/dist/esm/Helpers.js +7 -1
- package/dist/esm/Translator.d.ts +1 -0
- package/dist/esm/Translator.js +11 -0
- package/dist/esm/commands/app/install/wordpress.js +1 -1
- package/dist/esm/commands/context/set.js +4 -3
- package/dist/esm/commands/database/mysql/charsets.d.ts +14 -3
- package/dist/esm/commands/database/mysql/charsets.js +25 -2
- package/dist/esm/commands/database/mysql/create.d.ts +23 -0
- package/dist/esm/commands/database/mysql/create.js +103 -0
- package/dist/esm/commands/database/mysql/delete.d.ts +14 -0
- package/dist/esm/commands/database/mysql/delete.js +20 -0
- package/dist/esm/commands/database/mysql/dump.d.ts +15 -0
- package/dist/esm/commands/database/mysql/dump.js +70 -0
- package/dist/esm/commands/database/mysql/get.d.ts +14 -2
- package/dist/esm/commands/database/mysql/get.js +14 -5
- package/dist/esm/commands/database/mysql/list.d.ts +11 -3
- package/dist/esm/commands/database/mysql/list.js +23 -13
- package/dist/esm/commands/database/mysql/phpmyadmin.d.ts +8 -0
- package/dist/esm/commands/database/mysql/phpmyadmin.js +25 -0
- package/dist/esm/commands/database/mysql/port-forward.d.ts +14 -0
- package/dist/esm/commands/database/mysql/port-forward.js +44 -0
- package/dist/esm/commands/database/mysql/shell.d.ts +14 -0
- package/dist/esm/commands/database/mysql/shell.js +39 -0
- package/dist/esm/commands/database/mysql/user/get.d.ts +13 -2
- package/dist/esm/commands/database/mysql/user/get.js +18 -5
- package/dist/esm/commands/database/mysql/user/list.d.ts +13 -3
- package/dist/esm/commands/database/mysql/user/list.js +38 -2
- package/dist/esm/commands/database/mysql/versions.d.ts +13 -3
- package/dist/esm/commands/database/mysql/versions.js +19 -2
- package/dist/esm/commands/database/redis/get.d.ts +15 -2
- package/dist/esm/commands/database/redis/get.js +21 -5
- package/dist/esm/commands/database/redis/list.d.ts +13 -3
- package/dist/esm/commands/database/redis/list.js +26 -2
- package/dist/esm/commands/database/redis/shell.d.ts +13 -0
- package/dist/esm/commands/database/redis/shell.js +26 -0
- package/dist/esm/commands/database/redis/versions.d.ts +11 -3
- package/dist/esm/commands/database/redis/versions.js +12 -2
- package/dist/esm/commands/domain/virtualhost/create.js +1 -1
- package/dist/esm/commands/login/reset.js +1 -1
- package/dist/esm/commands/mail/address/create.d.ts +1 -1
- package/dist/esm/commands/mail/address/create.js +1 -1
- package/dist/esm/commands/org/delete.js +2 -3
- package/dist/esm/commands/org/invite/revoke.js +1 -1
- package/dist/esm/commands/org/invite.js +1 -1
- package/dist/esm/commands/org/list.js +4 -0
- package/dist/esm/commands/org/membership/revoke.js +1 -1
- package/dist/esm/commands/project/create.js +1 -1
- package/dist/esm/commands/project/get.js +8 -4
- package/dist/esm/commands/project/list-react.js +1 -1
- package/dist/esm/commands/user/api-token/create.js +1 -1
- package/dist/esm/commands/user/ssh-key/create.js +1 -1
- package/dist/esm/lib/database/common.d.ts +8 -0
- package/dist/esm/lib/database/common.js +17 -0
- package/dist/esm/lib/database/mysql/connect.d.ts +19 -0
- package/dist/esm/lib/database/mysql/connect.js +50 -0
- package/dist/esm/lib/database/mysql/flags.d.ts +10 -0
- package/dist/esm/lib/database/mysql/flags.js +48 -0
- package/dist/esm/lib/database/redis/connect.d.ts +8 -0
- package/dist/esm/lib/database/redis/connect.js +22 -0
- package/dist/esm/lib/database/redis/flags.d.ts +7 -0
- package/dist/esm/lib/database/redis/flags.js +35 -0
- package/dist/esm/lib/org/flags.js +2 -1
- package/dist/esm/rendering/process/components/ProcessConfirmation.d.ts +6 -0
- package/dist/esm/rendering/process/components/ProcessConfirmation.js +12 -0
- package/dist/esm/rendering/process/components/ProcessConfirmationStateSummary.d.ts +5 -0
- package/dist/esm/rendering/process/components/ProcessConfirmationStateSummary.js +18 -0
- package/dist/esm/rendering/process/components/ProcessError.d.ts +4 -0
- package/dist/esm/rendering/process/components/ProcessError.js +10 -0
- package/dist/esm/rendering/process/components/ProcessInput.d.ts +6 -0
- package/dist/esm/rendering/process/components/ProcessInput.js +15 -0
- package/dist/esm/rendering/process/components/ProcessInputStateSummary.d.ts +5 -0
- package/dist/esm/rendering/process/components/ProcessInputStateSummary.js +13 -0
- package/dist/esm/rendering/process/components/ProcessState.d.ts +5 -0
- package/dist/esm/rendering/process/components/ProcessState.js +8 -0
- package/dist/esm/rendering/process/components/ProcessStateIcon.d.ts +5 -0
- package/dist/esm/rendering/process/components/ProcessStateIcon.js +22 -0
- package/dist/esm/rendering/process/components/ProcessStateSummary.d.ts +5 -0
- package/dist/esm/rendering/process/components/ProcessStateSummary.js +27 -0
- package/dist/esm/rendering/process/components/ProcessValidationErrors.d.ts +7 -0
- package/dist/esm/rendering/process/components/ProcessValidationErrors.js +15 -0
- package/dist/esm/rendering/{react → process}/process.d.ts +5 -5
- package/dist/esm/rendering/{react → process}/process_fancy.d.ts +1 -12
- package/dist/esm/rendering/process/process_fancy.js +119 -0
- package/dist/esm/rendering/process/process_flags.d.ts +20 -0
- package/dist/esm/rendering/{react → process}/process_flags.js +13 -0
- package/dist/esm/rendering/{react → process}/process_quiet.d.ts +2 -2
- package/dist/esm/rendering/react/components/ErrorBox.d.ts +11 -0
- package/dist/esm/rendering/react/components/ErrorBox.js +45 -0
- package/dist/esm/rendering/react/components/{ProjectReadiness.js → Project/ProjectReadiness.js} +1 -1
- package/dist/esm/rendering/react/components/Project/ProjectStatus.d.ts +18 -0
- package/dist/esm/rendering/react/error.d.ts +6 -0
- package/dist/esm/rendering/react/error.js +9 -40
- package/package.json +25 -5
- package/dist/esm/commands/database/mysql/user/getMysqlUserPhpMyAdminUrl.d.ts +0 -3
- package/dist/esm/commands/database/mysql/user/getMysqlUserPhpMyAdminUrl.js +0 -7
- package/dist/esm/generated/database/getMysqlDatabase.d.ts +0 -16
- package/dist/esm/generated/database/getMysqlDatabase.js +0 -25
- package/dist/esm/generated/database/getMysqlUser.d.ts +0 -16
- package/dist/esm/generated/database/getMysqlUser.js +0 -25
- package/dist/esm/generated/database/getMysqlUserPhpMyAdminUrl.d.ts +0 -14
- package/dist/esm/generated/database/getMysqlUserPhpMyAdminUrl.js +0 -24
- package/dist/esm/generated/database/getRedisDatabase.d.ts +0 -16
- package/dist/esm/generated/database/getRedisDatabase.js +0 -25
- package/dist/esm/generated/database/listMysqlCharsets.d.ts +0 -13
- package/dist/esm/generated/database/listMysqlCharsets.js +0 -17
- package/dist/esm/generated/database/listMysqlDatabases.d.ts +0 -13
- package/dist/esm/generated/database/listMysqlDatabases.js +0 -24
- package/dist/esm/generated/database/listMysqlUsers.d.ts +0 -13
- package/dist/esm/generated/database/listMysqlUsers.js +0 -24
- package/dist/esm/generated/database/listMysqlVersions.d.ts +0 -13
- package/dist/esm/generated/database/listMysqlVersions.js +0 -17
- package/dist/esm/generated/database/listRedisDatabases.d.ts +0 -13
- package/dist/esm/generated/database/listRedisDatabases.js +0 -24
- package/dist/esm/generated/database/listRedisVersions.d.ts +0 -13
- package/dist/esm/generated/database/listRedisVersions.js +0 -17
- package/dist/esm/rendering/react/components/ProjectStatus.d.ts +0 -7
- package/dist/esm/rendering/react/process_fancy.js +0 -221
- package/dist/esm/rendering/react/process_flags.d.ts +0 -9
- /package/dist/esm/rendering/{react → process}/process.js +0 -0
- /package/dist/esm/rendering/{react → process}/process_quiet.js +0 -0
- /package/dist/esm/rendering/react/components/{ProjectEnabled.d.ts → Project/ProjectEnabled.d.ts} +0 -0
- /package/dist/esm/rendering/react/components/{ProjectEnabled.js → Project/ProjectEnabled.js} +0 -0
- /package/dist/esm/rendering/react/components/{ProjectReadiness.d.ts → Project/ProjectReadiness.d.ts} +0 -0
- /package/dist/esm/rendering/react/components/{ProjectStatus.js → Project/ProjectStatus.js} +0 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { ProcessRenderer } from "../../../rendering/process/process.js";
|
|
2
|
+
import { MittwaldAPIV2Client } from "@mittwald/api-client";
|
|
3
|
+
export declare function getConnectionDetailsWithPassword(apiClient: MittwaldAPIV2Client, databaseId: string, p: ProcessRenderer, flags: {
|
|
4
|
+
"mysql-password": string | undefined;
|
|
5
|
+
}): Promise<{
|
|
6
|
+
password: string;
|
|
7
|
+
hostname: string;
|
|
8
|
+
database: string;
|
|
9
|
+
user: string;
|
|
10
|
+
sshHost: string;
|
|
11
|
+
sshUser: string;
|
|
12
|
+
}>;
|
|
13
|
+
export declare function getConnectionDetails(apiClient: MittwaldAPIV2Client, databaseId: string, p: ProcessRenderer): Promise<{
|
|
14
|
+
hostname: string;
|
|
15
|
+
database: string;
|
|
16
|
+
user: string;
|
|
17
|
+
sshHost: string;
|
|
18
|
+
sshUser: string;
|
|
19
|
+
}>;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { assertStatus } from "@mittwald/api-client-commons";
|
|
2
|
+
import { getProject, getUser } from "../common.js";
|
|
3
|
+
export async function getConnectionDetailsWithPassword(apiClient, databaseId, p, flags) {
|
|
4
|
+
const password = await getPassword(p, flags);
|
|
5
|
+
return {
|
|
6
|
+
...(await getConnectionDetails(apiClient, databaseId, p)),
|
|
7
|
+
password,
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
export async function getConnectionDetails(apiClient, databaseId, p) {
|
|
11
|
+
const database = await getDatabase(apiClient, p, databaseId);
|
|
12
|
+
const databaseUser = await getDatabaseUser(apiClient, p, databaseId);
|
|
13
|
+
const project = await getProject(apiClient, p, database);
|
|
14
|
+
const user = await getUser(apiClient, p);
|
|
15
|
+
return {
|
|
16
|
+
hostname: database.hostname,
|
|
17
|
+
database: database.name,
|
|
18
|
+
user: databaseUser.name,
|
|
19
|
+
sshHost: `ssh.${project.clusterID}.${project.clusterDomain}`,
|
|
20
|
+
sshUser: `${user.email}@${project.shortId}`,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
async function getPassword(p, flags) {
|
|
24
|
+
if (flags["mysql-password"]) {
|
|
25
|
+
return flags["mysql-password"];
|
|
26
|
+
}
|
|
27
|
+
return await p.addInput("enter password for MySQL user", true);
|
|
28
|
+
}
|
|
29
|
+
async function getDatabase(apiClient, p, id) {
|
|
30
|
+
return await p.runStep("fetching database", async () => {
|
|
31
|
+
const r = await apiClient.database.getMysqlDatabase({
|
|
32
|
+
pathParameters: { id },
|
|
33
|
+
});
|
|
34
|
+
assertStatus(r, 200);
|
|
35
|
+
return r.data;
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
async function getDatabaseUser(apiClient, p, databaseId) {
|
|
39
|
+
return await p.runStep("fetching main user", async () => {
|
|
40
|
+
const r = await apiClient.database.listMysqlUsers({
|
|
41
|
+
pathParameters: { databaseId },
|
|
42
|
+
});
|
|
43
|
+
assertStatus(r, 200);
|
|
44
|
+
const mainUser = r.data.find((u) => u.mainUser);
|
|
45
|
+
if (!mainUser) {
|
|
46
|
+
throw new Error("No main user found");
|
|
47
|
+
}
|
|
48
|
+
return mainUser;
|
|
49
|
+
});
|
|
50
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Config } from "@oclif/core";
|
|
2
|
+
import { MittwaldAPIV2Client } from "@mittwald/api-client";
|
|
3
|
+
import { ArgOutput, FlagOutput } from "@oclif/core/lib/interfaces/parser.js";
|
|
4
|
+
export declare const mysqlConnectionFlags: {
|
|
5
|
+
"mysql-password": import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
6
|
+
};
|
|
7
|
+
export declare const mysqlArgs: {
|
|
8
|
+
"database-id": import("@oclif/core/lib/interfaces/parser.js").Arg<string, Record<string, unknown>>;
|
|
9
|
+
};
|
|
10
|
+
export declare function withMySQLId(apiClient: MittwaldAPIV2Client, flags: FlagOutput, args: ArgOutput, cfg: Config): Promise<string>;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { Args, Flags } from "@oclif/core";
|
|
2
|
+
import { isUuid } from "../../../Helpers.js";
|
|
3
|
+
import { withProjectId } from "../../project/flags.js";
|
|
4
|
+
import { assertStatus } from "@mittwald/api-client-commons";
|
|
5
|
+
export const mysqlConnectionFlags = {
|
|
6
|
+
"mysql-password": Flags.string({
|
|
7
|
+
char: "p",
|
|
8
|
+
summary: "the password to use for the MySQL user (env: MYSQL_PWD)",
|
|
9
|
+
description: `\
|
|
10
|
+
The password to use for the MySQL user. If not provided, the environment variable MYSQL_PWD will be used. If that is not set either, the command will interactively ask for the password.
|
|
11
|
+
|
|
12
|
+
NOTE: This is a security risk, as the password will be visible in the process list of your system, and will be visible in your Shell history. It is recommended to use the environment variable instead.\
|
|
13
|
+
`,
|
|
14
|
+
required: false,
|
|
15
|
+
env: "MYSQL_PWD",
|
|
16
|
+
}),
|
|
17
|
+
};
|
|
18
|
+
export const mysqlArgs = {
|
|
19
|
+
"database-id": Args.string({
|
|
20
|
+
description: "The ID of the database (when a project context is set, you can also use the name)",
|
|
21
|
+
required: true,
|
|
22
|
+
}),
|
|
23
|
+
};
|
|
24
|
+
function getIdCandidate(flags, args) {
|
|
25
|
+
if (args["database-id"]) {
|
|
26
|
+
return args["database-id"];
|
|
27
|
+
}
|
|
28
|
+
if (flags["database-id"]) {
|
|
29
|
+
return flags["database-id"];
|
|
30
|
+
}
|
|
31
|
+
throw new Error("No ID given");
|
|
32
|
+
}
|
|
33
|
+
export async function withMySQLId(apiClient, flags, args, cfg) {
|
|
34
|
+
const candidate = getIdCandidate(flags, args);
|
|
35
|
+
if (isUuid(candidate)) {
|
|
36
|
+
return candidate;
|
|
37
|
+
}
|
|
38
|
+
const projectId = await withProjectId(apiClient, flags, args, cfg);
|
|
39
|
+
const databases = await apiClient.database.listMysqlDatabases({
|
|
40
|
+
pathParameters: { projectId },
|
|
41
|
+
});
|
|
42
|
+
assertStatus(databases, 200);
|
|
43
|
+
const database = databases.data.find((db) => db.name === candidate);
|
|
44
|
+
if (!database) {
|
|
45
|
+
throw new Error(`No database with name "${candidate}" found`);
|
|
46
|
+
}
|
|
47
|
+
return database.id;
|
|
48
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { ProcessRenderer } from "../../../rendering/process/process.js";
|
|
2
|
+
import { MittwaldAPIV2Client } from "@mittwald/api-client";
|
|
3
|
+
export declare function getConnectionDetails(apiClient: MittwaldAPIV2Client, databaseId: string, p: ProcessRenderer): Promise<{
|
|
4
|
+
hostname: string;
|
|
5
|
+
database: string;
|
|
6
|
+
sshHost: string;
|
|
7
|
+
sshUser: string;
|
|
8
|
+
}>;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { assertStatus } from "@mittwald/api-client-commons";
|
|
2
|
+
import { getProject, getUser } from "../common.js";
|
|
3
|
+
export async function getConnectionDetails(apiClient, databaseId, p) {
|
|
4
|
+
const database = await getDatabase(apiClient, p, databaseId);
|
|
5
|
+
const project = await getProject(apiClient, p, database);
|
|
6
|
+
const user = await getUser(apiClient, p);
|
|
7
|
+
return {
|
|
8
|
+
hostname: database.hostname,
|
|
9
|
+
database: database.name,
|
|
10
|
+
sshHost: `ssh.${project.clusterID}.${project.clusterDomain}`,
|
|
11
|
+
sshUser: `${user.email}@${project.shortId}`,
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
async function getDatabase(apiClient, p, id) {
|
|
15
|
+
return await p.runStep("fetching database", async () => {
|
|
16
|
+
const r = await apiClient.database.getRedisDatabase({
|
|
17
|
+
pathParameters: { id },
|
|
18
|
+
});
|
|
19
|
+
assertStatus(r, 200);
|
|
20
|
+
return r.data;
|
|
21
|
+
});
|
|
22
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Config } from "@oclif/core";
|
|
2
|
+
import { MittwaldAPIV2Client } from "@mittwald/api-client";
|
|
3
|
+
import { ArgOutput, FlagOutput } from "@oclif/core/lib/interfaces/parser.js";
|
|
4
|
+
export declare const redisArgs: {
|
|
5
|
+
"database-id": import("@oclif/core/lib/interfaces/parser.js").Arg<string, Record<string, unknown>>;
|
|
6
|
+
};
|
|
7
|
+
export declare function withRedisId(apiClient: MittwaldAPIV2Client, flags: FlagOutput, args: ArgOutput, cfg: Config): Promise<string>;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Args } from "@oclif/core";
|
|
2
|
+
import { isUuid } from "../../../Helpers.js";
|
|
3
|
+
import { withProjectId } from "../../project/flags.js";
|
|
4
|
+
import { assertStatus } from "@mittwald/api-client-commons";
|
|
5
|
+
export const redisArgs = {
|
|
6
|
+
"database-id": Args.string({
|
|
7
|
+
description: "The ID of the database (when a project context is set, you can also use the name)",
|
|
8
|
+
required: true,
|
|
9
|
+
}),
|
|
10
|
+
};
|
|
11
|
+
function getIdCandidate(flags, args) {
|
|
12
|
+
if (args["database-id"]) {
|
|
13
|
+
return args["database-id"];
|
|
14
|
+
}
|
|
15
|
+
if (flags["database-id"]) {
|
|
16
|
+
return flags["database-id"];
|
|
17
|
+
}
|
|
18
|
+
throw new Error("No ID given");
|
|
19
|
+
}
|
|
20
|
+
export async function withRedisId(apiClient, flags, args, cfg) {
|
|
21
|
+
const candidate = getIdCandidate(flags, args);
|
|
22
|
+
if (isUuid(candidate)) {
|
|
23
|
+
return candidate;
|
|
24
|
+
}
|
|
25
|
+
const projectId = await withProjectId(apiClient, flags, args, cfg);
|
|
26
|
+
const databases = await apiClient.database.listRedisDatabases({
|
|
27
|
+
pathParameters: { projectId },
|
|
28
|
+
});
|
|
29
|
+
assertStatus(databases, 200);
|
|
30
|
+
const database = databases.data.find((db) => db.name === candidate);
|
|
31
|
+
if (!database) {
|
|
32
|
+
throw new Error(`No database with name "${candidate}" found`);
|
|
33
|
+
}
|
|
34
|
+
return database.id;
|
|
35
|
+
}
|
|
@@ -1,2 +1,3 @@
|
|
|
1
1
|
import { makeFlagSet } from "../context_flags.js";
|
|
2
|
-
|
|
2
|
+
import { normalizeCustomerIdToUuid } from "../../Helpers.js";
|
|
3
|
+
export const { flags: orgFlags, args: orgArgs, withId: withOrgId, } = makeFlagSet("org", "o", normalizeCustomerIdToUuid);
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { ProcessState } from "./ProcessState.js";
|
|
3
|
+
import { useInput, useStdin } from "ink";
|
|
4
|
+
export const ProcessConfirmation = ({ step, onConfirm }) => {
|
|
5
|
+
const { isRawModeSupported } = useStdin();
|
|
6
|
+
if (isRawModeSupported) {
|
|
7
|
+
useInput((input) => {
|
|
8
|
+
onConfirm(input === "y");
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
return _jsx(ProcessState, { step: step });
|
|
12
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { Text, useStdin } from "ink";
|
|
3
|
+
const InteractiveConfirmationDisabled = () => (_jsxs(Text, { color: "red", children: [" ", "interactive input required; start this command with --force or --quiet to disable interactive prompts"] }));
|
|
4
|
+
export const ProcessConfirmationStateSummary = ({ step }) => {
|
|
5
|
+
const { isRawModeSupported } = useStdin();
|
|
6
|
+
if (!isRawModeSupported) {
|
|
7
|
+
return _jsx(InteractiveConfirmationDisabled, {});
|
|
8
|
+
}
|
|
9
|
+
if (step.confirmed) {
|
|
10
|
+
return _jsx(Text, { color: "green", children: " confirmed" });
|
|
11
|
+
}
|
|
12
|
+
else if (step.confirmed === false) {
|
|
13
|
+
return _jsx(Text, { color: "yellow", children: " not confirmed" });
|
|
14
|
+
}
|
|
15
|
+
else {
|
|
16
|
+
return (_jsxs(_Fragment, { children: [_jsx(Text, { children: ": press " }), _jsx(Text, { color: "blue", children: "y" }), _jsx(Text, { children: " or " }), _jsx(Text, { color: "blue", children: "n" }), _jsxs(Text, { color: "gray", children: [" ", "(use the --force or --quiet flags to disable this prompt)"] })] }));
|
|
17
|
+
}
|
|
18
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { isValidationError } from "../../../lib/handleError.js";
|
|
3
|
+
import { ProcessValidationErrors } from "./ProcessValidationErrors.js";
|
|
4
|
+
import { Box, Text } from "ink";
|
|
5
|
+
export const ProcessError = ({ err }) => {
|
|
6
|
+
if (isValidationError(err)) {
|
|
7
|
+
return _jsx(ProcessValidationErrors, { err: err.response.data });
|
|
8
|
+
}
|
|
9
|
+
return (_jsxs(Box, { marginY: 1, marginX: 5, flexDirection: "column", children: [_jsx(Text, { color: "red", children: "An error occurred during this operation:" }), _jsx(Text, { color: "red", bold: true, children: err?.toString() })] }));
|
|
10
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from "react";
|
|
3
|
+
import { ProcessStateIcon } from "./ProcessStateIcon.js";
|
|
4
|
+
import { ProcessState } from "./ProcessState.js";
|
|
5
|
+
import { Box, Text, useStdin } from "ink";
|
|
6
|
+
import TextInput from "ink-text-input";
|
|
7
|
+
const InteractiveInputDisabled = () => (_jsx(Text, { color: "red", children: "interactive input required; inspect this command's --help page to learn how to pass the required input non-interactively." }));
|
|
8
|
+
export const ProcessInput = ({ step, onSubmit }) => {
|
|
9
|
+
const [value, setValue] = useState("");
|
|
10
|
+
if (!step.value) {
|
|
11
|
+
const { isRawModeSupported } = useStdin();
|
|
12
|
+
return (_jsx(_Fragment, { children: _jsxs(Box, { marginX: 2, children: [_jsx(ProcessStateIcon, { step: step }), _jsxs(Text, { children: [step.title, ": "] }), isRawModeSupported ? (_jsx(TextInput, { mask: step.mask ? "*" : undefined, value: value, onChange: setValue, onSubmit: onSubmit })) : (_jsx(InteractiveInputDisabled, {}))] }) }));
|
|
13
|
+
}
|
|
14
|
+
return _jsx(ProcessState, { step: step });
|
|
15
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Text } from "ink";
|
|
3
|
+
export const ProcessInputStateSummary = ({ step }) => {
|
|
4
|
+
if (step.value && step.mask) {
|
|
5
|
+
return (_jsxs(_Fragment, { children: [_jsx(Text, { children: ": " }), _jsx(Text, { color: "blue", children: "[secret]" })] }));
|
|
6
|
+
}
|
|
7
|
+
if (step.value) {
|
|
8
|
+
return (_jsxs(_Fragment, { children: [_jsx(Text, { children: ": " }), _jsx(Text, { color: "green", children: step.value })] }));
|
|
9
|
+
}
|
|
10
|
+
else {
|
|
11
|
+
return _jsx(Text, { children: ": " });
|
|
12
|
+
}
|
|
13
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { ProcessStateIcon } from "./ProcessStateIcon.js";
|
|
3
|
+
import { ProcessStateSummary } from "./ProcessStateSummary.js";
|
|
4
|
+
import { ProcessError } from "./ProcessError.js";
|
|
5
|
+
import { Box, Text } from "ink";
|
|
6
|
+
export const ProcessState = ({ step }) => {
|
|
7
|
+
return (_jsxs(_Fragment, { children: [_jsxs(Box, { marginX: 2, children: [_jsx(ProcessStateIcon, { step: step }), _jsx(Text, { children: step.title }), _jsx(ProcessStateSummary, { step: step })] }), step.type === "step" && step.error ? (_jsx(ProcessError, { err: step.error })) : null] }));
|
|
8
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Text } from "ink";
|
|
3
|
+
export const ProcessStateIcon = ({ step }) => {
|
|
4
|
+
if (step.type === "info") {
|
|
5
|
+
return _jsxs(Text, { children: ["\u2139\uFE0F", " "] });
|
|
6
|
+
}
|
|
7
|
+
else if (step.type === "confirm" || step.type === "input") {
|
|
8
|
+
return _jsx(Text, { children: "\u2753" });
|
|
9
|
+
}
|
|
10
|
+
else if (step.phase === "completed") {
|
|
11
|
+
return _jsx(Text, { children: "\u2705" });
|
|
12
|
+
}
|
|
13
|
+
else if (step.phase === "aborted") {
|
|
14
|
+
return _jsx(Text, { children: "\u23E9\uFE0F " });
|
|
15
|
+
}
|
|
16
|
+
else if (step.phase === "failed") {
|
|
17
|
+
return _jsx(Text, { children: "\u274C" });
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
return _jsx(Text, { children: "\uD83D\uDD01 " });
|
|
21
|
+
}
|
|
22
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { ProcessConfirmationStateSummary } from "./ProcessConfirmationStateSummary.js";
|
|
3
|
+
import { ProcessInputStateSummary } from "./ProcessInputStateSummary.js";
|
|
4
|
+
import { Text } from "ink";
|
|
5
|
+
export const ProcessStateSummary = ({ step, }) => {
|
|
6
|
+
if (step.type === "info") {
|
|
7
|
+
return _jsx(_Fragment, {});
|
|
8
|
+
}
|
|
9
|
+
else if (step.type === "confirm") {
|
|
10
|
+
return _jsx(ProcessConfirmationStateSummary, { step: step });
|
|
11
|
+
}
|
|
12
|
+
else if (step.type === "input") {
|
|
13
|
+
return _jsx(ProcessInputStateSummary, { step: step });
|
|
14
|
+
}
|
|
15
|
+
else if (step.phase === "completed") {
|
|
16
|
+
return (_jsxs(_Fragment, { children: [_jsx(Text, { children: ". " }), _jsx(Text, { color: "green", children: "done" })] }));
|
|
17
|
+
}
|
|
18
|
+
else if (step.phase === "aborted") {
|
|
19
|
+
return (_jsxs(_Fragment, { children: [_jsx(Text, { children: ". " }), _jsx(Text, { color: "yellow", children: "cancelled" })] }));
|
|
20
|
+
}
|
|
21
|
+
else if (step.phase === "failed") {
|
|
22
|
+
return (_jsxs(_Fragment, { children: [_jsx(Text, { children: ". " }), _jsx(Text, { color: "red", children: "error" })] }));
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
return _jsx(Text, { children: "..." });
|
|
26
|
+
}
|
|
27
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { MittwaldAPIV2 } from "@mittwald/api-client";
|
|
3
|
+
import CommonsValidationErrors = MittwaldAPIV2.Components.Schemas.CommonsValidationErrors;
|
|
4
|
+
export declare const ProcessValidationErrors: React.FC<{
|
|
5
|
+
err: CommonsValidationErrors;
|
|
6
|
+
color?: string;
|
|
7
|
+
}>;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Box, Text } from "ink";
|
|
3
|
+
const boxProps = {
|
|
4
|
+
marginY: 1,
|
|
5
|
+
marginX: 5,
|
|
6
|
+
paddingX: 1,
|
|
7
|
+
borderColor: "color",
|
|
8
|
+
borderStyle: "round",
|
|
9
|
+
flexDirection: "column",
|
|
10
|
+
width: 80,
|
|
11
|
+
};
|
|
12
|
+
export const ProcessValidationErrors = ({ err, color = "red" }) => {
|
|
13
|
+
const errorItems = err.validationErrors.map((e, idx) => (_jsxs(Box, { flexDirection: "row", children: [_jsx(Box, { minWidth: e.path.length + 2, children: _jsxs(Text, { color: color, bold: true, children: [e.path, ":", " "] }) }), _jsx(Text, { color: color, children: e.message })] }, idx)));
|
|
14
|
+
return (_jsxs(Box, { ...boxProps, children: [_jsx(Text, { color: color, children: "Your input contained invalid data:" }), _jsx(Box, { flexDirection: "column", marginY: 1, children: errorItems }), _jsx(Text, { color: color, children: "Please correct the errors and try again. Consult this command's help page (by invoking it with the --help flag) for more information." })] }));
|
|
15
|
+
};
|
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
import { ReactElement, ReactNode } from "react";
|
|
2
2
|
export type ProcessStepInfo = {
|
|
3
3
|
type: "info";
|
|
4
|
-
title:
|
|
4
|
+
title: ReactNode;
|
|
5
5
|
};
|
|
6
6
|
export type ProcessStepRunnable = {
|
|
7
7
|
type: "step";
|
|
8
|
-
title:
|
|
8
|
+
title: ReactNode;
|
|
9
9
|
phase: "running" | "completed" | "failed" | "aborted";
|
|
10
10
|
error?: unknown;
|
|
11
11
|
};
|
|
12
12
|
export type ProcessStepConfirm = {
|
|
13
13
|
type: "confirm";
|
|
14
|
-
title:
|
|
14
|
+
title: ReactNode;
|
|
15
15
|
confirmed: boolean | undefined;
|
|
16
16
|
};
|
|
17
17
|
export type ProcessStepInput = {
|
|
18
18
|
type: "input";
|
|
19
|
-
title:
|
|
19
|
+
title: ReactNode;
|
|
20
20
|
mask?: boolean;
|
|
21
21
|
value?: string;
|
|
22
22
|
};
|
|
@@ -36,7 +36,7 @@ export interface ProcessRenderer {
|
|
|
36
36
|
runStep<TRes>(title: ReactNode, fn: () => Promise<TRes>): Promise<TRes>;
|
|
37
37
|
addInfo(title: ReactElement): void;
|
|
38
38
|
addConfirmation(question: ReactElement): Promise<boolean>;
|
|
39
|
-
addInput(question:
|
|
39
|
+
addInput(question: ReactNode, mask?: boolean): Promise<string>;
|
|
40
40
|
complete(summary: ReactElement): void;
|
|
41
41
|
error(err: unknown): void;
|
|
42
42
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { ReactElement, ReactNode } from "react";
|
|
2
|
-
import { ProcessRenderer,
|
|
2
|
+
import { ProcessRenderer, RunnableHandler } from "./process.js";
|
|
3
3
|
export declare class FancyProcessRenderer implements ProcessRenderer {
|
|
4
4
|
private readonly title;
|
|
5
5
|
private started;
|
|
@@ -15,14 +15,3 @@ export declare class FancyProcessRenderer implements ProcessRenderer {
|
|
|
15
15
|
error(err: unknown): void;
|
|
16
16
|
private renderStart;
|
|
17
17
|
}
|
|
18
|
-
export declare const ProcessState: React.FC<{
|
|
19
|
-
step: ProcessStep;
|
|
20
|
-
}>;
|
|
21
|
-
export declare const ProcessConfirmation: React.FC<{
|
|
22
|
-
step: ProcessStep;
|
|
23
|
-
onConfirm: (confirmed: boolean) => void;
|
|
24
|
-
}>;
|
|
25
|
-
export declare const ProcessInput: React.FC<{
|
|
26
|
-
step: ProcessStepInput;
|
|
27
|
-
onSubmit: (value: string) => void;
|
|
28
|
-
}>;
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { RunnableHandler } from "./process.js";
|
|
3
|
+
import { Header } from "../react/components/Header.js";
|
|
4
|
+
import { Box, render, Text } from "ink";
|
|
5
|
+
import { ProcessState } from "./components/ProcessState.js";
|
|
6
|
+
import { ProcessConfirmation } from "./components/ProcessConfirmation.js";
|
|
7
|
+
import { ProcessInput } from "./components/ProcessInput.js";
|
|
8
|
+
export class FancyProcessRenderer {
|
|
9
|
+
title;
|
|
10
|
+
started = false;
|
|
11
|
+
currentHandler = null;
|
|
12
|
+
constructor(title) {
|
|
13
|
+
this.title = title;
|
|
14
|
+
}
|
|
15
|
+
start() {
|
|
16
|
+
if (this.started) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
this.started = true;
|
|
20
|
+
render(this.renderStart(), {}).unmount();
|
|
21
|
+
}
|
|
22
|
+
addStep(title) {
|
|
23
|
+
this.start();
|
|
24
|
+
if (this.currentHandler !== null) {
|
|
25
|
+
this.currentHandler.abort();
|
|
26
|
+
}
|
|
27
|
+
const state = { type: "step", title, phase: "running" };
|
|
28
|
+
const renderHandle = render(_jsx(ProcessState, { step: state }));
|
|
29
|
+
this.currentHandler = new RunnableHandler(state, () => {
|
|
30
|
+
renderHandle.rerender(_jsx(ProcessState, { step: state }));
|
|
31
|
+
if (this.currentHandler?.done) {
|
|
32
|
+
this.currentHandler = null;
|
|
33
|
+
renderHandle.unmount();
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
return this.currentHandler;
|
|
37
|
+
}
|
|
38
|
+
async runStep(title, fn) {
|
|
39
|
+
const step = this.addStep(title);
|
|
40
|
+
try {
|
|
41
|
+
const result = await fn();
|
|
42
|
+
step.complete();
|
|
43
|
+
return result;
|
|
44
|
+
}
|
|
45
|
+
catch (err) {
|
|
46
|
+
step.error(err);
|
|
47
|
+
throw err;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
addInfo(title) {
|
|
51
|
+
this.start();
|
|
52
|
+
if (this.currentHandler !== null) {
|
|
53
|
+
this.currentHandler.complete();
|
|
54
|
+
}
|
|
55
|
+
const state = { type: "info", title };
|
|
56
|
+
render(_jsx(ProcessState, { step: state })).unmount();
|
|
57
|
+
}
|
|
58
|
+
addInput(question, mask) {
|
|
59
|
+
this.start();
|
|
60
|
+
if (this.currentHandler !== null) {
|
|
61
|
+
this.currentHandler.complete();
|
|
62
|
+
}
|
|
63
|
+
const state = {
|
|
64
|
+
type: "input",
|
|
65
|
+
title: question,
|
|
66
|
+
mask,
|
|
67
|
+
};
|
|
68
|
+
return new Promise((res) => {
|
|
69
|
+
const onInput = (value) => {
|
|
70
|
+
res(value);
|
|
71
|
+
state.value = value;
|
|
72
|
+
if (renderHandle) {
|
|
73
|
+
renderHandle.rerender(_jsx(ProcessInput, { step: state, onSubmit: onInput }));
|
|
74
|
+
renderHandle.unmount();
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
const renderHandle = render(_jsx(ProcessInput, { step: state, onSubmit: onInput }));
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
addConfirmation(question) {
|
|
81
|
+
this.start();
|
|
82
|
+
if (this.currentHandler !== null) {
|
|
83
|
+
this.currentHandler.complete();
|
|
84
|
+
}
|
|
85
|
+
const state = {
|
|
86
|
+
type: "confirm",
|
|
87
|
+
title: question,
|
|
88
|
+
confirmed: undefined,
|
|
89
|
+
};
|
|
90
|
+
return new Promise((res) => {
|
|
91
|
+
const onConfirm = (confirmed) => {
|
|
92
|
+
res(confirmed);
|
|
93
|
+
state.confirmed = confirmed;
|
|
94
|
+
if (renderHandle) {
|
|
95
|
+
renderHandle.rerender(_jsx(ProcessConfirmation, { step: state, onConfirm: onConfirm }));
|
|
96
|
+
renderHandle.unmount();
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
const renderHandle = render(_jsx(ProcessConfirmation, { step: state, onConfirm: onConfirm }));
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
complete(summary) {
|
|
103
|
+
if (this.currentHandler) {
|
|
104
|
+
this.currentHandler.complete();
|
|
105
|
+
}
|
|
106
|
+
render(_jsx(Box, { marginY: 1, marginX: 2, children: summary })).unmount();
|
|
107
|
+
}
|
|
108
|
+
error(err) {
|
|
109
|
+
if (this.currentHandler) {
|
|
110
|
+
this.currentHandler.error(err);
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
render(_jsx(Box, { marginY: 1, marginX: 2, borderStyle: "round", borderColor: "red", children: _jsxs(Text, { color: "red", children: ["Error: ", err?.toString()] }) })).unmount();
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
renderStart() {
|
|
117
|
+
return (_jsx(Box, { marginY: 1, marginX: 2, children: _jsx(Header, { title: this.title }) }));
|
|
118
|
+
}
|
|
119
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { ProcessRenderer } from "./process.js";
|
|
2
|
+
import { InferredFlags } from "@oclif/core/lib/interfaces/index.js";
|
|
3
|
+
export declare const processFlags: {
|
|
4
|
+
quiet: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
5
|
+
};
|
|
6
|
+
export type ProcessFlags = InferredFlags<typeof processFlags>;
|
|
7
|
+
/**
|
|
8
|
+
* Create a ProcessRenderer based on the given flags. Currently, only two
|
|
9
|
+
* renderers are available:
|
|
10
|
+
*
|
|
11
|
+
* - `FancyProcessRenderer` for interactive output
|
|
12
|
+
* - `SilentProcessRenderer` for non-interactive output when the `quiet` flag is
|
|
13
|
+
* set
|
|
14
|
+
*
|
|
15
|
+
* More renderers may be added in the future.
|
|
16
|
+
*
|
|
17
|
+
* @param flags
|
|
18
|
+
* @param title
|
|
19
|
+
*/
|
|
20
|
+
export declare const makeProcessRenderer: (flags: ProcessFlags, title: string) => ProcessRenderer;
|