diff --git a/src/cli/dashboard/users/create.ts b/src/cli/dashboard/users/create.ts new file mode 100644 index 00000000..ffe49931 --- /dev/null +++ b/src/cli/dashboard/users/create.ts @@ -0,0 +1,40 @@ +import { Flags } from '@oclif/core'; +import { DashboardCommand } from '../_shared/base.js'; + +export default class UsersCreate extends DashboardCommand { + static override description = 'Create a new user.'; + + static override flags = { + ...DashboardCommand.baseFlags, + email: Flags.string({ description: 'User email address', required: true }), + password: Flags.string({ description: 'User password', required: true }), + name: Flags.string({ description: 'User display name', required: true }), + role: Flags.string({ + description: 'User role (member, admin, superadmin)', + options: ['member', 'admin', 'superadmin'], + default: 'member', + }), + }; + + async run(): Promise { + const { flags } = await this.parse(UsersCreate); + + try { + const result = await this.client.users.create.mutate({ + email: flags.email, + password: flags.password, + name: flags.name, + role: flags.role as 'member' | 'admin' | 'superadmin' | undefined, + }); + + if (flags.json) { + this.outputJson(result); + return; + } + + this.log(`Created user: ${flags.name} <${flags.email}> (role: ${flags.role})`); + } catch (err) { + this.handleError(err); + } + } +} diff --git a/src/cli/dashboard/users/delete.ts b/src/cli/dashboard/users/delete.ts new file mode 100644 index 00000000..79556412 --- /dev/null +++ b/src/cli/dashboard/users/delete.ts @@ -0,0 +1,36 @@ +import { Args, Flags } from '@oclif/core'; +import { DashboardCommand } from '../_shared/base.js'; + +export default class UsersDelete extends DashboardCommand { + static override description = 'Delete a user.'; + + static override args = { + id: Args.string({ description: 'User ID (UUID)', required: true }), + }; + + static override flags = { + ...DashboardCommand.baseFlags, + yes: Flags.boolean({ description: 'Skip confirmation', char: 'y', default: false }), + }; + + async run(): Promise { + const { args, flags } = await this.parse(UsersDelete); + + if (!flags.yes) { + this.error('Pass --yes to confirm deletion.'); + } + + try { + await this.client.users.delete.mutate({ id: args.id }); + + if (flags.json) { + this.outputJson({ ok: true }); + return; + } + + this.log(`Deleted user ${args.id}`); + } catch (err) { + this.handleError(err); + } + } +} diff --git a/src/cli/dashboard/users/list.ts b/src/cli/dashboard/users/list.ts new file mode 100644 index 00000000..f71c6752 --- /dev/null +++ b/src/cli/dashboard/users/list.ts @@ -0,0 +1,33 @@ +import { DashboardCommand } from '../_shared/base.js'; +import { formatDate } from '../_shared/format.js'; + +export default class UsersList extends DashboardCommand { + static override description = 'List organization users.'; + + static override flags = { + ...DashboardCommand.baseFlags, + }; + + async run(): Promise { + const { flags } = await this.parse(UsersList); + + try { + const users = await this.client.users.list.query(); + + if (flags.json) { + this.outputJson(users); + return; + } + + this.outputTable(users as unknown as Record[], [ + { key: 'id', header: 'ID' }, + { key: 'email', header: 'Email' }, + { key: 'name', header: 'Name' }, + { key: 'role', header: 'Role' }, + { key: 'createdAt', header: 'Created', format: formatDate }, + ]); + } catch (err) { + this.handleError(err); + } + } +} diff --git a/src/cli/dashboard/users/update.ts b/src/cli/dashboard/users/update.ts new file mode 100644 index 00000000..1f0f7392 --- /dev/null +++ b/src/cli/dashboard/users/update.ts @@ -0,0 +1,44 @@ +import { Args, Flags } from '@oclif/core'; +import { DashboardCommand } from '../_shared/base.js'; + +export default class UsersUpdate extends DashboardCommand { + static override description = 'Update a user.'; + + static override args = { + id: Args.string({ description: 'User ID (UUID)', required: true }), + }; + + static override flags = { + ...DashboardCommand.baseFlags, + name: Flags.string({ description: 'User display name' }), + email: Flags.string({ description: 'User email address' }), + role: Flags.string({ + description: 'User role (member, admin, superadmin)', + options: ['member', 'admin', 'superadmin'], + }), + password: Flags.string({ description: 'New password' }), + }; + + async run(): Promise { + const { args, flags } = await this.parse(UsersUpdate); + + try { + await this.client.users.update.mutate({ + id: args.id, + name: flags.name, + email: flags.email, + role: flags.role as 'member' | 'admin' | 'superadmin' | undefined, + password: flags.password, + }); + + if (flags.json) { + this.outputJson({ ok: true }); + return; + } + + this.log(`Updated user ${args.id}`); + } catch (err) { + this.handleError(err); + } + } +}