@swell/cli
Version:
Swell's command line interface/utility
191 lines (190 loc) • 7.55 kB
JavaScript
import { input, select } from '@inquirer/prompts';
import { Args, Flags } from '@oclif/core';
import { singularize } from 'inflection';
import { CreateConfigCommand } from '../../create-config-command.js';
import { ConfigType } from '../../lib/apps/index.js';
import { toFileName, toNotificationLabel } from '../../lib/create/index.js';
import { SCHEMAS } from '../../lib/create/schemas.js';
export default class CreateNotification extends CreateConfigCommand {
static args = {
name: Args.string({
default: '',
description: 'Notification name (e.g., order-paid)',
}),
};
static description = 'Create notification files and configuration in the notifications folder.';
static examples = [
'$ swell create notification',
'$ swell create notification order-paid -m orders -y',
'$ swell create notification order-paid -m orders -e created -s "Order Paid" --admin --once -y',
];
static helpMeta = {
usageDirect: '<name> -m <model> [...] -y',
};
static flags = {
model: Flags.string({
char: 'm',
default: '',
description: 'Triggering model (required with -y)',
}),
event: Flags.string({
char: 'e',
default: '',
description: 'Triggering event (default: created)',
}),
subject: Flags.string({
char: 's',
default: '',
description: 'Email subject',
}),
description: Flags.string({
char: 'd',
default: '',
description: 'Description',
}),
admin: Flags.boolean({
char: 'a',
description: 'Send to store admins only',
}),
once: Flags.boolean({
char: 'o',
description: 'Send only once when conditions met',
}),
overwrite: Flags.boolean({
default: false,
description: 'Overwrite existing file',
}),
yes: Flags.boolean({
char: 'y',
description: 'Skip prompts, require all arguments',
}),
};
static summary = 'Create notification files and configuration in the notifications folder.';
createType = ConfigType.NOTIFICATION;
async run() {
const { args, flags } = await this.parse(CreateNotification);
const confirmYes = Boolean(flags.yes);
// NON-INTERACTIVE PATH
if (confirmYes) {
// Validate NAME argument
if (!args.name) {
this.error('Missing required argument for non-interactive mode: NAME\n\nExample: swell create notification order-paid -m orders -y', { exit: 1 });
}
// Validate --model flag
if (!flags.model) {
this.error('Missing required flag for non-interactive mode: --model\n\nExample: swell create notification order-paid -m orders -y', { exit: 1 });
}
// Build with defaults
const name = toFileName(args.name);
const { model, event: eventFlag, subject: subjectFlag, description: descFlag, admin: adminFlag, once: onceFlag, overwrite, } = flags;
const event = eventFlag || 'created';
const subject = subjectFlag || toNotificationLabel(name);
const description = descFlag || '';
const admin = adminFlag || false;
const once = onceFlag || false;
await this.writeNotificationFile({ admin, description, event, model, name, once, subject }, overwrite,
/* shouldConfirm */ false);
return;
}
// INTERACTIVE PATH
let name = args.name;
let model = flags.model;
const { event: eventFlag, description: descFlag, subject: subjectFlag, overwrite, } = flags;
// Prompt for admin if not provided
let { admin } = flags;
if (admin === undefined) {
const choice = await select({
choices: [
{ name: 'Admins', value: 'admin' },
{ name: 'Customers', value: 'customer' },
],
message: 'Who will be notified?',
});
admin = choice === 'admin';
}
// Prompt for model if not provided
if (!model) {
const collections = await this.getCollectionOptions();
model = await select({
choices: collections.map((collectionName) => ({
name: collectionName,
value: collectionName,
})),
loop: false,
message: 'Which model will trigger the notification?',
pageSize: 25,
});
}
// Prompt for event if not provided
const event = eventFlag ||
(await input({
default: 'created',
message: 'Event to trigger the notification',
}));
// Prompt for name if not provided
if (!name) {
name = await input({
default: `${singularize(model)}-${event}`,
message: 'Name of the notification',
});
}
name = toFileName(name);
// Prompt for description if not provided
const description = descFlag ||
(await input({
default: `Notify ${admin ? 'admin' : 'customer'} when ${singularize(model)}...`,
message: 'Describe what the notification does',
}));
// Prompt for once if not provided
let { once } = flags;
if (once === undefined) {
once = await select({
choices: [
{ name: 'Every time conditions are met', value: false },
{ name: 'Only the first time conditions are met', value: true },
],
message: 'When should we send this notification?',
});
}
// Prompt for subject if not provided
const subject = subjectFlag ||
(await input({
default: toNotificationLabel(name),
message: 'Subject of the notification email',
}));
await this.writeNotificationFile({ admin, description, event, model, name, once, subject }, overwrite,
/* shouldConfirm */ true);
}
async writeNotificationFile({ admin, description, event, model, name, once, subject, }, overwrite, shouldConfirm = true) {
const fileName = toFileName(name);
const noteLabel = toNotificationLabel(name);
const fileBody = {
$schema: SCHEMAS.NOTIFICATION,
collection: model,
conditions: {},
event: event || 'created',
label: noteLabel,
method: 'email',
subject: subject || `${noteLabel}...`,
};
fileBody.description = description;
if (admin) {
fileBody.admin = true;
}
else {
fileBody.contact = 'account.email';
}
// Note since we are using events, we don't need 'new' option
if (!once) {
fileBody.repeat = true;
}
fileBody.query = {
expand: [],
};
fileBody.sample = {};
const jsonCreated = await this.createFile({ fileBody, fileName }, overwrite, shouldConfirm);
if (jsonCreated) {
await this.createFile({ extension: 'tpl', fileBody: '\n', fileName }, overwrite, false);
}
}
}