diff --git a/app/src/js/render-aurora-component.js b/app/src/js/render-aurora-component.js index 36325340..623ad87d 100644 --- a/app/src/js/render-aurora-component.js +++ b/app/src/js/render-aurora-component.js @@ -48,6 +48,16 @@ export default function renderAuroraComponent( }) } + // TODO: now! + // TODO: if onFetch, then set new values here, send generic fetch request to get skill -> widget id? + // TODO: need to create a standard on_fetch skill action that will be executed? + /*if (component.props.onFetch) { + console.log('component', component) + if (component.props.initialTime) { + component.props.initialTime = 0 + } + }*/ + return createElement(reactComponent, component.props) } } diff --git a/core/skills-endpoints.json b/core/skills-endpoints.json index e84e0859..08ff1669 100644 --- a/core/skills-endpoints.json +++ b/core/skills-endpoints.json @@ -52,6 +52,64 @@ "route": "/api/action/games/rochambeau/rematch", "params": [] }, + { + "method": "POST", + "route": "/api/action/news/github_trends/run", + "params": ["number", "daterange"], + "entitiesType": "builtIn" + }, + { + "method": "GET", + "route": "/api/action/news/product_hunt_trends/run", + "params": [] + }, + { + "method": "POST", + "route": "/api/action/productivity/todo_list/create_list", + "params": ["list"], + "entitiesType": "trim" + }, + { + "method": "GET", + "route": "/api/action/productivity/todo_list/view_lists", + "params": [] + }, + { + "method": "POST", + "route": "/api/action/productivity/todo_list/view_list", + "params": ["list"], + "entitiesType": "trim" + }, + { + "method": "POST", + "route": "/api/action/productivity/todo_list/rename_list", + "params": ["old_list", "new_list"], + "entitiesType": "trim" + }, + { + "method": "POST", + "route": "/api/action/productivity/todo_list/delete_list", + "params": ["list"], + "entitiesType": "trim" + }, + { + "method": "POST", + "route": "/api/action/productivity/todo_list/add_todos", + "params": ["todos", "list"], + "entitiesType": "trim" + }, + { + "method": "POST", + "route": "/api/action/productivity/todo_list/complete_todos", + "params": ["todos", "list"], + "entitiesType": "trim" + }, + { + "method": "POST", + "route": "/api/action/productivity/todo_list/uncheck_todos", + "params": ["todos", "list"], + "entitiesType": "trim" + }, { "method": "GET", "route": "/api/action/leon/age/run", @@ -127,89 +185,6 @@ "route": "/api/action/leon/thanks/run", "params": [] }, - { - "method": "POST", - "route": "/api/action/news/github_trends/run", - "params": ["number", "daterange"], - "entitiesType": "builtIn" - }, - { - "method": "GET", - "route": "/api/action/news/product_hunt_trends/run", - "params": [] - }, - { - "method": "POST", - "route": "/api/action/productivity/todo_list/create_list", - "params": ["list"], - "entitiesType": "trim" - }, - { - "method": "GET", - "route": "/api/action/productivity/todo_list/view_lists", - "params": [] - }, - { - "method": "POST", - "route": "/api/action/productivity/todo_list/view_list", - "params": ["list"], - "entitiesType": "trim" - }, - { - "method": "POST", - "route": "/api/action/productivity/todo_list/rename_list", - "params": ["old_list", "new_list"], - "entitiesType": "trim" - }, - { - "method": "POST", - "route": "/api/action/productivity/todo_list/delete_list", - "params": ["list"], - "entitiesType": "trim" - }, - { - "method": "POST", - "route": "/api/action/productivity/todo_list/add_todos", - "params": ["todos", "list"], - "entitiesType": "trim" - }, - { - "method": "POST", - "route": "/api/action/productivity/todo_list/complete_todos", - "params": ["todos", "list"], - "entitiesType": "trim" - }, - { - "method": "POST", - "route": "/api/action/productivity/todo_list/uncheck_todos", - "params": ["todos", "list"], - "entitiesType": "trim" - }, - { - "method": "GET", - "route": "/api/action/social_communication/conversation/setup", - "params": [] - }, - { - "method": "GET", - "route": "/api/action/social_communication/conversation/chit_chat", - "params": [] - }, - { - "method": "GET", - "route": "/api/action/social_communication/conversation/converse", - "params": [] - }, - { - "method": "GET", - "route": "/api/action/social_communication/mbti/setup", - "params": [] - }, - { - "method": "GET", - "route": "/api/action/social_communication/mbti/quiz", - "params": [] - }, { "method": "GET", "route": "/api/action/unknown/widget-playground/run", @@ -305,6 +280,31 @@ "method": "GET", "route": "/api/action/utilities/translator-poc/translate", "params": [] + }, + { + "method": "GET", + "route": "/api/action/social_communication/conversation/setup", + "params": [] + }, + { + "method": "GET", + "route": "/api/action/social_communication/conversation/chit_chat", + "params": [] + }, + { + "method": "GET", + "route": "/api/action/social_communication/conversation/converse", + "params": [] + }, + { + "method": "GET", + "route": "/api/action/social_communication/mbti/setup", + "params": [] + }, + { + "method": "GET", + "route": "/api/action/social_communication/mbti/quiz", + "params": [] } ] } diff --git a/server/src/core/socket-server.ts b/server/src/core/socket-server.ts index b291eeef..5cf1a2d9 100644 --- a/server/src/core/socket-server.ts +++ b/server/src/core/socket-server.ts @@ -197,6 +197,7 @@ export default class SocketServer { } else if (method.methodName === 'run_skill_action') { this.socket?.emit('widget-run-skill-action', method.methodParams) } else if (method.methodName === 'fetch_widget_data') { + console.log('method.methodParams', method.methodParams) // TODO: get memory from domain:skill:action // TODO: grab new data from the widget. E.g. initialTime // TODO: get memory timestamp of the timer creation + initialTime diff --git a/skills/utilities/timer/config/en.json b/skills/utilities/timer/config/en.json index 563ff94d..23a0815b 100644 --- a/skills/utilities/timer/config/en.json +++ b/skills/utilities/timer/config/en.json @@ -58,7 +58,8 @@ "unit_not_supported": [ "Sorry, I can't set a timer for this unit. Use %hours%, %minutes% or %seconds% instead.", "I can't set a timer for this duration. Use %hours%, %minutes% or %seconds% instead." - ] + ], + "no_timer_set": ["No timer is set.", "There is no timer set."] }, "widget_contents": { "second_unit": "second", diff --git a/skills/utilities/timer/src/actions/check_timer.ts b/skills/utilities/timer/src/actions/check_timer.ts new file mode 100644 index 00000000..3b191a8e --- /dev/null +++ b/skills/utilities/timer/src/actions/check_timer.ts @@ -0,0 +1,31 @@ +import type { ActionFunction } from '@sdk/types' +import { leon } from '@sdk/leon' + +import { TimerWidget } from '../widgets/timer-widget' +import { getNewestTimerMemory } from '../lib/memory' + +export const run: ActionFunction = async function () { + const timerMemory = await getNewestTimerMemory() + + if (!timerMemory) { + return await leon.answer({ key: 'no_timer_set' }) + } + + const { widgetId, interval, finishedAt, duration } = timerMemory + const remainingTime = finishedAt - Math.floor(Date.now() / 1_000) + + if (remainingTime <= 0) { + return await leon.answer({ key: 'no_timer_set' }) + } + + const timerWidget = new TimerWidget({ + params: { + id: widgetId, + seconds: remainingTime, + initialDuration: duration, + interval + } + }) + + await leon.answer({ widget: timerWidget }) +} diff --git a/skills/utilities/timer/src/actions/set_timer.ts b/skills/utilities/timer/src/actions/set_timer.ts index 91054b50..516f3d6d 100644 --- a/skills/utilities/timer/src/actions/set_timer.ts +++ b/skills/utilities/timer/src/actions/set_timer.ts @@ -1,9 +1,8 @@ import type { ActionFunction, BuiltInDurationEntity } from '@sdk/types' import { leon } from '@sdk/leon' -import { Memory } from '@sdk/memory' -import { TimerWidget } from '../widgets/timer' -import { createTimerMemory } from '@@/skills/utilities/timer/src/lib/memory' +import { TimerWidget } from '../widgets/timer-widget' +import { createTimerMemory } from '../lib/memory' export const run: ActionFunction = async function (params) { const supportedUnits = ['hours', 'minutes', 'seconds'] @@ -23,14 +22,15 @@ export const run: ActionFunction = async function (params) { const { value: durationValue } = duration const seconds = Number(durationValue) - + const interval = 1_000 const timerWidget = new TimerWidget({ params: { - seconds + seconds, + interval } }) - await createTimerMemory(timerWidget.id, seconds) + await createTimerMemory(timerWidget.id, seconds, interval) // TODO: return a speech without new utterance /*await leon.answer({ diff --git a/skills/utilities/timer/src/lib/memory.ts b/skills/utilities/timer/src/lib/memory.ts index 72eb80c4..290e9e28 100644 --- a/skills/utilities/timer/src/lib/memory.ts +++ b/skills/utilities/timer/src/lib/memory.ts @@ -3,6 +3,7 @@ import { Memory } from '@sdk/memory' export interface TimerMemory { widgetId: string duration: number + interval: number createdAt: number finishedAt: number } @@ -14,13 +15,16 @@ const TIMERS_MEMORY = new Memory({ export async function createTimerMemory( widgetId: string, - duration: number + duration: number, + interval: number ): Promise { + const createdAt = Math.floor(Date.now() / 1_000) const newTimerMemory: TimerMemory = { duration, widgetId, - createdAt: Date.now(), - finishedAt: Date.now() + duration + interval, + createdAt, + finishedAt: createdAt + duration } const timersMemory = await TIMERS_MEMORY.read() @@ -28,3 +32,9 @@ export async function createTimerMemory( return newTimerMemory } + +export async function getNewestTimerMemory(): Promise { + const timersMemory = await TIMERS_MEMORY.read() + + return timersMemory[timersMemory.length - 1] || null +} diff --git a/skills/utilities/timer/src/widgets/timer.ts b/skills/utilities/timer/src/widgets/timer-widget.ts similarity index 81% rename from skills/utilities/timer/src/widgets/timer.ts rename to skills/utilities/timer/src/widgets/timer-widget.ts index bde0f087..5a14124f 100644 --- a/skills/utilities/timer/src/widgets/timer.ts +++ b/skills/utilities/timer/src/widgets/timer-widget.ts @@ -5,11 +5,18 @@ import { Timer } from './components/timer' interface Params { seconds: number + interval: number + initialDuration?: number + id?: string } export class TimerWidget extends Widget { constructor(options: WidgetOptions) { super(options) + + if (options.params.id) { + this.id = options.params.id + } } /** @@ -25,15 +32,16 @@ export class TimerWidget extends Widget { // TODO: content... public render(): WidgetComponent { - const { seconds } = this.params + const { seconds, interval, initialDuration } = this.params const secondUnitContent = this.content('second_unit') const secondsUnitContent = this.content('seconds_unit') const minuteUnitContent = this.content('minute_unit') const minutesUnitContent = this.content('minutes_unit') + const totalTime = initialDuration || seconds let totalTimeContent = '' - if (seconds >= 60) { - const minutes = seconds / 60 + if (totalTime >= 60) { + const minutes = totalTime / 60 totalTimeContent = this.content('total_time', { value: minutes % 1 === 0 ? minutes : minutes.toFixed(2), @@ -41,14 +49,14 @@ export class TimerWidget extends Widget { }) } else { totalTimeContent = this.content('total_time', { - value: seconds, - unit: seconds > 1 ? secondsUnitContent : secondUnitContent + value: totalTime, + unit: totalTime > 1 ? secondsUnitContent : secondUnitContent }) } return new Timer({ initialTime: seconds, - interval: 1_000, + interval, totalTimeContent, onFetch: (): WidgetEventMethod => { return this.fetchWidgetData(['initialTime']) @@ -60,6 +68,4 @@ export class TimerWidget extends Widget { } }) } - - public fetch(dataToSet: string[]): WidgetEventMethod {} }