Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New Components - timetonic #11813

Merged
merged 12 commits into from
May 9, 2024
178 changes: 178 additions & 0 deletions components/timetonic/actions/common/create-update-row.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
import timetonic from "../../timetonic.app.mjs";
import constants from "../../common/constants.mjs";
import fs from "fs";
import FormData from "form-data";

export default {
props: {
timetonic,
bookCode: {
propDefinition: [
timetonic,
"bookCode",
],
},
tableId: {
propDefinition: [
timetonic,
"tableId",
(c) => ({
bookCode: c.bookCode,
}),
],
reloadProps: true,
},
},
async additionalProps() {
const props = {};
if (!this.tableId || !this.bookCode) {
return props;
}
const { bookTables: { categories } } = await this.timetonic.listTables({
params: {
b_c: this.bookCode,
includeFields: true,
},
});
const { fields } = categories.find(({ id }) => id === this.tableId);
for (const field of fields) {
if (!field?.readOnly) {
const id = `${field.id}`;
props[id] = {
type: constants.FIELD_TYPES[field.type] || "string",
label: field.name,
optional: this.isUpdate()
? true
: !field?.required,
};
if (field.type === "link") {
const linkTableId = field.link.category.id;
const { tableRows } = await this.timetonic.listRows({
params: {
catId: linkTableId,
},
});
const options = tableRows?.map(({
id, name: label,
}) => ({
value: `${id}`,
label,
})) || [];
props[id].options = options;
props[id].description = "The Row ID from the linked table to create a link to";
tableRows.forEach(({
id: rowId, name,
}) => {
props[`${id}_${rowId}_link_text`] = {
type: "string",
default: name,
hidden: true,
};
});
}
if (field.type === "file" || field.type === "files") {
props[id].description = "The path to the file saved to the `/tmp` directory (e.g. `/tmp/example.pdf`). [See the documentation](https://pipedream.com/docs/workflows/steps/code/nodejs/working-with-files/#the-tmp-directory).";
props[`${id}_is_file`] = {
type: "boolean",
default: true,
hidden: true,
};
}
}
}
return props;
},
methods: {
isUpdate() {
return false;
},
uploadFile($, fieldId, filePath, rowId) {
const fileStream = fs.createReadStream(filePath.includes("/tmp")
? filePath
: `/tmp/${filePath}`);
const formData = new FormData();
formData.append("qqfile", fileStream);
return this.timetonic.uploadFile({
$,
params: {
b_c: this.bookCode,
fieldId,
rowId,
},
data: formData,
headers: formData.getHeaders(),
});
},
},
async run({ $ }) {
const {
timetonic,
// eslint-disable-next-line no-unused-vars
isUpdate,
uploadFile,
// eslint-disable-next-line no-unused-vars
bookCode,
tableId,
rowId = `tmp${Math.random().toString(36)
.substr(2, 9)}`,
...fields
} = this;

const fieldValues = {};
const files = [];
for (const [
key,
value,
] of Object.entries(fields)) {
if (key.includes("link_text") || key.includes("is_file")) {
continue;
}
if (fields[`${key}_is_file`]) {
files.push({
fieldId: key,
filePath: value,
});
continue;
}
fieldValues[+key] = fields[`${key}_${value}_link_text`]
? [
{
row_id: +value,
value: fields[`${key}_${value}_link_text`],
},
]
: value;
}
// if fieldValues is empty, createOrUpdateRow will create a new row
// if updating, get and return the row instead
const response = isUpdate() && !Object.entries(fieldValues).length
? await timetonic.getTableValues({
$,
params: {
b_c: bookCode,
catId: tableId,
filterRowIds: {
row_ids: [
rowId,
],
},
},
})
: await timetonic.createOrUpdateRow({
$,
params: {
rowId,
catId: tableId,
fieldValues,
},
});
const newRowId = this.rowId || response.rows[0].id;
for (const file of files) {
await uploadFile($, file.fieldId, file.filePath, newRowId);
}
$.export("$summary", `Successfully ${isUpdate()
? "updated"
: "created"} row in table ${tableId}`);
return response;
},
};
10 changes: 10 additions & 0 deletions components/timetonic/actions/create-row/create-row.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import common from "../common/create-update-row.mjs";

export default {
...common,
key: "timetonic-create-row",
name: "Create Row",
description: "Create a new row within an existing table in TimeTonic. [See the documentation](https://timetonic.com/live/apidoc/#api-Smart_table_operations-createOrUpdateTableRow)",
version: "0.0.1",
type: "action",
};
46 changes: 46 additions & 0 deletions components/timetonic/actions/delete-row/delete-row.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import timetonic from "../../timetonic.app.mjs";

export default {
key: "timetonic-delete-row",
name: "Delete Row",
description: "Deletes a row within an existing table in TimeTonic. [See the documentation](https://timetonic.com/live/apidoc/#api-Smart_table_operations-deleteTableRow)",
version: "0.0.1",
type: "action",
props: {
timetonic,
bookCode: {
propDefinition: [
timetonic,
"bookCode",
],
},
tableId: {
propDefinition: [
timetonic,
"tableId",
(c) => ({
bookCode: c.bookCode,
}),
],
},
rowId: {
propDefinition: [
timetonic,
"rowId",
(c) => ({
tableId: c.tableId,
}),
],
},
},
async run({ $ }) {
const response = await this.timetonic.deleteRow({
$,
params: {
rowId: this.rowId,
},
});
$.export("$summary", `Successfully deleted row with ID ${this.rowId}`);
return response;
},
};
100 changes: 100 additions & 0 deletions components/timetonic/actions/search-rows/search-rows.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import timetonic from "../../timetonic.app.mjs";
import constants from "../../common/constants.mjs";

export default {
key: "timetonic-search-rows",
name: "Search Rows",
description: "Perform a search across table rows based on given criteria. [See the documentation](https://timetonic.com/live/apidoc/#api-Smart_table_operations-listTableRowsById)",
version: "0.0.1",
type: "action",
props: {
timetonic,
bookCode: {
propDefinition: [
timetonic,
"bookCode",
],
},
tableId: {
propDefinition: [
timetonic,
"tableId",
(c) => ({
bookCode: c.bookCode,
}),
],
},
searchField: {
propDefinition: [
timetonic,
"fieldId",
(c) => ({
bookCode: c.bookCode,
tableId: c.tableId,
}),
],
reloadProps: true,
},
},
async additionalProps() {
const props = {};
if (!this.searchField || !this.bookCode || !this.tableId) {
return props;
}
const { tableValues: { fields } } = await this.timetonic.getTableValues({
params: {
catId: this.tableId,
b_c: this.bookCode,
},
});
const field = fields.find(({ id }) => id === this.searchField);
props.searchValue = {
type: constants.FIELD_TYPES[field.type] || "string",
label: "Search Value",
description: "The value to search for",
};
if (field.type === "link") {
props.searchValue.description = `Please enter the Row ID from ${field.link.category.name} to link to`;
}
return props;
},
methods: {
findMatches(fields) {
const field = fields.find(({ id }) => id === this.searchField);
let matches;
if (field.type === "link") {
matches = field.values.filter(({ value }) =>
value?.length && value.find((link) => link.row_id == this.searchValue));
} else {
matches = field.values.filter(({ value }) => value == this.searchValue);
}
return matches.map(({ id }) => id);
},
buildRow(fields, matches) {
const rows = [];
matches.forEach((match) => {
const row = {};
fields.forEach((field) => {
row[field.name] = field.values.find(({ id }) => id === match).value;
});
rows.push(row);
});
return rows;
},
},
async run({ $ }) {
const { tableValues: { fields } } = await this.timetonic.getTableValues({
$,
params: {
catId: this.tableId,
b_c: this.bookCode,
},
});
const matches = this.findMatches(fields);
const rows = this.buildRow(fields, matches);
$.export("$summary", `Found ${rows.length} matching row${rows.length === 1
? ""
: "s"}`);
return rows;
},
};
28 changes: 28 additions & 0 deletions components/timetonic/actions/update-row/update-row.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import common from "../common/create-update-row.mjs";

export default {
...common,
key: "timetonic-update-row",
name: "Update Row",
description: "Updates the values within a specified row in a table. [See the documentation](https://timetonic.com/live/apidoc/#api-Smart_table_operations-createOrUpdateTableRow)",
version: "0.0.1",
type: "action",
props: {
...common.props,
rowId: {
propDefinition: [
common.props.timetonic,
"rowId",
(c) => ({
tableId: c.tableId,
}),
],
},
},
methods: {
...common.methods,
isUpdate() {
return true;
},
},
};
17 changes: 17 additions & 0 deletions components/timetonic/common/constants.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
const DEFAULT_LIMIT = 100;

const FIELD_TYPES = {
shorttext: "string",
mediumtext: "string",
email: "string",
phone: "string",
date: "string",
link: "string",
boolean: "boolean",
int: "integer",
};

export default {
DEFAULT_LIMIT,
FIELD_TYPES,
};
Loading
Loading