Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions src/commands/api-keys/delete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Command } from '@commander-js/extra-typings';
import { runDelete } from '../../lib/actions';
import type { GlobalOpts } from '../../lib/client';
import { buildHelpText } from '../../lib/help-text';
import { pickId } from '../../lib/prompts';
import { pickItem } from '../../lib/prompts';
import { apiKeyPickerConfig } from './utils';

export const deleteApiKeyCommand = new Command('delete')
Expand Down Expand Up @@ -30,16 +30,16 @@ can delete itself — the API does not prevent self-deletion.`,
)
.action(async (idArg, opts, cmd) => {
const globalOpts = cmd.optsWithGlobals() as GlobalOpts;
const id = await pickId(idArg, apiKeyPickerConfig, globalOpts);
const picked = await pickItem(idArg, apiKeyPickerConfig, globalOpts);
await runDelete(
id,
picked.id,
!!opts.yes,
{
confirmMessage: `Delete API key ${id}?\nAny services using this key will stop working.`,
confirmMessage: `Delete API key "${picked.label}"?\nID: ${picked.id}\nAny services using this key will stop working.`,
loading: 'Deleting API key...',
object: 'api-key',
successMsg: 'API key deleted',
sdkCall: (resend) => resend.apiKeys.remove(id),
sdkCall: (resend) => resend.apiKeys.remove(picked.id),
},
globalOpts,
);
Expand Down
10 changes: 5 additions & 5 deletions src/commands/broadcasts/delete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Command } from '@commander-js/extra-typings';
import { runDelete } from '../../lib/actions';
import type { GlobalOpts } from '../../lib/client';
import { buildHelpText } from '../../lib/help-text';
import { pickId } from '../../lib/prompts';
import { pickItem } from '../../lib/prompts';
import { broadcastPickerConfig } from './utils';

export const deleteBroadcastCommand = new Command('delete')
Expand All @@ -29,16 +29,16 @@ Non-interactive: --yes is required to confirm deletion when stdin/stdout is not
)
.action(async (idArg, opts, cmd) => {
const globalOpts = cmd.optsWithGlobals() as GlobalOpts;
const id = await pickId(idArg, broadcastPickerConfig, globalOpts);
const picked = await pickItem(idArg, broadcastPickerConfig, globalOpts);
await runDelete(
id,
picked.id,
!!opts.yes,
{
confirmMessage: `Delete broadcast ${id}?\nIf scheduled, delivery will be cancelled.`,
confirmMessage: `Delete broadcast "${picked.label}"?\nID: ${picked.id}\nIf scheduled, delivery will be cancelled.`,
loading: 'Deleting broadcast...',
object: 'broadcast',
successMsg: 'Broadcast deleted',
sdkCall: (resend) => resend.broadcasts.remove(id),
sdkCall: (resend) => resend.broadcasts.remove(picked.id),
},
globalOpts,
);
Expand Down
14 changes: 9 additions & 5 deletions src/commands/contact-properties/delete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Command } from '@commander-js/extra-typings';
import { runDelete } from '../../lib/actions';
import type { GlobalOpts } from '../../lib/client';
import { buildHelpText } from '../../lib/help-text';
import { pickId } from '../../lib/prompts';
import { pickItem } from '../../lib/prompts';
import { contactPropertyPickerConfig } from './utils';

export const deleteContactPropertyCommand = new Command('delete')
Expand Down Expand Up @@ -31,16 +31,20 @@ Non-interactive: --yes is required to confirm deletion when stdin/stdout is not
)
.action(async (idArg, opts, cmd) => {
const globalOpts = cmd.optsWithGlobals() as GlobalOpts;
const id = await pickId(idArg, contactPropertyPickerConfig, globalOpts);
const picked = await pickItem(
idArg,
contactPropertyPickerConfig,
globalOpts,
);
await runDelete(
id,
picked.id,
!!opts.yes,
{
confirmMessage: `Delete contact property "${id}"?\nThis will remove this property from ALL contacts permanently.`,
confirmMessage: `Delete contact property "${picked.label}"?\nID: ${picked.id}\nThis will remove this property from ALL contacts permanently.`,
loading: 'Deleting contact property...',
object: 'contact_property',
successMsg: 'Contact property deleted',
sdkCall: (resend) => resend.contactProperties.remove(id),
sdkCall: (resend) => resend.contactProperties.remove(picked.id),
},
globalOpts,
);
Expand Down
10 changes: 5 additions & 5 deletions src/commands/contacts/delete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Command } from '@commander-js/extra-typings';
import { runDelete } from '../../lib/actions';
import type { GlobalOpts } from '../../lib/client';
import { buildHelpText } from '../../lib/help-text';
import { pickId } from '../../lib/prompts';
import { pickItem } from '../../lib/prompts';
import { contactPickerConfig } from './utils';

export const deleteContactCommand = new Command('delete')
Expand Down Expand Up @@ -32,16 +32,16 @@ Non-interactive: --yes is required to confirm deletion when stdin/stdout is not
)
.action(async (idArg, opts, cmd) => {
const globalOpts = cmd.optsWithGlobals() as GlobalOpts;
const id = await pickId(idArg, contactPickerConfig, globalOpts);
const picked = await pickItem(idArg, contactPickerConfig, globalOpts);
await runDelete(
id,
picked.id,
!!opts.yes,
{
confirmMessage: `Delete contact ${id}?\nThis cannot be undone.`,
confirmMessage: `Delete contact "${picked.label}"?\nID: ${picked.id}\nThis cannot be undone.`,
loading: 'Deleting contact...',
object: 'contact',
successMsg: 'Contact deleted',
sdkCall: (resend) => resend.contacts.remove(id),
sdkCall: (resend) => resend.contacts.remove(picked.id),
},
globalOpts,
);
Expand Down
10 changes: 5 additions & 5 deletions src/commands/domains/delete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Command } from '@commander-js/extra-typings';
import { runDelete } from '../../lib/actions';
import type { GlobalOpts } from '../../lib/client';
import { buildHelpText } from '../../lib/help-text';
import { pickId } from '../../lib/prompts';
import { pickItem } from '../../lib/prompts';
import { domainPickerConfig } from './utils';

export const deleteDomainCommand = new Command('delete')
Expand All @@ -25,16 +25,16 @@ export const deleteDomainCommand = new Command('delete')
)
.action(async (idArg, opts, cmd) => {
const globalOpts = cmd.optsWithGlobals() as GlobalOpts;
const id = await pickId(idArg, domainPickerConfig, globalOpts);
const picked = await pickItem(idArg, domainPickerConfig, globalOpts);
await runDelete(
id,
picked.id,
!!opts.yes,
{
confirmMessage: `Delete domain ${id}?\nThis cannot be undone.`,
confirmMessage: `Delete domain "${picked.label}"?\nID: ${picked.id}\nThis cannot be undone.`,
loading: 'Deleting domain...',
object: 'domain',
successMsg: 'Domain deleted',
sdkCall: (resend) => resend.domains.remove(id),
sdkCall: (resend) => resend.domains.remove(picked.id),
},
globalOpts,
);
Expand Down
10 changes: 5 additions & 5 deletions src/commands/segments/delete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Command } from '@commander-js/extra-typings';
import { runDelete } from '../../lib/actions';
import type { GlobalOpts } from '../../lib/client';
import { buildHelpText } from '../../lib/help-text';
import { pickId } from '../../lib/prompts';
import { pickItem } from '../../lib/prompts';
import { segmentPickerConfig } from './utils';

export const deleteSegmentCommand = new Command('delete')
Expand Down Expand Up @@ -30,16 +30,16 @@ Non-interactive: --yes is required to confirm deletion when stdin/stdout is not
)
.action(async (idArg, opts, cmd) => {
const globalOpts = cmd.optsWithGlobals() as GlobalOpts;
const id = await pickId(idArg, segmentPickerConfig, globalOpts);
const picked = await pickItem(idArg, segmentPickerConfig, globalOpts);
await runDelete(
id,
picked.id,
!!opts.yes,
{
confirmMessage: `Delete segment ${id}?\nContacts will not be deleted, but broadcasts targeting this segment will no longer work.`,
confirmMessage: `Delete segment "${picked.label}"?\nID: ${picked.id}\nContacts will not be deleted, but broadcasts targeting this segment will no longer work.`,
loading: 'Deleting segment...',
object: 'segment',
successMsg: 'Segment deleted',
sdkCall: (resend) => resend.segments.remove(id),
sdkCall: (resend) => resend.segments.remove(picked.id),
},
globalOpts,
);
Expand Down
10 changes: 5 additions & 5 deletions src/commands/templates/delete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Command } from '@commander-js/extra-typings';
import { runDelete } from '../../lib/actions';
import type { GlobalOpts } from '../../lib/client';
import { buildHelpText } from '../../lib/help-text';
import { pickId } from '../../lib/prompts';
import { pickItem } from '../../lib/prompts';
import { templatePickerConfig } from './utils';

export const deleteTemplateCommand = new Command('delete')
Expand Down Expand Up @@ -31,16 +31,16 @@ Non-interactive: --yes is required to confirm deletion when stdin/stdout is not
)
.action(async (idArg, opts, cmd) => {
const globalOpts = cmd.optsWithGlobals() as GlobalOpts;
const id = await pickId(idArg, templatePickerConfig, globalOpts);
const picked = await pickItem(idArg, templatePickerConfig, globalOpts);
await runDelete(
id,
picked.id,
!!opts.yes,
{
confirmMessage: `Delete template ${id}?\nThis action is permanent and cannot be undone.`,
confirmMessage: `Delete template "${picked.label}"?\nID: ${picked.id}\nThis action is permanent and cannot be undone.`,
loading: 'Deleting template...',
object: 'template',
successMsg: 'Template deleted',
sdkCall: (resend) => resend.templates.remove(id),
sdkCall: (resend) => resend.templates.remove(picked.id),
},
globalOpts,
);
Expand Down
10 changes: 5 additions & 5 deletions src/commands/topics/delete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Command } from '@commander-js/extra-typings';
import { runDelete } from '../../lib/actions';
import type { GlobalOpts } from '../../lib/client';
import { buildHelpText } from '../../lib/help-text';
import { pickId } from '../../lib/prompts';
import { pickItem } from '../../lib/prompts';
import { topicPickerConfig } from './utils';

export const deleteTopicCommand = new Command('delete')
Expand Down Expand Up @@ -30,16 +30,16 @@ Non-interactive: --yes is required to confirm deletion when stdin/stdout is not
)
.action(async (idArg, opts, cmd) => {
const globalOpts = cmd.optsWithGlobals() as GlobalOpts;
const id = await pickId(idArg, topicPickerConfig, globalOpts);
const picked = await pickItem(idArg, topicPickerConfig, globalOpts);
await runDelete(
id,
picked.id,
!!opts.yes,
{
confirmMessage: `Delete topic ${id}?\nAll contact subscriptions and broadcast associations will be removed.`,
confirmMessage: `Delete topic "${picked.label}"?\nID: ${picked.id}\nAll contact subscriptions and broadcast associations will be removed.`,
loading: 'Deleting topic...',
object: 'topic',
successMsg: 'Topic deleted',
sdkCall: (resend) => resend.topics.remove(id),
sdkCall: (resend) => resend.topics.remove(picked.id),
},
globalOpts,
);
Expand Down
10 changes: 5 additions & 5 deletions src/commands/webhooks/delete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Command } from '@commander-js/extra-typings';
import { runDelete } from '../../lib/actions';
import type { GlobalOpts } from '../../lib/client';
import { buildHelpText } from '../../lib/help-text';
import { pickId } from '../../lib/prompts';
import { pickItem } from '../../lib/prompts';
import { webhookPickerConfig } from './utils';

export const deleteWebhookCommand = new Command('delete')
Expand Down Expand Up @@ -32,16 +32,16 @@ Non-interactive: --yes is required to confirm deletion when stdin/stdout is not
)
.action(async (idArg, opts, cmd) => {
const globalOpts = cmd.optsWithGlobals() as GlobalOpts;
const id = await pickId(idArg, webhookPickerConfig, globalOpts);
const picked = await pickItem(idArg, webhookPickerConfig, globalOpts);
await runDelete(
id,
picked.id,
!!opts.yes,
{
confirmMessage: `Delete webhook ${id}?\nEvents will no longer be delivered to this endpoint.`,
confirmMessage: `Delete webhook "${picked.label}"?\nID: ${picked.id}\nEvents will no longer be delivered to this endpoint.`,
loading: 'Deleting webhook...',
object: 'webhook',
successMsg: 'Webhook deleted',
sdkCall: (resend) => resend.webhooks.remove(id),
sdkCall: (resend) => resend.webhooks.remove(picked.id),
},
globalOpts,
);
Expand Down
50 changes: 40 additions & 10 deletions src/lib/prompts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -249,25 +249,27 @@ export type PickerConfig<T extends { id: string }> = {
filter?: (item: T) => boolean;
};

export async function pickId<T extends { id: string }>(
export type PickedItem = { readonly id: string; readonly label: string };

export async function pickItem<T extends { id: string }>(
id: string | undefined,
config: PickerConfig<T>,
globalOpts: GlobalOpts,
): Promise<string>;
export async function pickId<T extends { id: string }>(
): Promise<PickedItem>;
export async function pickItem<T extends { id: string }>(
id: string | undefined,
config: PickerConfig<T>,
globalOpts: GlobalOpts,
opts: { optional: true },
): Promise<string | undefined>;
export async function pickId<T extends { id: string }>(
): Promise<PickedItem | undefined>;
export async function pickItem<T extends { id: string }>(
id: string | undefined,
config: PickerConfig<T>,
globalOpts: GlobalOpts,
opts?: { optional?: boolean },
): Promise<string | undefined> {
): Promise<PickedItem | undefined> {
if (id) {
return id;
return { id, label: id };
}

const optional = opts?.optional ?? false;
Expand Down Expand Up @@ -347,10 +349,16 @@ export async function pickId<T extends { id: string }>(
continue;
}

const itemOptions = displayItems.map((item) => ({
item,
...config.display(item),
}));

const options: { value: string; label: string; hint?: string }[] =
displayItems.map((item) => ({
itemOptions.map(({ item, label, hint }) => ({
value: item.id,
...config.display(item),
label,
hint,
}));

if (optional) {
Expand All @@ -375,7 +383,29 @@ export async function pickId<T extends { id: string }>(
}

if (selected !== FETCH_MORE) {
return selected;
const match = itemOptions.find(({ item }) => item.id === selected);
return { id: selected, label: match?.label ?? selected };
}
}
}

export async function pickId<T extends { id: string }>(
id: string | undefined,
config: PickerConfig<T>,
globalOpts: GlobalOpts,
): Promise<string>;
export async function pickId<T extends { id: string }>(
id: string | undefined,
config: PickerConfig<T>,
globalOpts: GlobalOpts,
opts: { optional: true },
): Promise<string | undefined>;
export async function pickId<T extends { id: string }>(
id: string | undefined,
config: PickerConfig<T>,
globalOpts: GlobalOpts,
opts?: { optional?: boolean },
): Promise<string | undefined> {
const result = await pickItem(id, config, globalOpts, opts as never);
return result?.id;
}
Loading
Loading