diff --git a/packages/yii-dev-panel-sdk/src/Component/LogEntry.tsx b/packages/yii-dev-panel-sdk/src/Component/LogEntry.tsx
new file mode 100644
index 00000000..b39b3091
--- /dev/null
+++ b/packages/yii-dev-panel-sdk/src/Component/LogEntry.tsx
@@ -0,0 +1,34 @@
+import {FilePresent} from '@mui/icons-material';
+import {Alert, AlertTitle, Link} from '@mui/material';
+import Box from '@mui/material/Box';
+import {JsonRenderer} from '@yiisoft/yii-dev-panel-sdk/Component/JsonRenderer';
+import {phpLoggerLevelToAlertColor} from '@yiisoft/yii-dev-panel-sdk/Helper/collorMapper';
+import {parseFilePathWithLineAnchor} from '@yiisoft/yii-dev-panel-sdk/Helper/filePathParser';
+import {PhpLoggerLevel} from '@yiisoft/yii-dev-panel-sdk/Types/logger';
+
+export type LogEntry = {
+ context: object;
+ level: PhpLoggerLevel;
+ line?: string;
+ message: string;
+ time: number;
+};
+type LogEntryProps = {
+ entry: LogEntry;
+};
+export const LogEntry = ({entry}: LogEntryProps) => {
+ return (
+
+ {entry.message}
+
+
+ {'line' in entry && (
+
+ {entry.line}
+
+
+ )}
+
+
+ );
+};
diff --git a/packages/yii-dev-panel-sdk/src/Component/ServerSentEventsObserver.ts b/packages/yii-dev-panel-sdk/src/Component/ServerSentEventsObserver.ts
index af25f6f3..4b129bac 100644
--- a/packages/yii-dev-panel-sdk/src/Component/ServerSentEventsObserver.ts
+++ b/packages/yii-dev-panel-sdk/src/Component/ServerSentEventsObserver.ts
@@ -1,5 +1,5 @@
// TODO support custom events and decode payload to object
-class ServerSentEvents {
+export class ServerSentEvents {
private eventSource: EventSource = null;
private listeners: ((event: MessageEvent) => void)[] = [];
constructor(private url: string) {}
@@ -7,6 +7,15 @@ class ServerSentEvents {
subscribe(subscriber: (event: MessageEvent) => void) {
if (this.eventSource === null || this.eventSource.readyState === EventSource.CLOSED) {
this.eventSource = new EventSource(this.url);
+ this.eventSource.onopen = () => {
+ console.log('ServerSentEvents: connected');
+ };
+ this.eventSource.onerror = () => {
+ console.log('ServerSentEvents: error', this.listeners);
+ this.listeners.forEach((listener) => {
+ this.eventSource.addEventListener('message', listener);
+ });
+ };
}
this.listeners.push(subscriber);
this.eventSource.addEventListener('message', this.handle.bind(this));
@@ -32,5 +41,4 @@ class ServerSentEvents {
}
}
-export const createServerSentEventsObserver = (backendUrl: string) =>
- new ServerSentEvents(backendUrl + '/debug/api/event-stream');
+export const createServerSentEventsObserver = (url: string) => new ServerSentEvents(url);
diff --git a/packages/yii-dev-panel-sdk/src/Component/useDevServerEvents.ts b/packages/yii-dev-panel-sdk/src/Component/useDevServerEvents.ts
new file mode 100644
index 00000000..0a91d723
--- /dev/null
+++ b/packages/yii-dev-panel-sdk/src/Component/useDevServerEvents.ts
@@ -0,0 +1,41 @@
+import {createServerSentEventsObserver} from '@yiisoft/yii-dev-panel-sdk/Component/ServerSentEventsObserver';
+import {useEffect, useRef} from 'react';
+
+type DebugUpdatedType = {
+ type: EventTypesEnum.DebugUpdated;
+ payload: {};
+};
+
+export enum EventTypesEnum {
+ DebugUpdated = 'debug-updated',
+}
+
+export type EventTypes = DebugUpdatedType;
+
+export const useServerSentEvents = (
+ backendUrl: string,
+ onMessage: (event: MessageEvent) => void,
+ subscribe = true,
+) => {
+ const prevOnMessage = useRef(onMessage);
+ const ServerSentEventsObserverRef = useRef(createServerSentEventsObserver(backendUrl + '/debug/api/dev'));
+
+ useEffect(() => {
+ if (prevOnMessage.current) {
+ ServerSentEventsObserverRef.current.unsubscribe(prevOnMessage.current);
+ }
+ if (!subscribe) {
+ return () => {
+ ServerSentEventsObserverRef.current.unsubscribe(onMessage);
+ };
+ }
+
+ ServerSentEventsObserverRef.current.subscribe(onMessage);
+ prevOnMessage.current = onMessage;
+
+ return () => {
+ ServerSentEventsObserverRef.current.unsubscribe(onMessage);
+ ServerSentEventsObserverRef.current.close();
+ };
+ }, [onMessage, subscribe]);
+};
diff --git a/packages/yii-dev-panel-sdk/src/Component/useServerSentEvents.ts b/packages/yii-dev-panel-sdk/src/Component/useServerSentEvents.ts
index 4421ff37..a02b1218 100644
--- a/packages/yii-dev-panel-sdk/src/Component/useServerSentEvents.ts
+++ b/packages/yii-dev-panel-sdk/src/Component/useServerSentEvents.ts
@@ -18,7 +18,7 @@ export const useServerSentEvents = (
subscribe = true,
) => {
const prevOnMessage = useRef(onMessage);
- const ServerSentEventsObserverRef = useRef(createServerSentEventsObserver(backendUrl));
+ const ServerSentEventsObserverRef = useRef(createServerSentEventsObserver(backendUrl + '/debug/api/event-stream'));
useEffect(() => {
if (prevOnMessage.current) {
diff --git a/packages/yii-dev-panel-sdk/src/Helper/collorMapper.ts b/packages/yii-dev-panel-sdk/src/Helper/collorMapper.ts
new file mode 100644
index 00000000..c63133b3
--- /dev/null
+++ b/packages/yii-dev-panel-sdk/src/Helper/collorMapper.ts
@@ -0,0 +1,19 @@
+import {AlertColor} from '@mui/material';
+import {PhpLoggerLevel} from '@yiisoft/yii-dev-panel-sdk/Types/logger';
+
+export const phpLoggerLevelToAlertColor = (status: PhpLoggerLevel): AlertColor => {
+ switch (status) {
+ case 'emergency':
+ case 'alert':
+ case 'critical':
+ case 'error':
+ return 'error';
+ case 'warning':
+ return 'warning';
+ case 'notice':
+ case 'info':
+ case 'debug':
+ return 'info';
+ }
+ return 'success';
+};
diff --git a/packages/yii-dev-panel-sdk/src/Helper/formatDate.ts b/packages/yii-dev-panel-sdk/src/Helper/formatDate.ts
index eecaecd2..9532c4f3 100644
--- a/packages/yii-dev-panel-sdk/src/Helper/formatDate.ts
+++ b/packages/yii-dev-panel-sdk/src/Helper/formatDate.ts
@@ -1,7 +1,7 @@
import {format, fromUnixTime} from 'date-fns';
export function formatDate(unixTimeStamp: number) {
- return format(fromUnixTime(unixTimeStamp), 'do MMM HH:mm:ss');
+ return format(unixTimeStamp, 'do MMM HH:mm:ss');
}
export function formatMicrotime(unixTimeStamp: number) {
@@ -12,7 +12,7 @@ export function formatMicrotime(unixTimeStamp: number) {
}
export function formatWithMicrotime(unixTimeStamp: number, dateFormat: string) {
const float = String(unixTimeStamp).split('.');
- return format(fromUnixTime(+float[0]), dateFormat) + (float.length === 2 ? '.' + float[1].padEnd(6, '0') : '');
+ return format(unixTimeStamp, dateFormat) + (float.length === 2 ? '.' + float[1].padEnd(6, '0') : '');
}
export function formatMillisecondsAsDuration(milliseconds: number) {
diff --git a/packages/yii-dev-panel-sdk/src/Types/logger.ts b/packages/yii-dev-panel-sdk/src/Types/logger.ts
new file mode 100644
index 00000000..b45cb142
--- /dev/null
+++ b/packages/yii-dev-panel-sdk/src/Types/logger.ts
@@ -0,0 +1 @@
+export type PhpLoggerLevel = 'emergency' | 'alert' | 'critical' | 'error' | 'warning' | 'notice' | 'info' | 'debug';
diff --git a/packages/yii-dev-panel/src/Application/Component/Layout.tsx b/packages/yii-dev-panel/src/Application/Component/Layout.tsx
index fe0a34ff..d0da1808 100644
--- a/packages/yii-dev-panel/src/Application/Component/Layout.tsx
+++ b/packages/yii-dev-panel/src/Application/Component/Layout.tsx
@@ -1,5 +1,6 @@
import {ContentCut, GitHub, Refresh} from '@mui/icons-material';
import AdbIcon from '@mui/icons-material/Adb';
+import InfoIcon from '@mui/icons-material/Info';
import {
CssBaseline,
IconButton,
@@ -179,9 +180,12 @@ export const Layout = React.memo(({children}: React.PropsWithChildren) => {
})}
-
+
+
+
+