@motiadev/plugin-logs 0.17.4-beta.185 → 0.17.4-beta.186-361289

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/components/logs-page.tsx","../src/types/log.ts"],"sourcesContent":[],"mappings":";;;cAWa,gBAAQ,kBAAA,CAAA,GAAA,CAAA;;;KCXT,GAAA;;;EDWC,IAAA,EAAA,MA0IZ;;;;ECrJW,KAAA,EAAG,MAAA,EAAA"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/components/logs-page.tsx","../src/types/log.ts"],"sourcesContent":[],"mappings":";;;cAWa,gBAAQ,kBAAA,CAAA,GAAA,CAAA;;;KCXT,GAAA;;;EDWC,IAAA,EAAA,MAoJZ;;;;EC/JW,KAAA,EAAG,MAAA,EAAA"}
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Button, Input, LevelDot, Sidebar, cn } from "@motiadev/ui";
2
2
  import { useVirtualizer } from "@tanstack/react-virtual";
3
- import { Search, Trash, X } from "lucide-react";
3
+ import { Filter, Search, Trash, X } from "lucide-react";
4
4
  import { useMemo, useRef, useState } from "react";
5
5
  import { c } from "react/compiler-runtime";
6
6
  import { useStreamGroup } from "@motiadev/stream-client-react";
@@ -221,15 +221,24 @@ const LogsPage = () => {
221
221
  className: "whitespace-nowrap flex items-center gap-2 text-muted-foreground p-2 shrink-0",
222
222
  children: [/* @__PURE__ */ jsx(LevelDot, { level: log_1.level }), formatTimestamp(log_1.time)]
223
223
  }),
224
- /* @__PURE__ */ jsx("button", {
225
- type: "button",
226
- "data-testid": `trace-${log_1.traceId}`,
227
- className: "whitespace-nowrap cursor-pointer hover:text-primary text-muted-foreground p-2 shrink-0 bg-transparent border-0 text-left font-mono font-semibold text-sm",
228
- onClick: (e_1) => {
229
- e_1.stopPropagation();
230
- setSearch(log_1.traceId);
231
- },
232
- children: log_1.traceId
224
+ /* @__PURE__ */ jsxs("div", {
225
+ className: "flex items-center shrink-0",
226
+ children: [/* @__PURE__ */ jsx("span", {
227
+ "data-testid": `trace-${log_1.traceId}`,
228
+ className: "whitespace-nowrap text-muted-foreground p-2 font-mono font-semibold text-sm",
229
+ children: log_1.traceId
230
+ }), /* @__PURE__ */ jsx("button", {
231
+ type: "button",
232
+ "data-testid": `trace-filter-${log_1.traceId}`,
233
+ "aria-label": `Filter by trace ${log_1.traceId}`,
234
+ title: `Filter by trace ${log_1.traceId}`,
235
+ className: "p-1 rounded hover:bg-muted-foreground/20 text-muted-foreground hover:text-primary transition-colors cursor-pointer",
236
+ onClick: (e_1) => {
237
+ e_1.stopPropagation();
238
+ setSearch(log_1.traceId);
239
+ },
240
+ children: /* @__PURE__ */ jsx(Filter, { className: "w-3 h-3" })
241
+ })]
233
242
  }),
234
243
  /* @__PURE__ */ jsx("div", {
235
244
  "data-testid": `step-${index}`,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["create","Log","LogsState","logs","selectedLogId","setLogs","resetLogs","selectLogId","logId","useLogsStore","set","undefined","safeLogs","Array","isArray","reverse","useStreamGroup","useLogsStore","Log","streamName","groupId","useLogsStream","$","_c","$i","Symbol","for","setData","_temp","t0","state","setLogs","formatTimestamp","time","date","Date","Number","toLocaleDateString","year","undefined","month","day","toLocaleTimeString","hour","minute","second","hourCycle","getMilliseconds","toString","padStart","LevelDot","Sidebar","X","React","useMemo","useState","ReactJson","Log","formatTimestamp","Props","log","onClose","defaultProps","LogDetail","FC","hasOtherProps","setHasOtherProps","otherPropsObject","otherProps","Object","keys","filter","key","includes","length","reduce","acc","Record","icon","onClick","label","value","level","time","step","flows","join","traceId","Button","cn","Input","LevelDot","useVirtualizer","Search","Trash","X","useMemo","useRef","useState","useLogsStream","useLogsStore","formatTimestamp","LogDetail","ROW_HEIGHT","LogsPage","logs","state","resetLogs","selectedLogId","selectLogId","selectedLog","find","log","id","undefined","search","setSearch","filteredLogs","filter","String","msg","toLowerCase","includes","traceId","step","scrollContainerRef","HTMLDivElement","virtualizer","count","length","getScrollElement","current","estimateSize","overscan","virtualItems","getVirtualItems","e","target","value","height","getTotalSize","map","virtualRow","index","measureElement","transform","start","key","level","time","stopPropagation"],"sources":["../src/stores/use-logs-store.ts","../src/hooks/use-logs-stream.ts","../src/utils/format-timestamp.ts","../src/components/log-detail.tsx","../src/components/logs-page.tsx"],"sourcesContent":["import { create } from 'zustand'\nimport type { Log } from '../types/log'\n\nexport type LogsState = {\n logs: Log[]\n selectedLogId?: string\n setLogs: (logs: Log[]) => void\n resetLogs: () => void\n selectLogId: (logId?: string) => void\n}\n\nexport const useLogsStore = create<LogsState>()((set) => ({\n logs: [],\n selectedLogId: undefined,\n setLogs: (logs: Log[]) =>\n set(() => {\n const safeLogs = Array.isArray(logs) ? logs : []\n return {\n logs: [...safeLogs].reverse(),\n }\n }),\n resetLogs: () => {\n set({ logs: [] })\n },\n selectLogId: (logId) => set({ selectedLogId: logId }),\n}))\n","import { useStreamGroup } from '@motiadev/stream-client-react'\nimport { useLogsStore } from '../stores/use-logs-store'\nimport type { Log } from '../types/log'\n\nconst streamName = '__motia.logs'\nconst groupId = 'default'\n\nexport const useLogsStream = () => {\n const setData = useLogsStore((state) => state.setLogs)\n\n useStreamGroup<Log>({\n streamName,\n groupId,\n setData,\n })\n}\n","export const formatTimestamp = (time: number) => {\n const date = new Date(Number(time))\n return `${date.toLocaleDateString('en-US', { year: undefined, month: 'short', day: '2-digit' })}, ${date.toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit', second: '2-digit', hourCycle: 'h24' })}.${date.getMilliseconds().toString().padStart(3, '0')}`\n}\n","import { LevelDot, Sidebar } from '@motiadev/ui'\nimport { X } from 'lucide-react'\nimport type React from 'react'\nimport { useMemo, useState } from 'react'\nimport ReactJson from 'react18-json-view'\nimport 'react18-json-view/src/dark.css'\nimport 'react18-json-view/src/style.css'\nimport type { Log } from '../types/log'\nimport { formatTimestamp } from '../utils/format-timestamp'\n\ntype Props = {\n log?: Log\n onClose: () => void\n}\n\nconst defaultProps = ['id', 'msg', 'time', 'level', 'step', 'flows', 'traceId']\n\nexport const LogDetail: React.FC<Props> = ({ log, onClose }) => {\n const [hasOtherProps, setHasOtherProps] = useState(false)\n\n const otherPropsObject = useMemo(() => {\n if (!log) {\n return null\n }\n\n const otherProps = Object.keys(log ?? {}).filter((key) => !defaultProps.includes(key))\n setHasOtherProps(otherProps.length > 0)\n\n return otherProps.reduce(\n (acc, key) => {\n acc[key] = log[key]\n return acc\n },\n {} as Record<string, unknown>,\n )\n }, [log])\n\n if (!log) {\n return null\n }\n\n return (\n <Sidebar\n onClose={onClose}\n title=\"Logs Details\"\n subtitle=\"Details including custom properties\"\n actions={[{ icon: <X />, onClick: onClose, label: 'Close' }]}\n details={[\n {\n label: 'Level',\n value: (\n <div className=\"flex items-center gap-2\">\n <LevelDot level={log.level} />\n <div className=\"capitalize\">{log.level}</div>\n </div>\n ),\n },\n { label: 'Time', value: formatTimestamp(log.time) },\n { label: 'Step', value: log.step },\n { label: 'Flows', value: log.flows.join(', ') },\n { label: 'Trace ID', value: log.traceId },\n ]}\n >\n {hasOtherProps && <ReactJson src={otherPropsObject} theme=\"default\" enableClipboard />}\n </Sidebar>\n )\n}\n","import { Button, cn, Input, LevelDot } from '@motiadev/ui'\nimport { useVirtualizer } from '@tanstack/react-virtual'\nimport { Search, Trash, X } from 'lucide-react'\nimport { useMemo, useRef, useState } from 'react'\nimport { useLogsStream } from '../hooks/use-logs-stream'\nimport { useLogsStore } from '../stores/use-logs-store'\nimport { formatTimestamp } from '../utils/format-timestamp'\nimport { LogDetail } from './log-detail'\n\nconst ROW_HEIGHT = 40\n\nexport const LogsPage = () => {\n useLogsStream()\n\n const logs = useLogsStore((state) => state.logs)\n const resetLogs = useLogsStore((state) => state.resetLogs)\n const selectedLogId = useLogsStore((state) => state.selectedLogId)\n const selectLogId = useLogsStore((state) => state.selectLogId)\n const selectedLog = useMemo(\n () => (selectedLogId ? logs.find((log) => log.id === selectedLogId) : undefined),\n [logs, selectedLogId],\n )\n\n const [search, setSearch] = useState('')\n const filteredLogs = useMemo(() => {\n return logs.filter((log) => {\n return (\n String(log.msg || '')\n .toLowerCase()\n .includes(search.toLowerCase()) ||\n String(log.traceId || '')\n .toLowerCase()\n .includes(search.toLowerCase()) ||\n String(log.step || '')\n .toLowerCase()\n .includes(search.toLowerCase())\n )\n })\n }, [logs, search])\n\n const scrollContainerRef = useRef<HTMLDivElement>(null)\n\n const virtualizer = useVirtualizer({\n count: filteredLogs.length,\n getScrollElement: () => scrollContainerRef.current,\n estimateSize: () => ROW_HEIGHT,\n overscan: 5,\n })\n\n const virtualItems = virtualizer.getVirtualItems()\n\n return (\n <>\n <div className=\"grid grid-rows-[auto_1fr] h-full\" data-testid=\"logs-container\">\n <div className=\"flex p-2 border-b gap-2\" data-testid=\"logs-search-container\">\n <div className=\"flex-1 relative\">\n <Input\n variant=\"shade\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n className=\"px-9! font-medium\"\n placeholder=\"Search by Trace ID or Message\"\n />\n <Search className=\"absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-muted-foreground/50\" />\n <X\n className=\"cursor-pointer absolute right-3 top-1/2 -translate-y-1/2 w-4 h-4 text-muted-foreground/50 hover:text-muted-foreground\"\n onClick={() => setSearch('')}\n />\n </div>\n <Button variant=\"default\" onClick={resetLogs} className=\"h-[34px]\">\n <Trash /> Clear\n </Button>\n </div>\n <div ref={scrollContainerRef} className=\"overflow-auto h-full\">\n <div className=\"relative w-full\" style={{ height: virtualizer.getTotalSize() }}>\n {virtualItems.map((virtualRow) => {\n const log = filteredLogs[virtualRow.index]\n if (!log) return null\n const index = virtualRow.index\n return (\n <div\n data-testid=\"log-row\"\n data-index={virtualRow.index}\n ref={virtualizer.measureElement}\n key={log.id}\n role=\"row\"\n tabIndex={0}\n className={cn(\n 'absolute left-0 w-full flex items-center font-mono font-semibold cursor-pointer text-sm',\n {\n 'bg-muted-foreground/10 hover:bg-muted-foreground/20': selectedLogId === log.id,\n 'hover:bg-muted-foreground/10': selectedLogId !== log.id,\n },\n )}\n style={{\n height: ROW_HEIGHT,\n transform: `translateY(${virtualRow.start}px)`,\n }}\n onClick={() => selectLogId(log.id)}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n selectLogId(log.id)\n }\n }}\n >\n <div\n data-testid={`time-${index}`}\n role=\"cell\"\n className=\"whitespace-nowrap flex items-center gap-2 text-muted-foreground p-2 shrink-0\"\n >\n <LevelDot level={log.level} />\n {formatTimestamp(log.time)}\n </div>\n <button\n type=\"button\"\n data-testid={`trace-${log.traceId}`}\n className=\"whitespace-nowrap cursor-pointer hover:text-primary text-muted-foreground p-2 shrink-0 bg-transparent border-0 text-left font-mono font-semibold text-sm\"\n onClick={(e) => {\n e.stopPropagation()\n setSearch(log.traceId)\n }}\n >\n {log.traceId}\n </button>\n <div\n data-testid={`step-${index}`}\n role=\"cell\"\n title={log.step}\n className=\"whitespace-nowrap p-2 shrink-0\"\n >\n {log.step}\n </div>\n <div\n data-testid={`msg-${index}`}\n role=\"cell\"\n title={log.msg}\n className=\"whitespace-nowrap max-w-[500px] truncate p-2 flex-1\"\n >\n {log.msg}\n </div>\n </div>\n )\n })}\n </div>\n </div>\n </div>\n <LogDetail log={selectedLog} onClose={() => selectLogId(undefined)} />\n </>\n )\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["create","Log","LogsState","logs","selectedLogId","setLogs","resetLogs","selectLogId","logId","useLogsStore","set","undefined","safeLogs","Array","isArray","reverse","useStreamGroup","useLogsStore","Log","streamName","groupId","useLogsStream","$","_c","$i","Symbol","for","setData","_temp","t0","state","setLogs","formatTimestamp","time","date","Date","Number","toLocaleDateString","year","undefined","month","day","toLocaleTimeString","hour","minute","second","hourCycle","getMilliseconds","toString","padStart","LevelDot","Sidebar","X","React","useMemo","useState","ReactJson","Log","formatTimestamp","Props","log","onClose","defaultProps","LogDetail","FC","hasOtherProps","setHasOtherProps","otherPropsObject","otherProps","Object","keys","filter","key","includes","length","reduce","acc","Record","icon","onClick","label","value","level","time","step","flows","join","traceId","Button","cn","Input","LevelDot","useVirtualizer","Filter","Search","Trash","X","useMemo","useRef","useState","useLogsStream","useLogsStore","formatTimestamp","LogDetail","ROW_HEIGHT","LogsPage","logs","state","resetLogs","selectedLogId","selectLogId","selectedLog","find","log","id","undefined","search","setSearch","filteredLogs","filter","String","msg","toLowerCase","includes","traceId","step","scrollContainerRef","HTMLDivElement","virtualizer","count","length","getScrollElement","current","estimateSize","overscan","virtualItems","getVirtualItems","e","target","value","height","getTotalSize","map","virtualRow","index","measureElement","transform","start","key","level","time","stopPropagation"],"sources":["../src/stores/use-logs-store.ts","../src/hooks/use-logs-stream.ts","../src/utils/format-timestamp.ts","../src/components/log-detail.tsx","../src/components/logs-page.tsx"],"sourcesContent":["import { create } from 'zustand'\nimport type { Log } from '../types/log'\n\nexport type LogsState = {\n logs: Log[]\n selectedLogId?: string\n setLogs: (logs: Log[]) => void\n resetLogs: () => void\n selectLogId: (logId?: string) => void\n}\n\nexport const useLogsStore = create<LogsState>()((set) => ({\n logs: [],\n selectedLogId: undefined,\n setLogs: (logs: Log[]) =>\n set(() => {\n const safeLogs = Array.isArray(logs) ? logs : []\n return {\n logs: [...safeLogs].reverse(),\n }\n }),\n resetLogs: () => {\n set({ logs: [] })\n },\n selectLogId: (logId) => set({ selectedLogId: logId }),\n}))\n","import { useStreamGroup } from '@motiadev/stream-client-react'\nimport { useLogsStore } from '../stores/use-logs-store'\nimport type { Log } from '../types/log'\n\nconst streamName = '__motia.logs'\nconst groupId = 'default'\n\nexport const useLogsStream = () => {\n const setData = useLogsStore((state) => state.setLogs)\n\n useStreamGroup<Log>({\n streamName,\n groupId,\n setData,\n })\n}\n","export const formatTimestamp = (time: number) => {\n const date = new Date(Number(time))\n return `${date.toLocaleDateString('en-US', { year: undefined, month: 'short', day: '2-digit' })}, ${date.toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit', second: '2-digit', hourCycle: 'h24' })}.${date.getMilliseconds().toString().padStart(3, '0')}`\n}\n","import { LevelDot, Sidebar } from '@motiadev/ui'\nimport { X } from 'lucide-react'\nimport type React from 'react'\nimport { useMemo, useState } from 'react'\nimport ReactJson from 'react18-json-view'\nimport 'react18-json-view/src/dark.css'\nimport 'react18-json-view/src/style.css'\nimport type { Log } from '../types/log'\nimport { formatTimestamp } from '../utils/format-timestamp'\n\ntype Props = {\n log?: Log\n onClose: () => void\n}\n\nconst defaultProps = ['id', 'msg', 'time', 'level', 'step', 'flows', 'traceId']\n\nexport const LogDetail: React.FC<Props> = ({ log, onClose }) => {\n const [hasOtherProps, setHasOtherProps] = useState(false)\n\n const otherPropsObject = useMemo(() => {\n if (!log) {\n return null\n }\n\n const otherProps = Object.keys(log ?? {}).filter((key) => !defaultProps.includes(key))\n setHasOtherProps(otherProps.length > 0)\n\n return otherProps.reduce(\n (acc, key) => {\n acc[key] = log[key]\n return acc\n },\n {} as Record<string, unknown>,\n )\n }, [log])\n\n if (!log) {\n return null\n }\n\n return (\n <Sidebar\n onClose={onClose}\n title=\"Logs Details\"\n subtitle=\"Details including custom properties\"\n actions={[{ icon: <X />, onClick: onClose, label: 'Close' }]}\n details={[\n {\n label: 'Level',\n value: (\n <div className=\"flex items-center gap-2\">\n <LevelDot level={log.level} />\n <div className=\"capitalize\">{log.level}</div>\n </div>\n ),\n },\n { label: 'Time', value: formatTimestamp(log.time) },\n { label: 'Step', value: log.step },\n { label: 'Flows', value: log.flows.join(', ') },\n { label: 'Trace ID', value: log.traceId },\n ]}\n >\n {hasOtherProps && <ReactJson src={otherPropsObject} theme=\"default\" enableClipboard />}\n </Sidebar>\n )\n}\n","import { Button, cn, Input, LevelDot } from '@motiadev/ui'\nimport { useVirtualizer } from '@tanstack/react-virtual'\nimport { Filter, Search, Trash, X } from 'lucide-react'\nimport { useMemo, useRef, useState } from 'react'\nimport { useLogsStream } from '../hooks/use-logs-stream'\nimport { useLogsStore } from '../stores/use-logs-store'\nimport { formatTimestamp } from '../utils/format-timestamp'\nimport { LogDetail } from './log-detail'\n\nconst ROW_HEIGHT = 40\n\nexport const LogsPage = () => {\n useLogsStream()\n\n const logs = useLogsStore((state) => state.logs)\n const resetLogs = useLogsStore((state) => state.resetLogs)\n const selectedLogId = useLogsStore((state) => state.selectedLogId)\n const selectLogId = useLogsStore((state) => state.selectLogId)\n const selectedLog = useMemo(\n () => (selectedLogId ? logs.find((log) => log.id === selectedLogId) : undefined),\n [logs, selectedLogId],\n )\n\n const [search, setSearch] = useState('')\n const filteredLogs = useMemo(() => {\n return logs.filter((log) => {\n return (\n String(log.msg || '')\n .toLowerCase()\n .includes(search.toLowerCase()) ||\n String(log.traceId || '')\n .toLowerCase()\n .includes(search.toLowerCase()) ||\n String(log.step || '')\n .toLowerCase()\n .includes(search.toLowerCase())\n )\n })\n }, [logs, search])\n\n const scrollContainerRef = useRef<HTMLDivElement>(null)\n\n const virtualizer = useVirtualizer({\n count: filteredLogs.length,\n getScrollElement: () => scrollContainerRef.current,\n estimateSize: () => ROW_HEIGHT,\n overscan: 5,\n })\n\n const virtualItems = virtualizer.getVirtualItems()\n\n return (\n <>\n <div className=\"grid grid-rows-[auto_1fr] h-full\" data-testid=\"logs-container\">\n <div className=\"flex p-2 border-b gap-2\" data-testid=\"logs-search-container\">\n <div className=\"flex-1 relative\">\n <Input\n variant=\"shade\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n className=\"px-9! font-medium\"\n placeholder=\"Search by Trace ID or Message\"\n />\n <Search className=\"absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-muted-foreground/50\" />\n <X\n className=\"cursor-pointer absolute right-3 top-1/2 -translate-y-1/2 w-4 h-4 text-muted-foreground/50 hover:text-muted-foreground\"\n onClick={() => setSearch('')}\n />\n </div>\n <Button variant=\"default\" onClick={resetLogs} className=\"h-[34px]\">\n <Trash /> Clear\n </Button>\n </div>\n <div ref={scrollContainerRef} className=\"overflow-auto h-full\">\n <div className=\"relative w-full\" style={{ height: virtualizer.getTotalSize() }}>\n {virtualItems.map((virtualRow) => {\n const log = filteredLogs[virtualRow.index]\n if (!log) return null\n const index = virtualRow.index\n return (\n <div\n data-testid=\"log-row\"\n data-index={virtualRow.index}\n ref={virtualizer.measureElement}\n key={log.id}\n role=\"row\"\n tabIndex={0}\n className={cn(\n 'absolute left-0 w-full flex items-center font-mono font-semibold cursor-pointer text-sm',\n {\n 'bg-muted-foreground/10 hover:bg-muted-foreground/20': selectedLogId === log.id,\n 'hover:bg-muted-foreground/10': selectedLogId !== log.id,\n },\n )}\n style={{\n height: ROW_HEIGHT,\n transform: `translateY(${virtualRow.start}px)`,\n }}\n onClick={() => selectLogId(log.id)}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n selectLogId(log.id)\n }\n }}\n >\n <div\n data-testid={`time-${index}`}\n role=\"cell\"\n className=\"whitespace-nowrap flex items-center gap-2 text-muted-foreground p-2 shrink-0\"\n >\n <LevelDot level={log.level} />\n {formatTimestamp(log.time)}\n </div>\n <div className=\"flex items-center shrink-0\">\n <span\n data-testid={`trace-${log.traceId}`}\n className=\"whitespace-nowrap text-muted-foreground p-2 font-mono font-semibold text-sm\"\n >\n {log.traceId}\n </span>\n <button\n type=\"button\"\n data-testid={`trace-filter-${log.traceId}`}\n aria-label={`Filter by trace ${log.traceId}`}\n title={`Filter by trace ${log.traceId}`}\n className=\"p-1 rounded hover:bg-muted-foreground/20 text-muted-foreground hover:text-primary transition-colors cursor-pointer\"\n onClick={(e) => {\n e.stopPropagation()\n setSearch(log.traceId)\n }}\n >\n <Filter className=\"w-3 h-3\" />\n </button>\n </div>\n <div\n data-testid={`step-${index}`}\n role=\"cell\"\n title={log.step}\n className=\"whitespace-nowrap p-2 shrink-0\"\n >\n {log.step}\n </div>\n <div\n data-testid={`msg-${index}`}\n role=\"cell\"\n title={log.msg}\n className=\"whitespace-nowrap max-w-[500px] truncate p-2 flex-1\"\n >\n {log.msg}\n </div>\n </div>\n )\n })}\n </div>\n </div>\n </div>\n <LogDetail log={selectedLog} onClose={() => selectLogId(undefined)} />\n </>\n )\n}\n"],"mappings":";;;;;;;;;;;;;AAWA,MAAaS,eAAeT,QAAmB,EAAEU,SAAS;CACxDP,MAAM,EAAE;CACRC,eAAeO;CACfN,UAAUF,SACRO,UAAU;AAER,SAAO,EACLP,MAAM,CAAC,GAFQU,MAAMC,QAAQX,KAAK,GAAGA,OAAO,EAAE,CAE3B,CAACY,SAAQ,EAC7B;GACD;CACJT,iBAAiB;AACfI,MAAI,EAAEP,MAAM,EAAA,EAAI,CAAC;;CAEnBI,cAAcC,UAAUE,IAAI,EAAEN,eAAeI,OAAO,CAAA;CACrD,EAAE;;;;ACrBH,MAAMW,aAAa;AACnB,MAAMC,UAAU;AAEhB,MAAaC,sBAAgB;CAAA,MAAAC,IAAAC,EAAA,EAAA;AAAA,KAAAD,EAAA,OAAA,oEAAA;AAAA,OAAA,IAAAE,KAAA,GAAAA,KAAA,GAAAA,MAAA,EAAAF,GAAAE,MAAAC,OAAAC,IAAA,4BAAA;AAAAJ,IAAA,KAAA;;CAC3B,MAAAK,UAAgBV,aAAaW,MAAyB;CAAA,IAAAC;AAAA,KAAAP,EAAA,OAAAK,SAAA;AAElCE,OAAA;GAAAV;GAAAC;GAAAO;GAInB;AAAAL,IAAA,KAAAK;AAAAL,IAAA,KAAAO;OAAAA,MAAAP,EAAA;AAJDN,gBAAoBa,GAIlB;;AAPyB,SAAAD,MAAAE,OAAA;AAAA,QACaA,MAAKC;;;;;ACR/C,MAAaC,mBAAmBC,SAAiB;CAC/C,MAAMC,OAAO,IAAIC,KAAKC,OAAOH,KAAK,CAAC;AACnC,QAAO,GAAGC,KAAKG,mBAAmB,SAAS;EAAEC,MAAMC;EAAWC,OAAO;EAASC,KAAK;EAAW,CAAC,CAAA,IAAKP,KAAKQ,mBAAmB,SAAS;EAAEC,MAAM;EAAWC,QAAQ;EAAWC,QAAQ;EAAWC,WAAW;EAAO,CAAC,CAAA,GAAIZ,KAAKa,iBAAiB,CAACC,UAAU,CAACC,SAAS,GAAG,IAAI;;;;;ACazQ,MAAMa,eAAe;CAAC;CAAM;CAAO;CAAQ;CAAS;CAAQ;CAAS;CAAU;AAE/E,MAAaC,aAA8B,EAAEH,KAAKC,cAAc;CAC9D,MAAM,CAACI,eAAeC,oBAAoBX,SAAS,MAAM;CAEzD,MAAMY,mBAAmBb,cAAc;AACrC,MAAI,CAACM,IACH,QAAO;EAGT,MAAMQ,aAAaC,OAAOC,KAAKV,OAAO,EAAE,CAAC,CAACW,QAAQC,QAAQ,CAACV,aAAaW,SAASD,IAAI,CAAC;AACtFN,mBAAiBE,WAAWM,SAAS,EAAE;AAEvC,SAAON,WAAWO,QACfC,KAAKJ,UAAQ;AACZI,OAAIJ,SAAOZ,IAAIY;AACf,UAAOI;KAET,EAAE,CACH;IACA,CAAChB,IAAI,CAAC;AAET,KAAI,CAACA,IACH,QAAO;AAGT,QACE,oBAAC;EACUC;EACT,OAAM;EACN,UAAS;EACT,SAAS,CAAC;GAAEiB,MAAM,oBAAC,MAAI;GAAEC,SAASlB;GAASmB,OAAO;GAAS,CAAC;EAC5D,SAAS;GACP;IACEA,OAAO;IACPC,OACE,qBAAC;KAAI,WAAU;gBACb,oBAAC,YAAS,OAAOrB,IAAIsB,QAAM,EAC3B,oBAAC;MAAI,WAAU;gBAActB,IAAIsB;OAAW;MACzC;IAER;GACD;IAAEF,OAAO;IAAQC,OAAOvB,gBAAgBE,IAAIuB,KAAI;IAAG;GACnD;IAAEH,OAAO;IAAQC,OAAOrB,IAAIwB;IAAM;GAClC;IAAEJ,OAAO;IAASC,OAAOrB,IAAIyB,MAAMC,KAAK,KAAI;IAAG;GAC/C;IAAEN,OAAO;IAAYC,OAAOrB,IAAI2B;IAAS;GAC1C;YAEAtB,iBAAiB,oBAAC;GAAU,KAAKE;GAAkB,OAAM;GAAU;IAAkB;GAC9E;;;;;ACvDd,MAAMqC,aAAa;AAEnB,MAAaC,iBAAiB;AAC5BL,gBAAe;CAEf,MAAMM,OAAOL,cAAcM,UAAUA,MAAMD,KAAK;CAChD,MAAME,YAAYP,cAAcM,YAAUA,QAAMC,UAAU;CAC1D,MAAMC,gBAAgBR,cAAcM,YAAUA,QAAME,cAAc;CAClE,MAAMC,cAAcT,cAAcM,YAAUA,QAAMG,YAAY;CAC9D,MAAMC,cAAcd,cACXY,gBAAgBH,KAAKM,MAAMC,QAAQA,IAAIC,OAAOL,cAAc,GAAGM,QACtE,CAACT,MAAMG,cACT,CAAC;CAED,MAAM,CAACO,QAAQC,aAAalB,SAAS,GAAG;CACxC,MAAMmB,eAAerB,cAAc;AACjC,SAAOS,KAAKa,QAAQN,UAAQ;AAC1B,UACEO,OAAOP,MAAIQ,OAAO,GAAG,CAClBC,aAAa,CACbC,SAASP,OAAOM,aAAa,CAAC,IACjCF,OAAOP,MAAIW,WAAW,GAAG,CACtBF,aAAa,CACbC,SAASP,OAAOM,aAAa,CAAC,IACjCF,OAAOP,MAAIY,QAAQ,GAAG,CACnBH,aAAa,CACbC,SAASP,OAAOM,aAAa,CAAC;IAEnC;IACD,CAAChB,MAAMU,OAAO,CAAC;CAElB,MAAMU,qBAAqB5B,OAAuB,KAAK;CAEvD,MAAM8B,cAAcpC,eAAe;EACjCqC,OAAOX,aAAaY;EACpBC,wBAAwBL,mBAAmBM;EAC3CC,oBAAoB7B;EACpB8B,UAAU;EACX,CAAC;CAEF,MAAMC,eAAeP,YAAYQ,iBAAiB;AAElD,QACE,4CACE,qBAAC;EAAI,WAAU;EAAmC,eAAY;aAC5D,qBAAC;GAAI,WAAU;GAA0B,eAAY;cACnD,qBAAC;IAAI,WAAU;;KACb,oBAAC;MACC,SAAQ;MACR,OAAOpB;MACP,WAAWqB,MAAMpB,UAAUoB,EAAEC,OAAOC,MAAM;MAC1C,WAAU;MACV,aAAY;OAA+B;KAE7C,oBAAC,UAAO,WAAU,8EAA2E;KAC7F,oBAAC;MACC,WAAU;MACV,eAAetB,UAAU,GAAG;OAAC;;KAE5B,EACL,qBAAC;IAAO,SAAQ;IAAU,SAAST;IAAW,WAAU;eACtD,oBAAC,UAAQ;KACH;IACL,EACL,oBAAC;GAAI,KAAKkB;GAAoB,WAAU;aACtC,oBAAC;IAAI,WAAU;IAAkB,OAAO,EAAEc,QAAQZ,YAAYa,cAAa,EAAG;cAC3EN,aAAaO,KAAKC,eAAe;KAChC,MAAM9B,QAAMK,aAAayB,WAAWC;AACpC,SAAI,CAAC/B,MAAK,QAAO;KACjB,MAAM+B,QAAQD,WAAWC;AACzB,YACE,qBAAC;MACC,eAAY;MACZ,cAAYD,WAAWC;MACvB,KAAKhB,YAAYiB;MAEjB,MAAK;MACL,UAAU;MACV,WAAWxD,GACT,2FACA;OACE,uDAAuDoB,kBAAkBI,MAAIC;OAC7E,gCAAgCL,kBAAkBI,MAAIC;OAE1D,CAAC;MACD,OAAO;OACL0B,QAAQpC;OACR0C,WAAW,cAAcH,WAAWI,MAAK;OAC1C;MACD,eAAerC,YAAYG,MAAIC,GAAG;MAClC,YAAYuB,QAAM;AAChB,WAAIA,IAAEW,QAAQ,WAAWX,IAAEW,QAAQ,IACjCtC,aAAYG,MAAIC,GAAG;;;OAIvB,qBAAC;QACC,eAAa,QAAQ8B;QACrB,MAAK;QACL,WAAU;mBAEV,oBAAC,YAAS,OAAO/B,MAAIoC,QAAM,EAC1B/C,gBAAgBW,MAAIqC,KAAK;SACvB;OACL,qBAAC;QAAI,WAAU;mBACb,oBAAC;SACC,eAAa,SAASrC,MAAIW;SAC1B,WAAU;mBAETX,MAAIW;UACD,EACN,oBAAC;SACC,MAAK;SACL,eAAa,gBAAgBX,MAAIW;SACjC,cAAY,mBAAmBX,MAAIW;SACnC,OAAO,mBAAmBX,MAAIW;SAC9B,WAAU;SACV,UAAUa,QAAM;AACdA,cAAEc,iBAAiB;AACnBlC,oBAAUJ,MAAIW,QAAQ;;mBAGxB,oBAAC,UAAO,WAAU,YAAS;UACrB;SACL;OACL,oBAAC;QACC,eAAa,QAAQoB;QACrB,MAAK;QACL,OAAO/B,MAAIY;QACX,WAAU;kBAETZ,MAAIY;SACF;OACL,oBAAC;QACC,eAAa,OAAOmB;QACpB,MAAK;QACL,OAAO/B,MAAIQ;QACX,WAAU;kBAETR,MAAIQ;SACF;;QAjEAR,MAAIC,GAkEL;MAER;KACC;IACF;GACF,EACL,oBAAC;EAAU,KAAKH;EAAa,eAAeD,YAAYK,OAAU;GAAC,IAClE"}
package/dist/styles.css CHANGED
@@ -12,6 +12,8 @@
12
12
  --text-sm--line-height: calc(1.25 / 0.875);
13
13
  --font-weight-medium: 500;
14
14
  --font-weight-semibold: 600;
15
+ --default-transition-duration: 150ms;
16
+ --default-transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
15
17
  --default-font-family: var(--font-sans);
16
18
  --default-mono-font-family: var(--font-mono);
17
19
  --font-weight-500: var(--font-weight-500);
@@ -192,6 +194,9 @@
192
194
  .grid {
193
195
  display: grid;
194
196
  }
197
+ .h-3 {
198
+ height: calc(var(--spacing) * 3);
199
+ }
195
200
  .h-4 {
196
201
  height: calc(var(--spacing) * 4);
197
202
  }
@@ -201,6 +206,9 @@
201
206
  .h-full {
202
207
  height: 100%;
203
208
  }
209
+ .w-3 {
210
+ width: calc(var(--spacing) * 3);
211
+ }
204
212
  .w-4 {
205
213
  width: calc(var(--spacing) * 4);
206
214
  }
@@ -243,9 +251,8 @@
243
251
  .overflow-auto {
244
252
  overflow: auto;
245
253
  }
246
- .border-0 {
247
- border-style: var(--tw-border-style);
248
- border-width: 0px;
254
+ .rounded {
255
+ border-radius: 0.25rem;
249
256
  }
250
257
  .border-b {
251
258
  border-bottom-style: var(--tw-border-style);
@@ -257,8 +264,8 @@
257
264
  background-color: color-mix(in oklab, var(--muted-foreground) 10%, transparent);
258
265
  }
259
266
  }
260
- .bg-transparent {
261
- background-color: transparent;
267
+ .p-1 {
268
+ padding: calc(var(--spacing) * 1);
262
269
  }
263
270
  .p-2 {
264
271
  padding: calc(var(--spacing) * 2);
@@ -266,9 +273,6 @@
266
273
  .px-9\! {
267
274
  padding-inline: calc(var(--spacing) * 9) !important;
268
275
  }
269
- .text-left {
270
- text-align: left;
271
- }
272
276
  .font-mono {
273
277
  font-family: var(--font-mono);
274
278
  }
@@ -299,6 +303,11 @@
299
303
  .capitalize {
300
304
  text-transform: capitalize;
301
305
  }
306
+ .transition-colors {
307
+ transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to;
308
+ transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));
309
+ transition-duration: var(--tw-duration, var(--default-transition-duration));
310
+ }
302
311
  .hover\:bg-muted-foreground\/10 {
303
312
  &:hover {
304
313
  @media (hover: hover) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@motiadev/plugin-logs",
3
- "version": "0.17.4-beta.185",
3
+ "version": "0.17.4-beta.186-361289",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -20,11 +20,11 @@
20
20
  "zustand": "^5.0.8"
21
21
  },
22
22
  "peerDependencies": {
23
- "@motiadev/stream-client-browser": "0.17.4-beta.185",
24
- "@motiadev/ui": "0.17.4-beta.185",
25
- "@motiadev/stream-client-react": "0.17.4-beta.185",
26
- "@motiadev/core": "0.17.4-beta.185",
27
- "motia": "0.17.4-beta.185"
23
+ "@motiadev/core": "0.17.4-beta.186-361289",
24
+ "@motiadev/ui": "0.17.4-beta.186-361289",
25
+ "motia": "0.17.4-beta.186-361289",
26
+ "@motiadev/stream-client-browser": "0.17.4-beta.186-361289",
27
+ "@motiadev/stream-client-react": "0.17.4-beta.186-361289"
28
28
  },
29
29
  "devDependencies": {
30
30
  "@bosh-code/tsdown-plugin-inject-css": "^2.0.0",