speedybot
Version:
<p align="center"> <a href="https://github.com/valgaze/speedybot"> <img src="https://img.shields.io/npm/v/speedybot.svg" /> </a> <a href="https://github.com/valgaze/speedybot"> <img src="https://img.shields.io/npm/dm/speedybot.svg" /> </a>
512 lines • 16.5 kB
JavaScript
import { CONSTANTS } from "./index";
export const checkers = {
isSpeedyCard(input) {
return (typeof input === "object" &&
"build" in input &&
typeof input.build === "function");
},
isCard(cardCandidate) {
if (this.isSpeedyCard(cardCandidate)) {
return true;
}
return ("$schema" in cardCandidate &&
"type" in cardCandidate &&
"version" in cardCandidate);
},
isEmail(candidate) {
const res = candidate.includes("@") && candidate.includes(".");
return res;
},
};
export const SpeedyCardId = {
dropdown: "addPickerDropdown_result",
};
export class SpeedyCard {
json = {
$schema: "http://adaptivecards.io/schemas/adaptive-card.json",
type: "AdaptiveCard",
version: "1.0",
body: [],
};
tools = {
checkColor(candidate) {
const colorMapping = {
default: "Default",
dark: "Dark",
light: "Light",
accent: "Accent",
good: "Good",
warning: "Warning",
attention: "Attention",
blue: "Accent",
red: "Attention",
green: "Good",
yellow: "Warning",
};
const lowerCaseInput = candidate.toLowerCase();
return colorMapping[lowerCaseInput] || "Default";
},
};
_stash = {
needsSubmit: false,
title: "",
subTitle: "",
chips: [],
data: {},
submitLabel: "Submit",
};
id = {};
needsSubmit() {
return Boolean(this._stash.needsSubmit);
}
checkId(id = "") {
if (id in this.id) {
this.id[id]++;
const num = this.id[id];
const modifiedId = `${id}_${num}`;
return modifiedId;
}
else {
this.id[id] = 1;
return id;
}
}
constructor() { }
addTitle(title) {
this._stash.title = title;
return this;
}
addSubtitle(subTitle) {
this._stash.subTitle = subTitle;
return this;
}
addTable(input, separator = false) {
const payload = {
type: "FactSet",
separator,
facts: Array.isArray(input)
? input.map(([label, value]) => ({ title: label, value }))
: Object.entries(input).map(([label, value]) => ({
title: label,
value,
})),
};
this.json.body.push(payload);
return this;
}
addChip(payload, id = CONSTANTS.CHIP_LABEL) {
return this.addChips([payload], id);
}
addChips(chips, id = CONSTANTS.CHIP_LABEL) {
const chipPayload = chips.map((chip) => {
let chipLabel = "";
let chipAction = "";
if (typeof chip === "string") {
chipLabel = chip;
chipAction = chip;
}
else {
const { title, value = "" } = chip;
chipLabel = title;
if (value) {
chipAction = value;
}
else {
chipAction = title;
}
}
const payload = {
type: "Action.Submit",
title: chipLabel,
data: {
[id]: chipAction,
},
};
return payload;
});
this.json.actions = this.json.actions
? this.json.actions.concat(chipPayload)
: chipPayload;
return this;
}
addImage(url, config = {}) {
if (url) {
const payload = {
horizontalAlignment: config.align ?? "Center",
size: config.size ?? "ExtraLarge",
type: "Image",
url,
};
if (config.targetURL) {
const linkPayload = {
type: "Action.OpenUrl",
style: "positive",
isPrimary: true,
url: config.targetURL,
};
payload.selectAction = linkPayload;
}
this.json.body.push(payload);
}
return this;
}
addLink(url, label) {
return this.addText(`**[${label || url}](${url})**`);
}
addLinkButton(url, label) {
const id = String(Math.random()).slice(3);
const cleanId = this.checkId(id);
const payload = {
type: "Action.OpenUrl",
id: cleanId,
title: label ?? url,
url: url,
};
this.addAction(payload);
return this;
}
addText(text, config = {}) {
const { bold = false, size = "Medium", align = "Left", color, backgroundColor, vertAlign, } = config;
const payload = {
type: "TextBlock",
text: text,
wrap: true,
size,
horizontalAlignment: align,
...(color && { color: this.tools.checkColor(color) }),
...(bold && { weight: "Bolder" }),
};
if (backgroundColor || vertAlign) {
const containerPayload = {
type: "Container",
height: "stretch",
items: [payload],
...(backgroundColor && {
style: this.tools.checkColor(backgroundColor),
}),
...(color && { color: this.tools.checkColor(color) }),
...(vertAlign && {
verticalContentAlignment: vertAlign,
}),
};
this.json.body.push(containerPayload);
}
else {
this.json.body.push(payload);
}
return this;
}
addHeader(text, config = {}) {
const hasURL = config.iconURL?.includes("http");
const textPayload = {
items: [
{
type: "TextBlock",
text: text,
wrap: true,
size: config.textSize || "Large",
horizontalAlignment: config.textAlign ?? config.rtl ? "Right" : "Left",
...(config.textColor && {
color: this.tools.checkColor(config.textColor),
}),
verticalContentAlignment: "Center",
...(config.backgroundColor && {
style: this.tools.checkColor(config.backgroundColor),
}),
},
],
};
const iconPayload = config.iconURL
? hasURL
? {
width: "32px",
items: [
{
type: "Image",
horizontalAlignment: config.iconAlignment ?? "Left",
url: config.iconURL,
...(config.iconRound && { style: "person" }),
width: `${config.iconWidth ?? "16"}px`,
},
],
}
: {
type: "Column",
width: "auto",
items: [
{
type: "TextBlock",
text: config.iconURL,
verticalContentAlignment: "Center",
},
],
}
: null;
const headerPayload = {
type: "ColumnSet",
columns: config.rtl
? [textPayload, iconPayload].filter(Boolean)
: [iconPayload, textPayload].filter(Boolean),
};
this._stash.header = headerPayload;
return this;
}
addBlock(content, config = {}) {
if (typeof content === "string") {
return this.addText(content, config);
}
if (content instanceof SpeedyCard) {
const { backgroundColor, vertAlign } = config;
const { body } = content.build();
const containerPayload = {
...(config.separator && { separator: config.separator }),
type: "Container",
height: "stretch",
items: body,
...(backgroundColor && {
style: this.tools.checkColor(backgroundColor),
}),
...(vertAlign && {
verticalContentAlignment: vertAlign,
}),
};
this._stash.needsSubmit = !this._stash.needsSubmit
? content.needsSubmit()
: this._stash.needsSubmit;
this.json.body.push(containerPayload);
}
return this;
}
addSubcard(card, textLabel = "") {
const subCard = {
type: "Action.ShowCard",
title: textLabel,
card: "build" in card && typeof card.build === "function"
? card.build()
: card,
};
this.addAction(subCard);
return this;
}
addPickerDropdown(choices, id = SpeedyCardId.dropdown) {
const cleanId = this.checkId(id);
this._stash.needsSubmit = true;
const formattedChoices = choices.map((choice, idx) => {
if (typeof choice === "object") {
return choice;
}
return {
title: String(choice),
value: String(choice),
};
});
const payload = {
type: "Input.ChoiceSet",
id: cleanId,
value: "0",
isMultiSelect: false,
isVisible: true,
choices: formattedChoices,
};
this.json.body.push(payload);
return this;
}
addSingleSelect(choices, id = "addSingleSelectresult") {
return this.addSelect(choices, id, {
isMultiSelect: false,
style: "expanded",
});
}
addMultiSelect(choices, id = "addMultiSelect_result") {
return this.addSelect(choices, id, { isMultiSelect: true });
}
addSelect(choices, id, config = {}) {
this._stash.needsSubmit = true;
const cleanId = this.checkId(id);
let formattedChoices;
if (Array.isArray(choices) && typeof choices[0] === "string") {
formattedChoices = choices.map((choice) => ({
title: String(choice),
value: String(choice),
}));
}
else {
formattedChoices = choices;
}
const payload = {
type: "Input.ChoiceSet",
id: cleanId,
value: "0",
isMultiSelect: Boolean(config.isMultiSelect),
isVisible: true,
...(config.style && { style: "expanded" }),
choices: formattedChoices,
style: "expanded",
};
this.json.body.push(payload);
return this;
}
addPickerDate(textLabel, id = "addPickerDate_result") {
this._stash.needsSubmit = true;
const cleanId = this.checkId(id);
const textPayload = this.buildTextPayload(textLabel);
const datePicker = {
type: "Input.Date",
id: cleanId,
};
this.json.body.push(textPayload, datePicker);
return this;
}
addPickerTime(textLabel, id = "addPickerTime_result") {
this._stash.needsSubmit = true;
const cleanId = this.checkId(id);
const textPayload = this.buildTextPayload(textLabel);
const timePicker = {
type: "Input.Time",
id: cleanId,
};
this.json.body.push(textPayload, timePicker);
return this;
}
addTextInput(placeholder, id = "addTextInput_result") {
this._stash.needsSubmit = true;
const cleanId = this.checkId(id);
const payload = {
id: cleanId,
placeholder,
type: "Input.Text",
};
this.json.body.push(payload);
return this;
}
addTextarea(placeholder, id = "addTextarea_result") {
this._stash.needsSubmit = true;
const cleanId = this.checkId(id);
const payload = {
id: cleanId,
placeholder,
type: "Input.Text",
isMultiline: true,
};
this.json.body.push(payload);
return this;
}
setBackgroundImage(url) {
this.json.backgroundImage = url;
return this;
}
setSubmitButtonTitle(label) {
this._stash.submitLabel = label;
return this;
}
attachData(payload) {
this._stash.needsSubmit = true;
this._stash.data = payload;
return this;
}
buildTextPayload(text, textConfig = {}) {
const payload = {
type: "TextBlock",
text,
size: "Medium",
isSubtle: true,
wrap: true,
weight: "Lighter",
...textConfig,
};
return payload;
}
addAction(a) {
if (!this.json.actions) {
this.json.actions = [];
}
this.json.actions.push(a);
}
addDeleteButton(label = CONSTANTS.destroyLabel) {
return this.addButton(label, CONSTANTS.submitToken, CONSTANTS.action_delete);
}
addButton(label, id = "button_result", attachedData = {}) {
const payload = {
type: "Action.Submit",
title: label,
data: {
[id]: attachedData,
},
};
this.addAction(payload);
return this;
}
survey(questions, title = "📝 Survey") {
const card = new SpeedyCard();
card.addHeader(title);
questions.forEach((question, idx) => {
let id = question.id || `question_${idx + 1}`;
switch (question.type) {
case "text":
card.addTextInput(question.question, id);
break;
case "single-select":
card.addText(question.question);
card.addSingleSelect(question.choices || [], id);
break;
case "multi-select":
card.addText(question.question);
card.addMultiSelect(question.choices || [], id);
break;
case "picker-dropdown":
card.addText(question.question);
card.addPickerDropdown(question.choices || [], id);
break;
case "picker-date":
card.addPickerDate(question.question, id);
break;
case "picker-time":
card.addPickerTime(question.question, id);
break;
case "textarea":
card.addTextarea(question.question, id);
break;
}
});
return card;
}
build() {
const json = JSON.parse(JSON.stringify(this.json));
const needsSubmit = this._stash.needsSubmit;
if (this._stash.subTitle) {
json.body.unshift(this.buildTextPayload(this._stash.subTitle));
}
if (this._stash.title) {
json.body.unshift(this.buildTextPayload(this._stash.title, {
weight: "Bolder",
size: "ExtraLarge",
}));
}
if (needsSubmit) {
const payload = {
type: "Action.Submit",
title: this._stash.submitLabel,
};
if (this._stash.data && Object.keys(this._stash.data).length > 0) {
payload.data = this._stash.data;
}
if (!json.actions) {
json.actions = [];
}
json.actions.push(payload);
}
const hasHeader = Boolean(this._stash.header);
if (hasHeader) {
json.body = [
this._stash.header,
{
separator: true,
type: "Container",
items: json.body,
},
];
}
return json;
}
}
//# sourceMappingURL=cards.js.map