@@ -0,0 +1,54 @@
|
||||
import inquirer from 'inquirer';
|
||||
import chalk from 'chalk';
|
||||
import { ApiService } from '../services/api.service';
|
||||
import { CURRENT_EXECUTION_DIRECTORY } from '../constants/current-execution-directory';
|
||||
import { loadManifest } from '../utils/app-manifest-loader';
|
||||
|
||||
export class AppDeleteCommand {
|
||||
private apiService = new ApiService();
|
||||
|
||||
async execute(): Promise<void> {
|
||||
try {
|
||||
const appPath = CURRENT_EXECUTION_DIRECTORY;
|
||||
|
||||
console.log(chalk.blue('🚀 Deleting Twenty Application'));
|
||||
console.log(chalk.gray(`📁 App Path: ${appPath}`));
|
||||
console.log('');
|
||||
|
||||
if (!(await this.confirmationPrompt())) {
|
||||
console.error(chalk.red('⛔️ Aborting deletion'));
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const { packageJson } = await loadManifest(appPath);
|
||||
|
||||
const result = await this.apiService.deleteApplication(packageJson);
|
||||
|
||||
if (!result.success) {
|
||||
console.error(chalk.red('❌ Deletion failed:'), result.error);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log(chalk.green('✅ Application deleted successfully'));
|
||||
} catch (error) {
|
||||
console.error(
|
||||
chalk.red('Deletion failed:'),
|
||||
error instanceof Error ? error.message : error,
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
private async confirmationPrompt(): Promise<boolean> {
|
||||
const { confirmation } = await inquirer.prompt([
|
||||
{
|
||||
type: 'confirm',
|
||||
name: 'confirmation',
|
||||
message: 'Are you sure you want to delete this application?',
|
||||
default: false,
|
||||
},
|
||||
]);
|
||||
|
||||
return confirmation;
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
import chalk from 'chalk';
|
||||
import * as chokidar from 'chokidar';
|
||||
import { ApiService } from '../services/api.service';
|
||||
import { syncApp } from '../utils/app-sync';
|
||||
import { CURRENT_EXECUTION_DIRECTORY } from '../constants/current-execution-directory';
|
||||
import { loadManifest } from '../utils/app-manifest-loader';
|
||||
|
||||
export class AppDevCommand {
|
||||
private apiService = new ApiService();
|
||||
@@ -15,7 +15,13 @@ export class AppDevCommand {
|
||||
|
||||
this.logStartupInfo(appPath, debounceMs);
|
||||
|
||||
await syncApp(appPath, this.apiService);
|
||||
const { manifest, packageJson, yarnLock } = await loadManifest(appPath);
|
||||
|
||||
await this.apiService.syncApplication({
|
||||
manifest,
|
||||
packageJson,
|
||||
yarnLock,
|
||||
});
|
||||
|
||||
const watcher = this.setupFileWatcher(appPath, debounceMs);
|
||||
|
||||
@@ -54,7 +60,15 @@ export class AppDevCommand {
|
||||
|
||||
timeout = setTimeout(async () => {
|
||||
console.log(chalk.blue('🔄 Changes detected, syncing...'));
|
||||
await syncApp(appPath, this.apiService);
|
||||
|
||||
const { manifest, packageJson, yarnLock } = await loadManifest(appPath);
|
||||
|
||||
await this.apiService.syncApplication({
|
||||
manifest,
|
||||
packageJson,
|
||||
yarnLock,
|
||||
});
|
||||
|
||||
console.log(
|
||||
chalk.gray('👀 Watching for changes... (Press Ctrl+C to stop)'),
|
||||
);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import chalk from 'chalk';
|
||||
import { ApiService } from '../services/api.service';
|
||||
import { syncApp } from '../utils/app-sync';
|
||||
import { CURRENT_EXECUTION_DIRECTORY } from '../constants/current-execution-directory';
|
||||
import { loadManifest } from '../utils/app-manifest-loader';
|
||||
|
||||
export class AppSyncCommand {
|
||||
private apiService = new ApiService();
|
||||
@@ -14,7 +14,13 @@ export class AppSyncCommand {
|
||||
console.log(chalk.gray(`📁 App Path: ${appPath}`));
|
||||
console.log('');
|
||||
|
||||
const result = await syncApp(appPath, this.apiService);
|
||||
const { manifest, packageJson, yarnLock } = await loadManifest(appPath);
|
||||
|
||||
const result = await this.apiService.syncApplication({
|
||||
manifest,
|
||||
packageJson,
|
||||
yarnLock,
|
||||
});
|
||||
|
||||
if (!result.success) {
|
||||
console.error(chalk.red('❌ Sync failed:'), result.error);
|
||||
|
||||
@@ -2,6 +2,7 @@ import { Command } from 'commander';
|
||||
import { AppSyncCommand } from './app-sync.command';
|
||||
import { AppDevCommand } from './app-dev.command';
|
||||
import { AppInitCommand } from './app-init.command';
|
||||
import { AppDeleteCommand } from './app-delete.command';
|
||||
import {
|
||||
AppAddCommand,
|
||||
isSyncableEntity,
|
||||
@@ -12,6 +13,7 @@ import chalk from 'chalk';
|
||||
export class AppCommand {
|
||||
private devCommand = new AppDevCommand();
|
||||
private syncCommand = new AppSyncCommand();
|
||||
private deleteCommand = new AppDeleteCommand();
|
||||
private initCommand = new AppInitCommand();
|
||||
private addCommand = new AppAddCommand();
|
||||
|
||||
@@ -34,6 +36,13 @@ export class AppCommand {
|
||||
await this.syncCommand.execute();
|
||||
});
|
||||
|
||||
appCommand
|
||||
.command('delete')
|
||||
.description('Delete application from Twenty')
|
||||
.action(async () => {
|
||||
await this.deleteCommand.execute();
|
||||
});
|
||||
|
||||
appCommand
|
||||
.command('init [directory]')
|
||||
.description('Initialize a new Twenty application')
|
||||
|
||||
@@ -72,7 +72,6 @@ export class ApiService {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Accept: '*/*',
|
||||
'x-schema-version': '6',
|
||||
},
|
||||
},
|
||||
);
|
||||
@@ -115,7 +114,6 @@ export class ApiService {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Accept: '*/*',
|
||||
'x-schema-version': '6',
|
||||
},
|
||||
},
|
||||
);
|
||||
@@ -143,4 +141,52 @@ export class ApiService {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async deleteApplication(packageJson: PackageJson): Promise<ApiResponse> {
|
||||
try {
|
||||
const mutation = `
|
||||
mutation DeleteApplication($packageJson: JSON!) {
|
||||
deleteApplication(packageJson: $packageJson)
|
||||
}
|
||||
`;
|
||||
|
||||
const variables = { packageJson };
|
||||
|
||||
const response: AxiosResponse = await this.client.post(
|
||||
'/metadata',
|
||||
{
|
||||
query: mutation,
|
||||
variables,
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Accept: '*/*',
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if (response.data.errors) {
|
||||
return {
|
||||
success: false,
|
||||
error:
|
||||
response.data.errors[0]?.message || 'Failed to delete application',
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
data: response.data.data.deleteApplication,
|
||||
message: `Successfully deleted application: ${packageJson.name}`,
|
||||
};
|
||||
} catch (error) {
|
||||
if (axios.isAxiosError(error) && error.response) {
|
||||
return {
|
||||
success: false,
|
||||
error: error.response.data?.errors?.[0]?.message || error.message,
|
||||
};
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
import chalk from 'chalk';
|
||||
import { ApiService } from '../services/api.service';
|
||||
import { loadManifest } from './app-manifest-loader';
|
||||
|
||||
export const syncApp = async (
|
||||
appPath: string,
|
||||
apiService: ApiService,
|
||||
): Promise<any> => {
|
||||
const { manifest, packageJson, yarnLock } = await loadManifest(appPath);
|
||||
|
||||
try {
|
||||
const result = await apiService.syncApplication({
|
||||
manifest,
|
||||
packageJson,
|
||||
yarnLock,
|
||||
});
|
||||
|
||||
if (result.success) {
|
||||
console.log(chalk.green('✅ Application synced successfully'));
|
||||
} else {
|
||||
console.error(chalk.red('❌ Sync failed:'), result.error);
|
||||
}
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.error(
|
||||
chalk.red('Sync error:'),
|
||||
error instanceof Error ? error.message : error,
|
||||
);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user