Skip to content

Commit

Permalink
Merge pull request #13 from trycourier/bryan/list-templates
Browse files Browse the repository at this point in the history
adding templates:list
  • Loading branch information
bwebs authored Jun 18, 2024
2 parents 3420fdf + bfb9524 commit 3291593
Show file tree
Hide file tree
Showing 4 changed files with 184 additions and 5 deletions.
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,15 @@
"@trycourier/core": "^6.0.0",
"@trycourier/courier": "^6.1.2",
"cli-spinners": "^3.0.0",
"csv-stringify": "^6.5.0",
"dotenv": "^16.0.3",
"duckdb": "^0.10.2",
"duckdb": "^1.0.0",
"execa": "^9.1.0",
"ink": "^5.0.1",
"ink-link": "^4.0.0",
"ink-spinner": "^5.0.0",
"lodash": "^4.17.21",
"luxon": "^3.4.4",
"ms": "3.0.0-canary.1",
"react": "^18.2.0",
"usehooks-ts": "^3.1.0",
Expand All @@ -41,6 +43,7 @@
"devDependencies": {
"@sindresorhus/tsconfig": "^5.0.0",
"@types/lodash": "^4.17.4",
"@types/luxon": "^3.4.2",
"@types/node": "^20.13.0",
"@types/react": "^18.0.32",
"@types/yargs-parser": "^21.0.0",
Expand Down
135 changes: 135 additions & 0 deletions source/commands/Templates/List.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
import React, {useEffect, useState} from 'react';
import {useCliContext} from '../../components/Context.js';
import {Notification} from '@trycourier/courier/api/index.js';
import Table from '../../components/Table.js';
import {useBoolean} from 'usehooks-ts';
import Spinner from '../../components/Spinner.js';
import {Text} from 'ink';
import _ from 'lodash';
import {DateTime} from 'luxon';
import fs from 'fs/promises';
import {stringify} from 'csv-stringify/sync';
import UhOh from '../../components/UhOh.js';

const MAX_PAGES = 100;
const FILENAME = 'templates';

interface IParams {
csv?: boolean;
json?: boolean;
webhook?: string;
filename?: string;
}

const TemplatesList = () => {
const [templates, setTemplates] = useState<Notification[]>([]);
const {courier, parsedParams} = useCliContext();
const running = useBoolean(true);
const processing = useBoolean(true);
const [error, setError] = useState<string | undefined>();

const {csv, filename, json, webhook} = parsedParams as IParams;

const out_file = filename || FILENAME + (csv ? '.csv' : '.json');

useEffect(() => {
getTemplates();
}, []);

const getTemplates = async () => {
let cursor: string | undefined;
let page = -1;
while (page < MAX_PAGES) {
page++;
const templates = await courier.notifications.list({cursor});
setTemplates(p => [...p, ...templates.results]);
if (templates.paging.more) {
cursor = templates.paging.cursor;
} else {
break;
}
}
processing.setFalse();
};

useEffect(() => {
if (!processing.value) {
runExport();
}
}, [processing.value, templates]);

const runExport = async () => {
if (csv) {
await fs.writeFile(
out_file,
stringify(flattenData(templates), {header: true}),
);
} else if (json) {
await fs.writeFile(
out_file,
JSON.stringify(flattenData(templates), null, 2),
{
encoding: 'utf-8',
},
);
}
if (webhook?.length) {
try {
await fetch(webhook, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(flattenData(templates)),
});
} catch (e) {
setError(e instanceof Error ? e.message : String(e));
}
}
running.setFalse();
};

if (running.value) {
return <Spinner text="Retrieving notification templates" />;
} else if (error?.length) {
return <UhOh text={error} />;
} else if (json || csv) {
return <Text>Saved to {out_file}</Text>;
} else if (webhook?.length) {
return <Text>Webhook sent to {webhook}</Text>;
} else {
return (
<Table
data={templates.map(
({tags, routing, created_at, updated_at, ...rest}) => {
return {
...rest,
tags: _.map(tags?.data, t => t.name).join(', '),
routing: JSON.stringify(routing, null, 2),
created_at: DateTime.fromMillis(created_at, {
zone: 'utc',
}).toRelative(),
updated_at: DateTime.fromMillis(updated_at, {
zone: 'utc',
}).toRelative(),
};
},
)}
/>
);
}
};

const flattenData = (data: Notification[]) => {
return data.map(({tags, routing, created_at, updated_at, ...rest}) => {
return {
...rest,
tags: _.map(tags?.data, t => t.name).join(', '),
routing: JSON.stringify(routing, null, 2),
created_at: DateTime.fromMillis(created_at, {zone: 'utc'}).toISO(),
updated_at: DateTime.fromMillis(updated_at, {zone: 'utc'}).toISO(),
};
});
};

export default TemplatesList;
26 changes: 26 additions & 0 deletions source/mappings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import TenantsBulk from './commands/TenantsBulk.js';
import MarkAllRead from './commands/Inbox/MarkAllRead.js';
import ArchiveAll from './commands/Inbox/ArchiveAll.js';
import ArchiveAllBulk from './commands/Inbox/ArchiveAllBulk.js';
import TemplatesList from './commands/Templates/List.js';

const mappings: Map<string, IMapping> = new Map();

Expand Down Expand Up @@ -399,4 +400,29 @@ mappings.set('inbox:archive-all:bulk', {
},
});

mappings.set('templates:list', {
instructions: 'List all templates in your workspace and export it',
options: [
{
option: '--csv',
value: 'Output the templates in CSV format',
},
{
option: '--json',
value: 'Output the templates in JSON format',
},
{
option: '--webhook <webhook_url>',
value: 'Where to send the JSON output',
},
{
option: '--filename <filename>',
value: 'Name of the file to save the output',
},
],
component: () => {
return <TemplatesList />;
},
});

export default mappings;
23 changes: 19 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,11 @@
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.17.5.tgz#e6c29b58e66995d57cd170ce3e2a61926d55ee04"
integrity sha512-MBIOHVZqVqgfro1euRDWX7OO0fBVUUMrN6Pwm8LQsz8cWhEpihlvR70ENj3f40j58TNxZaWv2ndSkInykNBBJw==

"@types/luxon@^3.4.2":
version "3.4.2"
resolved "https://registry.yarnpkg.com/@types/luxon/-/luxon-3.4.2.tgz#e4fc7214a420173cea47739c33cdf10874694db7"
integrity sha512-TifLZlFudklWlMBfhubvgqTXRzLDI5pCbGa4P8a3wPyUQSW+1xQ5eDsreP9DWHX3tjq1ke96uYG/nwundroWcA==

"@types/minimist@^1.2.2":
version "1.2.5"
resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.5.tgz#ec10755e871497bcd83efe927e43ec46e8c0747e"
Expand Down Expand Up @@ -1162,6 +1167,11 @@ csstype@^3.0.2:
resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81"
integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==

csv-stringify@^6.5.0:
version "6.5.0"
resolved "https://registry.yarnpkg.com/csv-stringify/-/csv-stringify-6.5.0.tgz#7b1491893c917e018a97de9bf9604e23b88647c2"
integrity sha512-edlXFVKcUx7r8Vx5zQucsuMg4wb/xT6qyz+Sr1vnLrdXqlLD1+UKyWNyZ9zn6mUW1ewmGxrpVwAcChGF0HQ/2Q==

currently-unhandled@^0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea"
Expand Down Expand Up @@ -1319,10 +1329,10 @@ dotenv@^16.0.3:
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.4.5.tgz#cdd3b3b604cb327e286b4762e13502f717cb099f"
integrity sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==

duckdb@^0.10.2:
version "0.10.2"
resolved "https://registry.yarnpkg.com/duckdb/-/duckdb-0.10.2.tgz#a0a6c7d41487d566e2d524b81395151e0e1ca91c"
integrity sha512-7UGLRp+zkAzE0AQjyUfOyEjuX7Xs3St452+ZtUSbQEE8DJjc6GUWscxYPm5XPe5fX4nL+Zy9lVMEss1Yuw74kA==
duckdb@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/duckdb/-/duckdb-1.0.0.tgz#de81d9b93311bb816901b582de27ae75fa0e20e2"
integrity sha512-QwpcIeN42A2lL19S70mUFibZgRcEcZpCkKHdzDgecHaYZhXj3+1i2cxSDyAk/RVg5CYnqj1Dp4jAuN4cc80udA==
dependencies:
"@mapbox/node-pre-gyp" "^1.0.0"
node-addon-api "^7.0.0"
Expand Down Expand Up @@ -3110,6 +3120,11 @@ lru-cache@^7.5.1, lru-cache@^7.7.1:
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-7.18.3.tgz#f793896e0fd0e954a59dfdd82f0773808df6aa89"
integrity sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==

luxon@^3.4.4:
version "3.4.4"
resolved "https://registry.yarnpkg.com/luxon/-/luxon-3.4.4.tgz#cf20dc27dc532ba41a169c43fdcc0063601577af"
integrity sha512-zobTr7akeGHnv7eBOXcRgMeCP6+uyYsczwmeRCauvpvaAltgNyTbLH/+VaEAPUeWBT+1GuNmz4wC/6jtQzbbVA==

make-dir@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f"
Expand Down

0 comments on commit 3291593

Please sign in to comment.