Skip to content

Front/pd 284 events v2#25

Open
Ricardoaar wants to merge 8 commits intomainfrom
front/PD-284_events_v2
Open

Front/pd 284 events v2#25
Ricardoaar wants to merge 8 commits intomainfrom
front/PD-284_events_v2

Conversation

@Ricardoaar
Copy link
Copy Markdown

@Ricardoaar Ricardoaar commented Jan 22, 2026

Pull Request

📝 Descripción

Se agrego soporte para todos los events de V2

Se agregó un Event Emitter Panel interactivo para facilitar el testing de eventos de widgets en los ejemplos de desarrollo. Además, se crearon dos nuevos ejemplos completos que demuestran el uso de eventos de widgets.

Cambios principales:

  1. Soporte completo para eventos V2 - Implementación de todos los eventos con formato v2:*
  2. EventEmitterPanel Component - Panel lateral con 24 eventos organizados en 8 categorías (V1 y V2)
  3. Widget Events Basic - Ejemplo básico de eventos de widget con monitor en tiempo real
  4. Widget Events Multi - Ejemplo avanzado con múltiples widgets y monitor global
  5. Correcciones de ESLint - Todos los archivos ahora pasan lint sin errores

🔗 Issues Relacionados

https://app.clickup.com/t/9013371168/PD-284

🧪 Tipo de Cambio

  • 🐛 Bug fix
  • ✨ Nueva funcionalidad
  • 💥 Breaking change
  • 📚 Documentación
  • 🔧 Refactoring
  • ⚡ Mejora de performance
  • 🧹 Limpieza de código

🧪 Testing

  • Tests pasan (pnpm test)
  • Lint pasa (pnpm lint)
  • Type check pasa (pnpm typecheck)
  • Build funciona (pnpm build)
  • Probado manualmente

Cómo probar

  1. Ejecutar pnpm dev:examples
  2. Abrir http://localhost:3000
  3. Selecciona un evento
  4. Usar el panel lateral para emitir eventos
  5. Verificar que el monitor muestra los eventos recibidos

📸 Screenshots

✅ Checklist

  • El código sigue las convenciones del proyecto
  • Revisé mi propio código
  • Agregué comentarios donde era necesario
  • No hay nuevos warnings ni errores
  • Agregué/actualicé tests
  • Actualicé la documentación si era necesario

📋 Notas Adicionales

Archivos nuevos:

  • examples/shared/EventEmitterPanel.jsx - Componente reutilizable del panel
  • examples/shared/EventEmitterPanel.css - Estilos del panel
  • examples/widget-events-basic/WidgetEventsBasic.jsx - Ejemplo básico
  • examples/widget-events-basic/WidgetEventsBasic.css - Estilos del ejemplo básico
  • examples/widget-events-multi/WidgetEventsMulti.jsx - Ejemplo multi-widget
  • examples/widget-events-multi/WidgetEventsMulti.css - Estilos del ejemplo multi

Archivos modificados:

  • examples/dev/main.jsx - Agregados nuevos ejemplos al router + correcciones ESLint
  • examples/event-versioning/EventVersioningExample.jsx - Correcciones ESLint

Eventos V2 implementados:

Autenticación:

  • v2:auth:token - Token de autenticación V2
  • v2:auth:jwt - JWT token V2

Dashboard:

  • v2:dashboard:self - Información del dashboard
  • v2:dashboard:devices:self - Device propio
  • v2:dashboard:devices:selected - Devices seleccionados
  • v2:dashboard:settings:daterange - Rango de fechas
  • v2:dashboard:settings:rt - Estado de real-time
  • v2:dashboard:settings:filters - Filtros aplicados
  • v2:dashboard:settings:refreshed - Dashboard refrescado

Widget:

  • v2:widget:ready:${widgetId} - Widget listo
  • v2:widget:loaded:${widgetId} - Widget cargado
  • v2:widget:error:${widgetId} - Error en widget
  • v2:widget:customAction:${widgetId} - Acción personalizada

Características del EventEmitterPanel:

  • ✅ 24 eventos totales organizados en 8 categorías
  • Soporte completo para eventos V1 y V2 - Incluye ambas versiones del sistema de eventos
  • ✅ Widget ID dinámico (detecta automáticamente el widgetId del contexto)
  • ✅ Formato correcto de mensajes: { event, payload }
  • ✅ Payloads realistas para cada tipo de evento
  • ✅ Feedback visual del último evento emitido
  • ✅ Panel colapsable/expandible
  • ✅ Responsive y accesible (keyboard navigation, ARIA labels)
  • ✅ Console logs para debugging

Compatibilidad:

  • ✅ Mantiene soporte completo para eventos V1 (legacy)
  • ✅ Implementa todos los eventos V2 con el formato correcto
  • ✅ Permite testing de ambas versiones simultáneamente

Todos los archivos pasan pnpm lint sin errores ni warnings.

Summary by CodeRabbit

  • New Features

    • Event versioning with V1 and V2 support, ensuring backward compatibility
    • Widget-scoped events (v2:widget namespace) for isolated multi-widget communication
    • Three new interactive examples: Event Versioning, Widget Events - Basic, and Widget Events - Multi
  • Documentation

    • Event versioning guide detailing V1/V2 event mapping and migration patterns
    • Widget events documentation for multi-widget integration scenarios
    • Local example running guide with interactive gallery interface
  • Chores

    • Added development script for running examples locally

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Jan 22, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR introduces V2 event versioning and widget-scoped event communication to the Ubidots React library. Changes include new event constants and handlers, state management for widgetId, hook updates to support widget-specific messaging, comprehensive examples demonstrating the new patterns, and updated types and tests. V1 event compatibility is maintained through dual-emission handlers.

Changes

Cohort / File(s) Summary
Documentation
README.md, docs/EventVersioning.md
Added EventVersioning.md documenting V1/V2 event mapping, flows, and migration notes. Updated README with "Running Examples Locally" section and references to new examples (Event Versioning, Widget Events - Basic, Widget Events - Multi).
Examples Infrastructure
examples/dev/index.html, examples/dev/main.jsx, package.json
Added example gallery framework: static HTML with gradient UI grid, main.jsx entry point with dynamic example routing and fallback gallery component. Added dev:examples npm script for separate Vite build.
Event Versioning Example
examples/event-versioning/EventVersioningExample.jsx
New example demonstrating V1 and V2 event compatibility with EventLogger component subscribed to window messages and WidgetContent dispatching both event versions via UbidotsProvider.
Widget Events - Basic Example
examples/widget-events-basic/README.md, examples/widget-events-basic/WidgetEventsBasic.jsx, examples/widget-events-basic/styles.css
Documentation and component for v2:widget-scoped events with EventMonitor and WidgetContent displaying widget status, emitting lifecycle events (loaded, ready, error, settingsChanged, customAction).
Widget Events - Multi Example
examples/widget-events-multi/README.md, examples/widget-events-multi/WidgetEventsMulti.jsx, examples/widget-events-multi/styles.css
Documentation and component demonstrating multi-widget isolation via v2:widget:<widgetId>:<event> namespace with GlobalEventMonitor, Widget-to-widget messaging, and cross-widget communication patterns.
Event Emitter Panel (Shared)
examples/shared/EventEmitterPanel.jsx, examples/shared/EventEmitterPanel.css
New reusable collapsible panel component showcasing categorized event-emit actions across System, Authentication, Device Selection, Date & Time, Dashboard Objects, and Widget Events categories with payload templates.
Context: State & Constants
src/context/UbidotsReducer.ts, src/context/constants.ts, src/types/index.ts
Added widgetId to UbidotsState and SET_WIDGET_ID reducer handler. Introduced INBOUND_EVENTS_V2 and OUTBOUND_EVENTS_V2 with namespaced event keys. Added ReadyEventV1/V2 union types and SET_WIDGET_ID action type.
Context: Message Handling
src/context/messageHandlers.ts, src/context/actions.ts, src/context/ubidots.tsx
Extended action creators to emit both V1 and V2 events via postMessageWithV2 helper. Updated messageHandlers to emit V2 events when receiving V1 and handle direct V2 inbound events. Modified UbidotsProvider to accept widgetId prop and dispatch SET_WIDGET_ID action.
Hooks
src/hooks/useWidgetEvents.ts, src/hooks/useUbidotsSelections.ts, src/hooks/index.ts
Added useWidgetEvents hook for widget-scoped v2:widget event emission and listening with event filtering and wildcard support. Added useUbidotsWidgetId hook. Updated index.ts to re-export useWidgetEvents.
Tests: Context
src/context/__tests__/UbidotsReducer.test.ts, src/context/__tests__/actions.test.ts, src/context/__tests__/messageHandlers.test.ts
Added SET_WIDGET_ID reducer tests, comprehensive action creator tests verifying V1 and V2 event emissions with correct payload transformations, and V2 message handler tests for both emission from V1 handlers and direct V2 event routing.
Tests: Hooks
src/hooks/__tests__/useWidgetEvents.test.tsx, src/hooks/__tests__/useUbidotsSelections.test.tsx, src/hooks/__tests__/useUbidotsActions.test.tsx
Added full useWidgetEvents test suite covering emission formatting, listener registration, wildcard subscriptions, and ready event lifecycle. Added useUbidotsWidgetId tests. Updated openDrawer test to source widgetId from UbidotsProvider.

Sequence Diagrams

sequenceDiagram
    participant Widget as Widget/App
    participant Provider as UbidotsProvider
    participant Reducer as State Reducer
    participant Handler as Message Handler
    participant Parent as Parent Window

    Widget->>Provider: Action (e.g., setDashboardDevice)
    Provider->>Handler: Call action creator
    Handler->>Parent: postMessage V1 event
    Handler->>Parent: postMessage V2 event
    Parent-->>Parent: Receive V1 message
    Parent->>Handler: Trigger V1 handler
    Handler->>Parent: postMessage V2 event
    Handler->>Reducer: Dispatch Redux action
    Reducer->>Provider: Update state
Loading
sequenceDiagram
    participant Widget as Widget A
    participant Events as useWidgetEvents
    participant Listener as Message Listener
    participant Parent as Parent Window
    participant Widget2 as Widget B

    Widget->>Events: Call emitWidgetEvent('customAction')
    Events->>Parent: postMessage {event: 'v2:widget:widgetA:customAction', payload}
    Widget2->>Events: onWidgetEvent('v2:widget:widgetA:*')
    Events->>Listener: Register wildcard listener
    Parent-->>Parent: Broadcast to all widgets
    Listener->>Listener: Match v2:widget:widgetA:* pattern
    Listener->>Events: Invoke callback
    Events->>Widget2: Callback fired with event & payload
Loading
sequenceDiagram
    participant Client as Client Window
    participant Provider as UbidotsProvider
    participant Handlers as Message Handlers
    participant Parent as Parent Frame

    Parent->>Client: postMessage V2 event (INBOUND_EVENTS_V2.TOKEN)
    Client->>Handlers: handleInboundMessage (V2)
    Handlers->>Handlers: Map V2 → Redux action type
    Handlers->>Provider: dispatch(RECEIVED_TOKEN)
    Provider->>Provider: Update state.token
    Handlers->>Client: satisfiedEventsRef.add('v2:auth:token')
    Handlers->>Parent: postMessage V2 event (for compatibility)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Poem

🐰 Hops through the version gates, V1 and V2 aligned,
Widget events dancing in their scoped confines,
Messages flutter parent-ward, backward-compatible and fine,
Context flows with widgetId, examples brightly shine!

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 18.18% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The PR title is vague and generic, using 'Front/pd 284 events v2' which references a ticket ID but does not clearly summarize the primary changes. Use a clearer, more descriptive title such as 'Add V2 event support with EventEmitterPanel and widget examples' that conveys the main feature additions without relying solely on ticket references.
✅ Passed checks (1 passed)
Check name Status Explanation
Description check ✅ Passed The PR description is comprehensive and well-structured, covering objectives, changes, testing status, and implementation details in both Spanish and organized sections.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch front/PD-284_events_v2

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Copy Markdown

🔍 PR Quality Check Summary

Check Status
Code Quality & Tests ❌ failure
Security Audit ✅ success

📋 Checks Performed:

  • ✅ TypeScript compilation
  • ✅ ESLint code quality
  • ✅ Prettier code formatting
  • ✅ Unit tests with coverage (80%+ required)
  • ✅ Build verification
  • ✅ Security audit

⚠️ Some checks failed. Please review the details above.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/context/messageHandlers.ts (1)

171-244: V2 handlers add only V1 event names to satisfiedEventsRef, breaking readiness checks when V2 event names are used in readyEvents configuration.

The V2 handlers (lines 173–244) all add V1 event names ('receivedToken', 'selectedDevices', etc.) to satisfiedEventsRef, but the ReadyEvent type explicitly allows V2 event names like 'v2:auth:token'. When a consumer configures readyEvents with V2 names, those events will never be satisfied because the handlers only track V1 names. The checkReadyState function checks whether each event in readyEvents exists in satisfiedEventsRef (line 291–293), so this mismatch causes readiness to never be reached.

Add the corresponding V2 event name to satisfiedEventsRef in each V2 handler to support V2-only configurations:

[INBOUND_EVENTS_V2.TOKEN]: (payload, dispatch, satisfiedEventsRef) => {
  dispatch({ type: ACTION_TYPES.RECEIVED_TOKEN, payload: payload as string });
  satisfiedEventsRef.current.add('receivedToken');
  satisfiedEventsRef.current.add('v2:auth:token');
},

Apply the same pattern to all other V2 handlers.

🤖 Fix all issues with AI agents
In `@examples/dev/main.jsx`:
- Around line 5-12: The imports in main.jsx are using default imports but the
example files mostly export named components; update the import statements so
they use named imports matching the actual exports: replace default imports for
BasicUsage, CompleteWidget, WidgetEventsBasic, WidgetEventsMulti, and
WithHocsExample with named imports (e.g., { BasicUsage }, { CompleteWidget }, {
WidgetEventsBasic }, { WidgetEventsMulti }, { WithHocsExample }), and fix the
two misnamed imports by changing DeviceSelector to import {
DeviceSelectorExample } and RealTimeDashboard to import {
RealTimeDashboardExample } while keeping EventVersioningExample as the default
import since it exports default.

In `@examples/shared/EventEmitterPanel.jsx`:
- Around line 8-12: The WidgetEventsBasic component uses the wrong fallback
widgetId ('widget-demo-001') which mismatches EventEmitterPanel.jsx and the
README; update the fallback identifier in WidgetEventsBasic (the widgetId
constant/prop default used when window.widgetId is absent and any hardcoded
event strings like `v2:widget:ready:${widgetId}` or listener suffixes) to
'demo-widget-001' so emitted events and the event monitor/readme examples align
with EventEmitterPanel and documentation.
- Around line 13-17: The emitEvent function currently calls
window.parent.postMessage(message, '*') which weakens origin isolation; update
the EventEmitterPanel component to accept a targetOrigin prop (or add a required
prop) and replace the '*' with that prop when calling postMessage in emitEvent,
providing a sensible default (e.g., a deployment-specific origin or
throw/console.error if missing) and ensure the prop is validated/documented so
callers pass the explicit parent origin (e.g., when rendering <EventEmitterPanel
targetOrigin="https://trusted-parent.example.com" />).

In `@examples/widget-events-multi/README.md`:
- Around line 185-188: Update the README examples run command block that
currently shows "pnpm install" followed by "pnpm dev" to instead use "pnpm
dev:examples" so the docs launch the dedicated Vite-configured examples app;
locate the fenced bash code block containing those two commands and replace the
second line accordingly.

In `@src/context/messageHandlers.ts`:
- Around line 18-22: emitV2Event currently calls window.parent.postMessage with
'*' which leaks sensitive data to any parent; update emitV2Event (and the
postMessage usage in actions.ts) to accept or resolve a specific targetOrigin
instead of '*'—use the parent origin (e.g., window.parent.location.origin) as a
sensible default or read a configured outboundOrigin injected into the provider,
and wire this to the existing validateOrigin callback so outbound messages are
only sent to validated origins; change emitV2Event signature to accept an
optional targetOrigin or use the provider's configured outboundOrigin, and use
that value in postMessage calls.

In `@src/hooks/useWidgetEvents.ts`:
- Around line 52-65: onWidgetEvent currently stores listeners under the raw
event key (e.g., "ready") but incoming events use the full "v2:widget:...:ready"
format, so listeners never match; update onWidgetEvent to normalize the event
name to the same canonical form used by emitWidgetEvent (or accept both forms)
before storing/removing the callback, and emit a console/process warning if a
required widgetId is missing when resolving to the full "v2:widget:..." name;
look for listenersRef and onWidgetEvent in the file and ensure the same
normalization/matching logic is used when emitting in emitWidgetEvent so
callbacks registered via onWidgetEvent('ready', cb) will be invoked.

In `@vite.examples.config.ts`:
- Around line 4-18: The config currently uses __dirname (in the alias
path.resolve(__dirname, './src/index.ts')) which breaks in ESM; replace usage by
deriving a directory from import.meta.url (e.g., use fileURLToPath and
path.dirname on new URL(import.meta.url)) and pass that computed dirname into
path.resolve for the alias; update the top of the file to import or require the
helper (fileURLToPath) and compute const __dirname =
path.dirname(fileURLToPath(new URL(import.meta.url))) before calling
defineConfig so that the alias resolution in resolve.alias uses the correct
ESM-compatible directory.
🧹 Nitpick comments (4)
src/context/UbidotsReducer.ts (1)

95-96: Consider removing the unnecessary intermediate variable.

The intermediate variable r adds no value and slightly reduces readability. A direct return would be cleaner and consistent with typical reducer patterns.

♻️ Suggested simplification
-  const r = handler ? handler(state, action) : state;
-  return r;
+  return handler ? handler(state, action) : state;
examples/widget-events-basic/README.md (1)

16-18: Add language specifier to fenced code block.

The linter flags this code block as missing a language specifier. Since this shows a text pattern rather than executable code, consider using text or plaintext.

♻️ Suggested fix
-```
+```text
 v2:widget:<eventType>:<widgetId>
src/context/ubidots.tsx (1)

71-77: Consider cleanup for window.widgetId on unmount or prop change.

When widgetId changes to a falsy value or the component unmounts, window.widgetId remains set with the stale value. This could cause subtle bugs if multiple widgets or provider instances are used.

♻️ Suggested cleanup
  // Set widgetId on window and in state
  useEffect(() => {
    if (widgetId) {
      (window as unknown as Record<string, unknown>).widgetId = widgetId;
      dispatch({ type: ACTION_TYPES.SET_WIDGET_ID, payload: widgetId });
+     return () => {
+       (window as unknown as Record<string, unknown>).widgetId = undefined;
+     };
    }
  }, [widgetId]);
src/context/constants.ts (1)

50-59: Consider deduplicating the shared V2 selected-devices event string.
SET_DASHBOARD_DEVICE and SET_DASHBOARD_MULTIPLE_DEVICES point to the same literal; a shared constant makes the intent explicit and prevents drift.

♻️ Suggested tweak
+const DASHBOARD_DEVICES_SELECTED_V2 = 'v2:dashboard:devices:selected';
+
 export const OUTBOUND_EVENTS_V2 = {
   // Dashboard Events
-  SET_DASHBOARD_DEVICE: 'v2:dashboard:devices:selected',
-  SET_DASHBOARD_MULTIPLE_DEVICES: 'v2:dashboard:devices:selected',
+  SET_DASHBOARD_DEVICE: DASHBOARD_DEVICES_SELECTED_V2,
+  SET_DASHBOARD_MULTIPLE_DEVICES: DASHBOARD_DEVICES_SELECTED_V2,
   SET_DASHBOARD_DATE_RANGE: 'v2:dashboard:settings:daterange',
   SET_REAL_TIME: 'v2:dashboard:settings:rt',
   REFRESH_DASHBOARD: 'v2:dashboard:settings:refreshed',
   SET_FULL_SCREEN: 'v2:dashboard:settings:fullscreen',
   OPEN_DRAWER: 'v2:dashboard:drawer:open',
 } as const;

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds V2 (v2:*) event support to the library (including widget-scoped v2:widget:* events) and expands the examples app with an interactive Event Emitter panel plus new event-focused demos.

Changes:

  • Add V2 inbound/outbound event constants and update handlers/actions to emit V1+V2 for backward compatibility.
  • Introduce widget event support via useWidgetEvents and plumb widgetId through provider/state.
  • Add an examples gallery (new Vite config + dev entrypoint) and multiple new/updated examples + docs.

Reviewed changes

Copilot reviewed 30 out of 30 changed files in this pull request and generated 14 comments.

Show a summary per file
File Description
vite.examples.config.ts Adds a dedicated Vite config for running the examples gallery.
src/types/index.ts Extends ready event types to include V2 events and adds widgetId to state/actions.
src/hooks/useWidgetEvents.ts New hook for emitting/listening to v2:widget:<event>:<widgetId> messages.
src/hooks/useUbidotsSelections.ts Adds useUbidotsWidgetId selector hook.
src/hooks/index.ts Re-exports the new useWidgetEvents hook.
src/context/ubidots.tsx Adds widgetId prop and writes it into context state (and a window global).
src/context/messageHandlers.ts Adds V2 inbound support and V1→V2 “shadow emission” for inbound events.
src/context/constants.ts Adds V2 inbound/outbound event constant maps and new action type.
src/context/actions.ts Updates outbound actions to emit both V1 and V2 events.
src/context/UbidotsReducer.ts Adds SET_WIDGET_ID reducer handling.
package.json Adds dev:examples script to run examples via the new Vite config.
examples/shared/EventEmitterPanel.jsx New interactive panel to emit V1/V2/widget events for manual testing.
examples/shared/EventEmitterPanel.css Styles for the EventEmitterPanel UI.
examples/dev/index.html New examples gallery HTML entrypoint.
examples/dev/main.jsx New examples gallery/router to render selected demos via query param.
examples/widget-events-basic/WidgetEventsBasic.jsx New single-widget event example with live monitor.
examples/widget-events-basic/styles.css Styles for widget-events-basic example.
examples/widget-events-basic/README.md Documentation for widget-events-basic example.
examples/widget-events-multi/WidgetEventsMulti.jsx New multi-widget isolated-events example with global monitor.
examples/widget-events-multi/styles.css Styles for widget-events-multi example.
examples/widget-events-multi/README.md Documentation for widget-events-multi example.
examples/event-versioning/EventVersioningExample.jsx Updates/creates event versioning example and integrates the emitter panel.
examples/basic-usage/BasicUsage.jsx Integrates the emitter panel into the basic usage example.
examples/device-selector/DeviceSelector.jsx Integrates the emitter panel into the device selector example.
examples/real-time-dashboard/RealTimeDashboard.jsx Integrates the emitter panel into the real-time dashboard example.
examples/complete-widget/CompleteWidget.jsx Integrates the emitter panel into the complete widget example.
examples/with-hocs/WithHocsExample.jsx Integrates the emitter panel into the HOCs example.
examples/README.md Adds new example entries for event-versioning and widget-events demos.
docs/EventVersioning.md Adds a guide describing V1/V2 compatibility and mapping.
README.md Updates main README with local examples running instructions and links.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@github-actions
Copy link
Copy Markdown

🔍 PR Quality Check Summary

Check Status
Code Quality & Tests ❌ failure
Security Audit ✅ success

📋 Checks Performed:

  • ✅ TypeScript compilation
  • ✅ ESLint code quality
  • ✅ Prettier code formatting
  • ✅ Unit tests with coverage (80%+ required)
  • ✅ Build verification
  • ✅ Security audit

⚠️ Some checks failed. Please review the details above.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@src/context/__tests__/actions.test.ts`:
- Around line 44-47: The TypeScript error comes from accessing properties on
elements of postMessageSpy.mock.calls which are typed as unknown[]; update the
v2Call lookup to assert the call shape (e.g., cast call[0] to a known type) or
introduce a small helper/type (e.g., PostMessageCall and findV2Call) and use
that when searching for OUTBOUND_EVENTS_V2.SET_DASHBOARD_DEVICE so the
expression (call[0] as PostMessageCall).event is valid and the subsequent
expect(v2Call![0].payload) remains type-safe.
- Around line 78-82: The TypeScript compiler cannot infer the tuple type from
postMessageSpy.mock.calls.find, so add a type assertion for v2Call to silence
the error and access payload safely: when locating the call where call[0].event
=== OUTBOUND_EVENTS_V2.SET_DASHBOARD_MULTIPLE_DEVICES, assert the result
(v2Call) to a compatible type (e.g., unknown/any or a typed tuple) before using
v2Call[0].payload so the test compiles; reference the v2Call variable and
OUTBOUND_EVENTS_V2.SET_DASHBOARD_MULTIPLE_DEVICES in your change.
🧹 Nitpick comments (3)
src/hooks/__tests__/useWidgetEvents.test.tsx (3)

85-116: Redundant console.warn spy.

console.warn is already mocked in beforeEach (line 12). Creating another spy here is unnecessary—you can use vi.mocked(console.warn) or simply reference the existing mock directly.

Suggested fix
     it('should warn and not emit when widgetId is not defined', async () => {
       let emitFn: ((event: string, payload?: unknown) => void) | null = null;
-      const consoleWarnSpy = vi.spyOn(console, 'warn');

       function TestComponent() {
         const { emitWidgetEvent } = useWidgetEvents();
         emitFn = emitWidgetEvent;
         return null;
       }

       render(
         <UbidotsProvider>
           <TestComponent />
         </UbidotsProvider>
       );

       await waitFor(() => {
         expect(emitFn).not.toBeNull();
       });

       // Clear any previous calls (like from ready event)
       postMessageSpy.mockClear();

       act(() => {
         emitFn!('some-event', { data: 'test' });
       });

-      expect(consoleWarnSpy).toHaveBeenCalledWith(
+      expect(console.warn).toHaveBeenCalledWith(
         'Cannot emit widget event: widgetId is not defined'
       );
       expect(postMessageSpy).not.toHaveBeenCalled();
     });

354-356: Missing cleanup for registered listener.

Unlike the test above (lines 305-329), this test doesn't store or invoke the cleanup function. While afterEach restores mocks, explicitly cleaning up listeners maintains consistency and prevents potential leaks if the test setup changes.

Suggested fix
+      let cleanup: (() => void) | null = null;
       act(() => {
-        onAnyFn!(callback);
+        cleanup = onAnyFn!(callback);
       });

       // Simulate receiving a non-widget event
       act(() => {
         window.dispatchEvent(
           new MessageEvent('message', {
             data: {
               event: 'receivedToken',
               payload: 'some-token',
             },
           })
         );
       });

       expect(callback).not.toHaveBeenCalled();
+
+      // Cleanup
+      act(() => {
+        cleanup!();
+      });
     });

449-476: Consider extracting duplicated call search logic.

The logic to find the ready event call is repeated twice (lines 451-458 and 461-467). You could extract it into a helper or use the result from waitFor directly.

Suggested simplification
       // Wait for ready event to be emitted
+      const findReadyCall = () =>
+        postMessageSpy.mock.calls.find(
+          call =>
+            call[0] &&
+            typeof call[0] === 'object' &&
+            'event' in call[0] &&
+            call[0].event === 'v2:widget:ready:lifecycle-widget'
+        );
+
       await waitFor(() => {
-        const readyCall = postMessageSpy.mock.calls.find(
-          call =>
-            call[0] &&
-            typeof call[0] === 'object' &&
-            'event' in call[0] &&
-            call[0].event === 'v2:widget:ready:lifecycle-widget'
-        );
-        expect(readyCall).toBeDefined();
+        expect(findReadyCall()).toBeDefined();
       });

-      const readyCall = postMessageSpy.mock.calls.find(
-        call =>
-          call[0] &&
-          typeof call[0] === 'object' &&
-          'event' in call[0] &&
-          call[0].event === 'v2:widget:ready:lifecycle-widget'
-      );
+      const readyCall = findReadyCall();

       expect(readyCall![0]).toMatchObject({

@github-actions
Copy link
Copy Markdown

🔍 PR Quality Check Summary

Check Status
Code Quality & Tests ✅ success
Security Audit ✅ success

📋 Checks Performed:

  • ✅ TypeScript compilation
  • ✅ ESLint code quality
  • ✅ Prettier code formatting
  • ✅ Unit tests with coverage (80%+ required)
  • ✅ Build verification
  • ✅ Security audit

🎉 All checks passed! This PR is ready for review.

@github-actions
Copy link
Copy Markdown

🔍 PR Quality Check Summary

Check Status
Code Quality & Tests ✅ success
Security Audit ❌ failure

📋 Checks Performed:

  • ✅ TypeScript compilation
  • ✅ ESLint code quality
  • ✅ Prettier code formatting
  • ✅ Unit tests with coverage (80%+ required)
  • ✅ Build verification
  • ✅ Security audit

⚠️ Some checks failed. Please review the details above.

@Ricardoaar Ricardoaar force-pushed the front/PD-284_events_v2 branch from fc06f35 to d4b83f0 Compare April 6, 2026 13:55
@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 6, 2026

🔍 PR Quality Check Summary

Check Status
Code Quality & Tests ❌ failure
Security Audit ❌ failure

📋 Checks Performed:

  • ✅ TypeScript compilation
  • ✅ ESLint code quality
  • ✅ Prettier code formatting
  • ✅ Unit tests with coverage (80%+ required)
  • ✅ Build verification
  • ✅ Security audit

⚠️ Some checks failed. Please review the details above.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/context/messageHandlers.ts (1)

38-56: ⚠️ Potential issue | 🟠 Major

Mark both V1 and V2 ready-event aliases when bridging these handlers.

checkReadyState() matches readyEvents by exact string, but this block only records the version it received. So readyEvents={['selectedFilters']} never resolves when the host sends v2:dashboard:settings:filters, and readyEvents={['v2:auth:token']} never resolves when the host still sends receivedToken. Emitting the other version back to window.parent does not satisfy the local set.

💡 Suggested direction
+function markReady(
+  satisfiedEventsRef: React.MutableRefObject<Set<ReadyEvent>>,
+  ...events: ReadyEvent[]
+) {
+  events.forEach(event => satisfiedEventsRef.current.add(event));
+}
+
 const messageHandlers: Record<string, MessageHandler> = {
   [INBOUND_EVENTS.RECEIVED_TOKEN]: (payload, dispatch, satisfiedEventsRef) => {
     dispatch({ type: ACTION_TYPES.RECEIVED_TOKEN, payload: payload as string });
-    satisfiedEventsRef.current.add('receivedToken');
+    markReady(satisfiedEventsRef, 'receivedToken', INBOUND_EVENTS_V2.TOKEN);
     emitV2Event(INBOUND_EVENTS_V2.TOKEN, payload);
   },
@@
   [INBOUND_EVENTS_V2.SELECTED_FILTERS]: (
     payload,
     dispatch,
     satisfiedEventsRef
   ) => {
     dispatch({
       type: ACTION_TYPES.SELECTED_FILTERS,
       payload: payload as FilterValue[] | null,
     });
-    satisfiedEventsRef.current.add(INBOUND_EVENTS_V2.SELECTED_FILTERS);
+    markReady(
+      satisfiedEventsRef,
+      'selectedFilters',
+      INBOUND_EVENTS_V2.SELECTED_FILTERS
+    );
   },

Apply the same alias pairing to each V1/V2 equivalent.

Also applies to: 143-169, 174-249

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/context/messageHandlers.ts` around lines 38 - 56, When handling bridged
events in messageHandlers (e.g., the INBOUND_EVENTS.RECEIVED_TOKEN and
INBOUND_EVENTS.RECEIVED_JWT_TOKEN handlers), record both the V1 and V2
ready-event aliases in satisfiedEventsRef (e.g., call
satisfiedEventsRef.current.add('receivedToken') and also add the corresponding
V2 alias like 'v2:auth:token' or vice‑versa) so checkReadyState() can match
either form; likewise, when you receive a V2 alias add the V1 alias as well.
Also emit the counterpart event back to the host in addition to the existing
emitV2Event (i.e., emit both versions when bridging). Apply this alias-pairing
change consistently to the other bridged handler blocks referenced (around the
other ranges).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/context/__tests__/messageHandlers.test.ts`:
- Line 548: The test assertions like
expect(satisfiedEventsRef.current.has('v2:dashboard:devices:selected')).toBe(true)
are too long for Prettier; reflow them into multi-line assertions so the
formatter can wrap them (e.g., break the expect call and the matcher onto
separate lines). Update the occurrences referencing
satisfiedEventsRef.current.has(...) in this test (and the same pattern at the
other noted locations) to use the wrapped/multi-line format so Prettier passes.

In `@src/context/messageHandlers.ts`:
- Around line 223-225: Prettier is failing due to the broken wrap of the add
call; update the call to a single-line call to satisfiedEventsRef.current.add
with INBOUND_EVENTS_V2.SELECTED_DASHBOARD_OBJECT as the single argument (i.e.,
collapse the multi-line invocation into one line) so the invocation of
satisfiedEventsRef.current.add(INBOUND_EVENTS_V2.SELECTED_DASHBOARD_OBJECT)
conforms to the repo formatter.

In `@src/context/ubidots.tsx`:
- Around line 64-80: The reducer initial state is being set after first render
via an effect, causing state.widgetId to be null initially and not cleared when
the prop is removed; instead set widgetId synchronously when calling useReducer
by merging the prop into the initial state (e.g., pass { ...initialState,
...initialStateOverride, widgetId: widgetId ?? null }) so state.widgetId
reflects the prop on first render, and then simplify the useEffect to only
dispatch if the incoming prop actually differs from stateRef.current.widgetId
(or remove the effect entirely if synchronous init is sufficient); reference
ACTION_TYPES.SET_WIDGET_ID, useReducer/ubidotsReducer, initialStateOverride, and
stateRef to locate the changes.

In `@src/hooks/useWidgetEvents.ts`:
- Around line 72-90: The onAnyWidgetEvent listener in useWidgetEvents.ts (and
the other message handler in the same hook) currently trusts any postMessage
with data.event starting with "v2:widget:"; update these handlers
(onAnyWidgetEvent and the effect that registers the other message listener) to
validate the message origin before calling callbacks by either calling the
provider's validateOrigin function (thread it into useWidgetEvents via
props/context and use it to accept/reject events) or at minimum checking
ev.source === window.parent (and comparing ev.origin if available) so only
trusted frames trigger onWidgetEvent/onAnyWidgetEvent.

---

Outside diff comments:
In `@src/context/messageHandlers.ts`:
- Around line 38-56: When handling bridged events in messageHandlers (e.g., the
INBOUND_EVENTS.RECEIVED_TOKEN and INBOUND_EVENTS.RECEIVED_JWT_TOKEN handlers),
record both the V1 and V2 ready-event aliases in satisfiedEventsRef (e.g., call
satisfiedEventsRef.current.add('receivedToken') and also add the corresponding
V2 alias like 'v2:auth:token' or vice‑versa) so checkReadyState() can match
either form; likewise, when you receive a V2 alias add the V1 alias as well.
Also emit the counterpart event back to the host in addition to the existing
emitV2Event (i.e., emit both versions when bridging). Apply this alias-pairing
change consistently to the other bridged handler blocks referenced (around the
other ranges).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: fef8c4ee-4e58-4561-bddd-d1f9d0df0fea

📥 Commits

Reviewing files that changed from the base of the PR and between fc06f35 and d4b83f0.

📒 Files selected for processing (9)
  • src/context/UbidotsReducer.ts
  • src/context/__tests__/actions.test.ts
  • src/context/__tests__/messageHandlers.test.ts
  • src/context/actions.ts
  • src/context/messageHandlers.ts
  • src/context/ubidots.tsx
  • src/hooks/__tests__/useUbidotsActions.test.tsx
  • src/hooks/__tests__/useWidgetEvents.test.tsx
  • src/hooks/useWidgetEvents.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/context/UbidotsReducer.ts

@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 7, 2026

🔍 PR Quality Check Summary

Check Status
Code Quality & Tests ✅ success
Security Audit ❌ failure

📋 Checks Performed:

  • ✅ TypeScript compilation
  • ✅ ESLint code quality
  • ✅ Prettier code formatting
  • ✅ Unit tests with coverage (80%+ required)
  • ✅ Build verification
  • ✅ Security audit

⚠️ Some checks failed. Please review the details above.

Copy link
Copy Markdown
Member

@ChristianECG ChristianECG left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Queda aprobado, sujeto a que se haga el QA correspondiente de acuerdo con lo conversado con el autor del PR.

@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 7, 2026

🔍 PR Quality Check Summary

Check Status
Code Quality & Tests ✅ success
Security Audit ❌ failure

📋 Checks Performed:

  • ✅ TypeScript compilation
  • ✅ ESLint code quality
  • ✅ Prettier code formatting
  • ✅ Unit tests with coverage (80%+ required)
  • ✅ Build verification
  • ✅ Security audit

⚠️ Some checks failed. Please review the details above.

@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 7, 2026

🔍 PR Quality Check Summary

Check Status
Code Quality & Tests ✅ success
Security Audit ❌ failure

📋 Checks Performed:

  • ✅ TypeScript compilation
  • ✅ ESLint code quality
  • ✅ Prettier code formatting
  • ✅ Unit tests with coverage (80%+ required)
  • ✅ Build verification
  • ✅ Security audit

⚠️ Some checks failed. Please review the details above.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants