diff --git a/src/commands/app/create.ts b/src/commands/app/create.ts new file mode 100644 index 0000000..66fe787 --- /dev/null +++ b/src/commands/app/create.ts @@ -0,0 +1,121 @@ +import { Command, Flags } from "@oclif/core"; +import axios from "axios"; +import chalk from "chalk"; +import inquirer from "inquirer"; + +import { readAuthConfig } from "../../utils/utils.js"; + +export default class AppCreate extends Command { + static description = "Create a new application within a project."; + + static examples = ["$ <%= config.bin %> app create"]; + + static flags = { + projectId: Flags.string({ + char: "p", + description: "ID of the project", + required: false, + }), + }; + + public async run(): Promise { + const auth = await readAuthConfig(this); + + const { flags } = await this.parse(AppCreate); + + let { projectId } = flags; + + if (!projectId) { + // Obtener la lista de proyectos y permitir la selección + console.log(chalk.blue.bold("\n Listing all Projects \n")); + + try { + const response = await axios.get(`${auth.url}/api/trpc/project.all`, { + headers: { + Authorization: `Bearer ${auth.token}`, + "Content-Type": "application/json", + }, + }); + + if (!response.data.result.data.json) { + this.error(chalk.red("Error fetching projects")); + } + + const projects = response.data.result.data.json; + + if (projects.length === 0) { + this.log(chalk.yellow("No projects found.")); + return; + } + + // Permitir al usuario seleccionar un proyecto + const answers = await inquirer.prompt([ + { + choices: projects.map((project: any) => ({ + name: project.name, + value: project.projectId, + })), + message: "Select a project to create the application in:", + name: "selectedProject", + type: "list", + }, + ]); + + projectId = answers.selectedProject; + } catch (error) { + // @ts-expect-error TODO: Fix this + this.error(chalk.red(`Failed to fetch project list: ${error.message}`)); + } + } + + // Solicitar detalles de la nueva aplicación + const appDetails = await inquirer.prompt([ + { + message: "Enter the application name:", + name: "appName", + type: "input", + validate: (input) => (input ? true : "Application name is required"), + }, + { + message: "Enter the application description (optional):", + name: "appDescription", + type: "input", + }, + ]); + + const { appDescription, appName } = appDetails; + + // Crear la aplicación en el proyecto seleccionado + try { + const response = await axios.post( + `${auth.url}/api/trpc/application.create`, + { + json: { + description: appDescription, + name: appName, + projectId, + }, + }, + { + headers: { + Authorization: `Bearer ${auth.token}`, + "Content-Type": "application/json", + }, + }, + ); + + if (!response.data.result.data.json) { + this.error(chalk.red("Error creating application")); + } + + this.log( + chalk.green( + `Application '${appName}' created successfully in project ID '${projectId}'.`, + ), + ); + } catch (error) { + // @ts-expect-error TODO: Fix this + this.error(chalk.red(`Failed to create application: ${error.message}`)); + } + } +} diff --git a/src/commands/app/delete.ts b/src/commands/app/delete.ts new file mode 100644 index 0000000..6a12f98 --- /dev/null +++ b/src/commands/app/delete.ts @@ -0,0 +1,155 @@ +import { Command, Flags } from "@oclif/core"; +import axios from "axios"; +import chalk from "chalk"; +import inquirer from "inquirer"; + +import { readAuthConfig } from "../../utils/utils.js"; + +export default class AppDelete extends Command { + static description = "Delete an application from a project."; + + static examples = [ + "$ <%= config.bin %> app delete", + "$ <%= config.bin %> app delete -p ", + ]; + + static flags = { + projectId: Flags.string({ + char: "p", + description: "ID of the project", + required: false, + }), + }; + + public async run(): Promise { + const auth = await readAuthConfig(this); + + const { flags } = await this.parse(AppDelete); + + let { projectId } = flags; + + if (!projectId) { + // Obtener la lista de proyectos y permitir la selección + console.log(chalk.blue.bold("\n Listing all Projects \n")); + + try { + const response = await axios.get(`${auth.url}/api/trpc/project.all`, { + headers: { + Authorization: `Bearer ${auth.token}`, + "Content-Type": "application/json", + }, + }); + + if (!response.data.result.data.json) { + this.error(chalk.red("Error fetching projects")); + } + + const projects = response.data.result.data.json; + + if (projects.length === 0) { + this.log(chalk.yellow("No projects found.")); + return; + } + + // Permitir al usuario seleccionar un proyecto + const answers = await inquirer.prompt([ + { + choices: projects.map((project: any) => ({ + name: project.name, + value: project.projectId, + })), + message: "Select a project to delete the application from:", + name: "selectedProject", + type: "list", + }, + ]); + + projectId = answers.selectedProject; + } catch (error) { + // @ts-expect-error - TS2339: Property 'data' does not exist on type 'AxiosError'. + this.error(chalk.red(`Failed to fetch project list: ${error.message}`)); + } + } + + // Obtener la lista de aplicaciones del proyecto seleccionado + try { + const response = await axios.get(`${auth.url}/api/trpc/project.one`, { + headers: { + Authorization: `Bearer ${auth.token}`, + "Content-Type": "application/json", + }, + params: { + input: JSON.stringify({ + json: { projectId }, + }), + }, + }); + + if (!response.data.result.data.json) { + this.error(chalk.red("Error fetching applications")); + } + + const apps = response.data.result.data.json; + + if (apps.applications.length === 0) { + this.log(chalk.yellow("No applications found in this project.")); + return; + } + + // Permitir al usuario seleccionar una aplicación + const appAnswers = await inquirer.prompt([ + { + choices: apps.applications.map((app: any) => ({ + name: app.name, + value: app.applicationId, + })), + message: "Select the application to delete:", + name: "selectedApp", + type: "list", + }, + ]); + + const applicationId = appAnswers.selectedApp; + + // Confirmar eliminación + const confirmAnswers = await inquirer.prompt([ + { + default: false, + message: "Are you sure you want to delete this application?", + name: "confirmDelete", + type: "confirm", + }, + ]); + + if (!confirmAnswers.confirmDelete) { + this.log(chalk.yellow("Application deletion cancelled.")); + return; + } + + // Eliminar la aplicación seleccionada + const deleteResponse = await axios.post( + `${auth.url}/api/trpc/application.delete`, + { + json: { + applicationId, + }, + }, + { + headers: { + Authorization: `Bearer ${auth.token}`, + "Content-Type": "application/json", + }, + }, + ); + + if (!deleteResponse.data.result.data.json) { + this.error(chalk.red("Error deleting application")); + } + + this.log(chalk.green("Application deleted successfully.")); + } catch (error) { + // @ts-expect-error - TS2339: Property 'data' does not exist on type 'AxiosError'. + this.error(chalk.red(`Failed to delete application: ${error.message}`)); + } + } +} diff --git a/test/commands/app/create.test.ts b/test/commands/app/create.test.ts new file mode 100644 index 0000000..aaa7dbb --- /dev/null +++ b/test/commands/app/create.test.ts @@ -0,0 +1,14 @@ +import {runCommand} from '@oclif/test' +import {expect} from 'chai' + +describe('app:create', () => { + it('runs app:create cmd', async () => { + const {stdout} = await runCommand('app:create') + expect(stdout).to.contain('hello world') + }) + + it('runs app:create --name oclif', async () => { + const {stdout} = await runCommand('app:create --name oclif') + expect(stdout).to.contain('hello oclif') + }) +}) diff --git a/test/commands/app/delete.test.ts b/test/commands/app/delete.test.ts new file mode 100644 index 0000000..50dc59b --- /dev/null +++ b/test/commands/app/delete.test.ts @@ -0,0 +1,14 @@ +import {runCommand} from '@oclif/test' +import {expect} from 'chai' + +describe('app:delete', () => { + it('runs app:delete cmd', async () => { + const {stdout} = await runCommand('app:delete') + expect(stdout).to.contain('hello world') + }) + + it('runs app:delete --name oclif', async () => { + const {stdout} = await runCommand('app:delete --name oclif') + expect(stdout).to.contain('hello oclif') + }) +})