Skip to content
Merged
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
32 changes: 0 additions & 32 deletions components/habitify/app/habitify.app.mjs

This file was deleted.

63 changes: 63 additions & 0 deletions components/habitify/habitify.app.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { axios } from "@pipedream/platform";

export default {
type: "app",
app: "habitify",
propDefinitions: {
habitIds: {
type: "string[]",
label: "Habit IDs",
description: "The IDs of the habits to watch",
async options() {
const { data } = await this.getHabits();
return data?.map(({
id, name,
}) => ({
label: name,
value: id,
})) || [];
},
},
},
methods: {
_apiKey() {
return this.$auth.api_key;
},
_apiUrl() {
return "https://api.habitify.me";
},
async _makeRequest({
$ = this, path, ...args
}) {
return axios($, {
url: `${this._apiUrl()}${path}`,
headers: {
Authorization: this._apiKey(),
},
...args,
});
},
getHabits(args = {}) {
return this._makeRequest({
path: "/habits",
...args,
});
},
getHabitStatus({
habitId, ...args
}) {
return this._makeRequest({
path: `/status/${habitId}`,
...args,
});
},
getHabitLogs({
habitId, ...args
}) {
return this._makeRequest({
path: `/logs/${habitId}`,
...args,
});
},
},
};
6 changes: 3 additions & 3 deletions components/habitify/package.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"name": "@pipedream/habitify",
"version": "0.0.4",
"version": "0.1.0",
"description": "Pipedream Habitify Components",
"main": "app/habitify.app.mjs",
"main": "habitify.app.mjs",
"keywords": [
"pipedream",
"habitify"
Expand All @@ -13,6 +13,6 @@
"access": "public"
},
"dependencies": {
"@pipedream/platform": "^1.6.8"
"@pipedream/platform": "^3.1.1"
}
}
42 changes: 42 additions & 0 deletions components/habitify/sources/common/base-polling.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import habitify from "../../habitify.app.mjs";
import { DEFAULT_POLLING_SOURCE_TIMER_INTERVAL } from "@pipedream/platform";

export default {
props: {
habitify,
db: "$.service.db",
timer: {
type: "$.interface.timer",
default: {
intervalSeconds: DEFAULT_POLLING_SOURCE_TIMER_INTERVAL,
},
},
},
methods: {
getCurrentDateTime() {
return new Date().toISOString()
.replace("Z", this.getTimeZoneOffset());
},
getTimeZoneOffset() {
const offset = new Date().getTimezoneOffset();
const sign = offset > 0
? "-"
: "+";
const abs = Math.abs(offset);
const hours = String(Math.floor(abs / 60)).padStart(2, "0");
const minutes = String(abs % 60).padStart(2, "0");
return `${sign}${hours}:${minutes}`;
},
convertToUTCOffset(dateString) {
const date = new Date(dateString);
const iso =
date.getUTCFullYear() +
"-" + String(date.getUTCMonth() + 1).padStart(2, "0") +
"-" + String(date.getUTCDate()).padStart(2, "0") +
"T" + String(date.getUTCHours()).padStart(2, "0") +
":" + String(date.getUTCMinutes()).padStart(2, "0") +
":" + String(date.getUTCSeconds()).padStart(2, "0");
return iso + "+00:00";
},
},
};
65 changes: 65 additions & 0 deletions components/habitify/sources/habit-logged/habit-logged.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import common from "../common/base-polling.mjs";
import sampleEmit from "./test-event.mjs";

export default {
...common,
key: "habitify-habit-logged",
name: "Habit Logged",

Check warning on line 7 in components/habitify/sources/habit-logged/habit-logged.mjs

View workflow job for this annotation

GitHub Actions / Lint Code Base

Source names should start with "New". See https://pipedream.com/docs/components/guidelines/#source-name
description: "Emit new event when a new log is created for the selected habit(s). [See the documentation](https://docs.habitify.me/core-resources/habits/logs)",
version: "0.0.1",
type: "source",
dedupe: "unique",
props: {
...common.props,
habitIds: {
propDefinition: [
common.props.habitify,
"habitIds",
],
},
},
methods: {
...common.methods,
_getLastTs() {
return this.db.get("lastTs") || this.convertToUTCOffset(this.getCurrentDateTime());
},
_setLastTs(ts) {
this.db.set("lastTs", ts);
},
generateMeta(log) {
return {
id: log.id,
summary: `New log with ID ${log.id} created for habit ${log.habit_id}`,
ts: Date.parse(log.created_date),
};
},
},
async run() {
const lastTs = this._getLastTs();
let maxTs = lastTs;
const params = {
from: lastTs,
to: this.convertToUTCOffset(this.getCurrentDateTime()),
};
const logs = [];
for (const habitId of this.habitIds) {
const { data } = await this.habitify.getHabitLogs({
habitId,
params,
});
if (!data.length) {
continue;
}
logs.push(...data);
if (Date.parse(data[data.length - 1].created_date) > Date.parse(maxTs)) {
maxTs = this.convertToUTCOffset(data[data.length - 1].created_date);
}
}
this._setLastTs(maxTs);
logs.sort((a, b) => Date.parse(a.created_date) - Date.parse(b.created_date));
logs.forEach((log) => {
this.$emit(log, this.generateMeta(log));
});
},
sampleEmit,
};
7 changes: 7 additions & 0 deletions components/habitify/sources/habit-logged/test-event.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export default {
"id": "-Og94QB1QHNBaFW1Q12v",
"value": 1,
"created_date": "2025-12-10T21:05:52.838Z",
"unit_type": "rep",
"habit_id": "C0D4CD24-EF3E-4EAB-9D88-17BBDE801FC1"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import common from "../common/base-polling.mjs";
import sampleEmit from "./test-event.mjs";

export default {
...common,
key: "habitify-habit-status-updated",
name: "Habit Status Updated",

Check warning on line 7 in components/habitify/sources/habit-status-updated/habit-status-updated.mjs

View workflow job for this annotation

GitHub Actions / Lint Code Base

Source names should start with "New". See https://pipedream.com/docs/components/guidelines/#source-name
description: "Emit new event when the status of a habit is updated. [See the documentation](https://docs.habitify.me/core-resources/habits/status)",
version: "0.0.1",
type: "source",
dedupe: "unique",
props: {
...common.props,
habitIds: {
propDefinition: [
common.props.habitify,
"habitIds",
],
},
statuses: {
type: "string[]",
label: "Statuses",
description: "The statuses to watch for. [See the documentation](https://docs.habitify.me/core-resources/habits/status)",
options: [
"in_progress",
"completed",
"skipped",
"failed",
],
optional: true,
},
},
hooks: {
async deploy() {
const previousStatuses = {};
for (const habitId of this.habitIds) {
const { data } = await this.habitify.getHabitStatus({
habitId,
params: {
target_date: this.convertToUTCOffset(this.getCurrentDateTime()),
},
});
previousStatuses[habitId] = data.status;
}
this._setPreviousStatuses(previousStatuses);
},
},
methods: {
...common.methods,
_getPreviousStatuses() {
return this.db.get("previousStatuses") || {};
},
_setPreviousStatuses(statuses) {
this.db.set("previousStatuses", statuses);
},
generateMeta(status) {
return {
id: `${status.habit_id}-${status.progress.reference_date}`,
summary: `New Status ${status.status} for habit ${status.habit_id}`,
ts: Date.parse(status.progress.reference_date),
};
},
},
async run() {
const previousStatuses = this._getPreviousStatuses();
const currentStatuses = {};
const targetDate = this.convertToUTCOffset(this.getCurrentDateTime());
for (const habitId of this.habitIds) {
const { data } = await this.habitify.getHabitStatus({
habitId,
params: {
target_date: targetDate,
},
});
currentStatuses[habitId] = data.status;
if (
previousStatuses[habitId] !== data.status
&& (!this.statuses || this.statuses.includes(data.status))
) {
data.habit_id = habitId;
this.$emit(data, this.generateMeta(data));
}
}
this._setPreviousStatuses(currentStatuses);
},
sampleEmit,
};
10 changes: 10 additions & 0 deletions components/habitify/sources/habit-status-updated/test-event.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export default {
"status": "completed",
"progress": {
"current_value": 8,
"target_value": 8,
"unit_type": "rep",
"periodicity": "daily",
"reference_date": "2025-12-10T00:00:00.000Z"
}
}
Original file line number Diff line number Diff line change
@@ -1,23 +1,14 @@
import habitify from "../../app/habitify.app.mjs";
import { DEFAULT_POLLING_SOURCE_TIMER_INTERVAL } from "@pipedream/platform";
import common from "../common/base-polling.mjs";
import sampleEmit from "./test-event.mjs";

export default {
...common,
name: "New Habit Created",
version: "0.0.1",
version: "0.0.2",
key: "habitify-new-habit-created",
description: "Emit new event on each created habit.",
description: "Emit new event on each created habit. [See the documentation](https://docs.habitify.me/core-resources/habits#list-habits)",
type: "source",
dedupe: "unique",
props: {
habitify,
db: "$.service.db",
timer: {
type: "$.interface.timer",
static: {
intervalSeconds: DEFAULT_POLLING_SOURCE_TIMER_INTERVAL,
},
},
},
methods: {
emitEvent(data) {
this.$emit(data, {
Expand All @@ -32,4 +23,5 @@ export default {

habits.reverse().forEach(this.emitEvent);
},
sampleEmit,
};
29 changes: 29 additions & 0 deletions components/habitify/sources/new-habit-created/test-event.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
export default {
"id": "C0D4CD24-EF3E-4EAB-9D88-17BBDE801FC1",
"name": "Drink Water",
"is_archived": false,
"start_date": "2025-12-10T19:57:16.566Z",
"time_of_day": [
"any_time"
],
"goal": {
"unit_type": "rep",
"value": 8,
"periodicity": "daily"
},
"goal_history_items": [
{
"unit_type": "rep",
"value": 8,
"periodicity": "daily"
}
],
"log_method": "manual",
"recurrence": "DTSTART:20251210T195716Z\nRRULE:FREQ=DAILY",
"remind": [
"6:30"
],
"area": null,
"created_date": "2025-12-10T19:57:16.566Z",
"priority": 0
}
Loading
Loading