@yargram/react 1.0.2 → 1.0.3
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.
- package/package.json +1 -1
- package/src/components/LogWindow/LogEntryRow.tsx +52 -4
- package/src/components/LogWindow/LogWindow.css +84 -4
- package/src/components/LogWindow/LogWindow.stories.tsx +57 -0
- package/src/components/LogWindow/LogWindow.tsx +30 -6
- package/src/components/LogWindow/index.ts +1 -0
- package/src/components/LogWindow/types.ts +4 -1
- package/src/contexts/YargramContext.tsx +18 -8
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { Info, AlertTriangle, CircleAlert } from 'lucide-react';
|
|
3
|
-
import type { LogEntry as LogEntryType, LogLevel } from './types';
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import { Info, AlertTriangle, CircleAlert, ChevronRight, ChevronDown } from 'lucide-react';
|
|
3
|
+
import type { LogEntry as LogEntryType, LogLevel, LogMessage } from './types';
|
|
4
4
|
import './LogWindow.css';
|
|
5
5
|
|
|
6
6
|
type LogEntryRowProps = {
|
|
@@ -13,6 +13,52 @@ const levelIcons: Record<LogLevel, React.ComponentType<{ size?: number | string;
|
|
|
13
13
|
error: CircleAlert,
|
|
14
14
|
};
|
|
15
15
|
|
|
16
|
+
function isExpandableMessage(msg: LogMessage): msg is Record<string, unknown> | unknown[] {
|
|
17
|
+
return typeof msg === 'object' && msg !== null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function getMessageSummary(msg: Record<string, unknown> | unknown[]): string {
|
|
21
|
+
if (Array.isArray(msg)) return `Array (${msg.length})`;
|
|
22
|
+
return `Object (${Object.keys(msg).length} keys)`;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
type LogEntryMessageProps = {
|
|
26
|
+
message: LogMessage;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
function LogEntryMessage({ message }: LogEntryMessageProps) {
|
|
30
|
+
const [expanded, setExpanded] = useState(false);
|
|
31
|
+
|
|
32
|
+
if (isExpandableMessage(message)) {
|
|
33
|
+
const summary = getMessageSummary(message);
|
|
34
|
+
return (
|
|
35
|
+
<div className="logWindowEntryAccordion">
|
|
36
|
+
<button
|
|
37
|
+
type="button"
|
|
38
|
+
className="logWindowEntryAccordionHeader"
|
|
39
|
+
onClick={() => setExpanded((e) => !e)}
|
|
40
|
+
aria-expanded={expanded}
|
|
41
|
+
>
|
|
42
|
+
<span className="logWindowEntryAccordionChevron">
|
|
43
|
+
{expanded ? <ChevronDown size={14} aria-hidden /> : <ChevronRight size={14} aria-hidden />}
|
|
44
|
+
</span>
|
|
45
|
+
<span className="logWindowEntryAccordionSummary">{summary}</span>
|
|
46
|
+
</button>
|
|
47
|
+
<div
|
|
48
|
+
className={`logWindowEntryAccordionBody ${expanded ? 'logWindowEntryAccordionBodyExpanded' : ''}`}
|
|
49
|
+
aria-hidden={!expanded}
|
|
50
|
+
>
|
|
51
|
+
<div className="logWindowEntryAccordionBodyInner">
|
|
52
|
+
<pre className="logWindowEntryAccordionPre">{JSON.stringify(message, null, 2)}</pre>
|
|
53
|
+
</div>
|
|
54
|
+
</div>
|
|
55
|
+
</div>
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const text = typeof message === 'string' ? message : String(message);
|
|
60
|
+
return <span className="logWindowEntryMessageText">{text}</span>;
|
|
61
|
+
}
|
|
16
62
|
|
|
17
63
|
export function LogEntryRow({ entry }: LogEntryRowProps) {
|
|
18
64
|
const levelClass = `logWindowEntry${entry.level.charAt(0).toUpperCase() + entry.level.slice(1)}` as
|
|
@@ -31,7 +77,9 @@ export function LogEntryRow({ entry }: LogEntryRowProps) {
|
|
|
31
77
|
<span className={`logWindowEntryIcon ${iconClass}`}>
|
|
32
78
|
<IconComponent size={12} />
|
|
33
79
|
</span>
|
|
34
|
-
<span className="logWindowEntryMessage">
|
|
80
|
+
<span className="logWindowEntryMessage">
|
|
81
|
+
<LogEntryMessage message={entry.message} />
|
|
82
|
+
</span>
|
|
35
83
|
<span className="logWindowEntrySource">{entry.source}</span>
|
|
36
84
|
</div>
|
|
37
85
|
);
|
|
@@ -396,10 +396,10 @@
|
|
|
396
396
|
|
|
397
397
|
.logWindowEntry {
|
|
398
398
|
display: flex;
|
|
399
|
-
align-items:
|
|
399
|
+
align-items: flex-start;
|
|
400
400
|
gap: 10px;
|
|
401
401
|
padding: 6px 14px;
|
|
402
|
-
min-height:
|
|
402
|
+
min-height: 13px;
|
|
403
403
|
color: var(--logw-text);
|
|
404
404
|
}
|
|
405
405
|
|
|
@@ -457,9 +457,89 @@
|
|
|
457
457
|
|
|
458
458
|
.logWindowEntryMessage {
|
|
459
459
|
flex: 1;
|
|
460
|
-
|
|
460
|
+
min-width: 0;
|
|
461
|
+
margin-top: 3px;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
.logWindowEntryMessageText {
|
|
465
|
+
white-space: pre-wrap;
|
|
466
|
+
word-break: break-word;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
/* Log entry accordion (object / array) */
|
|
470
|
+
.logWindowEntryAccordion {
|
|
471
|
+
width: 100%;
|
|
472
|
+
min-width: 0;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
.logWindowEntryAccordionHeader {
|
|
476
|
+
display: flex;
|
|
477
|
+
align-items: center;
|
|
478
|
+
gap: 6px;
|
|
479
|
+
width: 100%;
|
|
480
|
+
padding: 0;
|
|
481
|
+
margin: 0;
|
|
482
|
+
border: none;
|
|
483
|
+
background: transparent;
|
|
484
|
+
color: inherit;
|
|
485
|
+
font: inherit;
|
|
486
|
+
cursor: pointer;
|
|
487
|
+
text-align: left;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
.logWindowEntryAccordionHeader:hover {
|
|
491
|
+
background: rgba(255, 255, 255, 0.04);
|
|
492
|
+
border-radius: 4px;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
.logWindowEntryAccordionChevron {
|
|
496
|
+
display: inline-flex;
|
|
497
|
+
align-items: center;
|
|
498
|
+
justify-content: center;
|
|
499
|
+
flex-shrink: 0;
|
|
500
|
+
color: var(--logw-text-muted);
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
.logWindowEntryAccordionChevron svg {
|
|
504
|
+
width: 14px;
|
|
505
|
+
height: 14px;
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
.logWindowEntryAccordionSummary {
|
|
509
|
+
color: #ffffff;
|
|
510
|
+
font-size: 11px;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
.logWindowEntryAccordionBody {
|
|
514
|
+
display: grid;
|
|
515
|
+
grid-template-rows: 0fr;
|
|
516
|
+
transition: grid-template-rows 0.2s ease-out;
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
.logWindowEntryAccordionBodyExpanded {
|
|
520
|
+
grid-template-rows: 1fr;
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
.logWindowEntryAccordionBodyInner {
|
|
461
524
|
overflow: hidden;
|
|
462
|
-
|
|
525
|
+
min-height: 0;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
.logWindowEntryAccordionPre {
|
|
529
|
+
margin: 4px 0 0 20px;
|
|
530
|
+
padding: 8px 10px;
|
|
531
|
+
font-size: 11px;
|
|
532
|
+
line-height: 1.4;
|
|
533
|
+
color: var(--logw-text);
|
|
534
|
+
background: rgba(0, 0, 0, 0.25);
|
|
535
|
+
border-radius: 4px;
|
|
536
|
+
white-space: pre-wrap;
|
|
537
|
+
word-break: break-word;
|
|
538
|
+
font-family: ui-monospace, 'Cascadia Code', 'Source Code Pro', Menlo, monospace;
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
.logWindowEntryAccordionBody:not(.logWindowEntryAccordionBodyExpanded) .logWindowEntryAccordionPre {
|
|
542
|
+
opacity: 0;
|
|
463
543
|
}
|
|
464
544
|
|
|
465
545
|
.logWindowEntrySource {
|
|
@@ -137,12 +137,69 @@ export const ManyEntries: Story = {
|
|
|
137
137
|
},
|
|
138
138
|
};
|
|
139
139
|
|
|
140
|
+
/** 表示行数を 2 行に固定。スクロールで続きを表示 */
|
|
141
|
+
export const VisibleRows2: Story = {
|
|
142
|
+
args: {
|
|
143
|
+
entries: [
|
|
144
|
+
...sampleEntries,
|
|
145
|
+
{ id: '4', level: 'info', message: 'Fetching data...', source: 'useApi.ts:18' },
|
|
146
|
+
{ id: '5', level: 'warn', message: 'Deprecated API used', source: 'legacy.ts:3' },
|
|
147
|
+
],
|
|
148
|
+
visibleRows: 2,
|
|
149
|
+
},
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
/** 表示行数を 3 行に固定 */
|
|
153
|
+
export const VisibleRows3: Story = {
|
|
154
|
+
args: {
|
|
155
|
+
entries: [
|
|
156
|
+
...sampleEntries,
|
|
157
|
+
{ id: '4', level: 'info', message: 'Fetching data...', source: 'useApi.ts:18' },
|
|
158
|
+
],
|
|
159
|
+
visibleRows: 3,
|
|
160
|
+
},
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
/** 表示行数を任意の数(例: 5 行)に指定 */
|
|
164
|
+
export const VisibleRows5: Story = {
|
|
165
|
+
args: {
|
|
166
|
+
entries: [
|
|
167
|
+
...sampleEntries,
|
|
168
|
+
{ id: '4', level: 'info', message: 'Fetching data...', source: 'useApi.ts:18' },
|
|
169
|
+
{ id: '5', level: 'warn', message: 'Deprecated API used', source: 'legacy.ts:3' },
|
|
170
|
+
{ id: '6', level: 'error', message: 'Network request failed', source: 'api.ts:92' },
|
|
171
|
+
],
|
|
172
|
+
visibleRows: 5,
|
|
173
|
+
},
|
|
174
|
+
};
|
|
175
|
+
|
|
140
176
|
export const Empty: Story = {
|
|
141
177
|
args: {
|
|
142
178
|
entries: [],
|
|
143
179
|
},
|
|
144
180
|
};
|
|
145
181
|
|
|
182
|
+
/** 連想配列・配列はアコーディオンで展開・縮小表示 */
|
|
183
|
+
export const ObjectAndArrayMessages: Story = {
|
|
184
|
+
args: {
|
|
185
|
+
entries: [
|
|
186
|
+
{ id: '1', level: 'info', message: 'Plain string message', source: 'App.tsx:1' },
|
|
187
|
+
{
|
|
188
|
+
id: '2',
|
|
189
|
+
level: 'info',
|
|
190
|
+
message: { name: 'Alice', age: 30, tags: ['admin', 'user'] },
|
|
191
|
+
source: 'App.tsx:2',
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
id: '3',
|
|
195
|
+
level: 'warn',
|
|
196
|
+
message: [{ id: 1, title: 'First' }, { id: 2, title: 'Second' }],
|
|
197
|
+
source: 'App.tsx:3',
|
|
198
|
+
},
|
|
199
|
+
],
|
|
200
|
+
},
|
|
201
|
+
};
|
|
202
|
+
|
|
146
203
|
export const NetworksTab: Story = {
|
|
147
204
|
args: {
|
|
148
205
|
entries: sampleEntries,
|
|
@@ -32,6 +32,8 @@ export type LogWindowProps = {
|
|
|
32
32
|
onTabChange?: (tab: LogWindowTab) => void;
|
|
33
33
|
/** 高さ(CSS 値)。未指定時は max-height: 320px */
|
|
34
34
|
height?: string | number;
|
|
35
|
+
/** 表示する行数(2, 3 など)。指定時はボディ高さを行数に合わせる。height より優先 */
|
|
36
|
+
visibleRows?: number;
|
|
35
37
|
className?: string;
|
|
36
38
|
/** true のときヘッダーをドラッグしてウィンドウを移動できる */
|
|
37
39
|
draggable?: boolean;
|
|
@@ -56,6 +58,9 @@ export type LogWindowProps = {
|
|
|
56
58
|
};
|
|
57
59
|
|
|
58
60
|
const CLOSE_ANIMATION_MS = 200;
|
|
61
|
+
/** 1行あたりの高さ(.logWindowEntry の min-height 28px + padding 6*2) */
|
|
62
|
+
const LOG_ROW_HEIGHT_PX = 40;
|
|
63
|
+
const LOG_PANEL_PADDING_V = 16;
|
|
59
64
|
|
|
60
65
|
export function LogWindow({
|
|
61
66
|
entries = [],
|
|
@@ -63,6 +68,7 @@ export function LogWindow({
|
|
|
63
68
|
defaultTab = 'logs',
|
|
64
69
|
onTabChange,
|
|
65
70
|
height,
|
|
71
|
+
visibleRows,
|
|
66
72
|
className = '',
|
|
67
73
|
draggable = false,
|
|
68
74
|
defaultPosition,
|
|
@@ -83,6 +89,8 @@ export function LogWindow({
|
|
|
83
89
|
const closeTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
|
84
90
|
const prevEntriesLengthRef = useRef(entries.length);
|
|
85
91
|
const prevNetworkEntriesLengthRef = useRef(networkEntries.length);
|
|
92
|
+
const logsPanelRef = useRef<HTMLDivElement>(null);
|
|
93
|
+
const networksPanelRef = useRef<HTMLDivElement>(null);
|
|
86
94
|
const [position, setPosition] = useState<{ x: number; y: number }>(() =>
|
|
87
95
|
draggable ? defaultPosition ?? { x: 100, y: 100 } : { x: 0, y: 0 }
|
|
88
96
|
);
|
|
@@ -101,6 +109,16 @@ export function LogWindow({
|
|
|
101
109
|
prevNetworkEntriesLengthRef.current = networkEntries.length;
|
|
102
110
|
}, [entries.length, networkEntries.length, activeTab]);
|
|
103
111
|
|
|
112
|
+
useEffect(() => {
|
|
113
|
+
const el = logsPanelRef.current;
|
|
114
|
+
if (el) el.scrollTop = el.scrollHeight;
|
|
115
|
+
}, [entries.length]);
|
|
116
|
+
|
|
117
|
+
useEffect(() => {
|
|
118
|
+
const el = networksPanelRef.current;
|
|
119
|
+
if (el) el.scrollTop = el.scrollHeight;
|
|
120
|
+
}, [networkEntries.length]);
|
|
121
|
+
|
|
104
122
|
const handleTab = (tab: LogWindowTab) => {
|
|
105
123
|
setActiveTab(tab);
|
|
106
124
|
if (tab === 'logs') setUnreadLogsCount(0);
|
|
@@ -162,9 +180,10 @@ export function LogWindow({
|
|
|
162
180
|
|
|
163
181
|
const handleExportCsv = useCallback(() => {
|
|
164
182
|
const header = 'level,message,source\n';
|
|
165
|
-
const rows = entries.map((e) =>
|
|
166
|
-
|
|
167
|
-
|
|
183
|
+
const rows = entries.map((e) => {
|
|
184
|
+
const msgStr = typeof e.message === 'string' ? e.message : JSON.stringify(e.message);
|
|
185
|
+
return [e.level, escapeCsvCell(msgStr), escapeCsvCell(e.source)].join(',');
|
|
186
|
+
});
|
|
168
187
|
const csv = header + rows.join('\n');
|
|
169
188
|
const blob = new Blob([csv], { type: 'text/csv;charset=utf-8' });
|
|
170
189
|
downloadBlob(blob, `logs-${Date.now()}.csv`);
|
|
@@ -179,7 +198,12 @@ export function LogWindow({
|
|
|
179
198
|
setExportDialogOpen(false);
|
|
180
199
|
}, [entries, networkEntries]);
|
|
181
200
|
|
|
182
|
-
const bodyStyle
|
|
201
|
+
const bodyStyle: React.CSSProperties | undefined =
|
|
202
|
+
visibleRows != null
|
|
203
|
+
? { maxHeight: visibleRows * LOG_ROW_HEIGHT_PX + LOG_PANEL_PADDING_V }
|
|
204
|
+
: height != null
|
|
205
|
+
? { maxHeight: typeof height === 'number' ? `${height}px` : height }
|
|
206
|
+
: undefined;
|
|
183
207
|
|
|
184
208
|
const rootStyle: React.CSSProperties | undefined = draggable
|
|
185
209
|
? {
|
|
@@ -300,12 +324,12 @@ export function LogWindow({
|
|
|
300
324
|
transform: activeTab === 'logs' ? 'translateX(0)' : 'translateX(-50%)',
|
|
301
325
|
}}
|
|
302
326
|
>
|
|
303
|
-
<div className="logWindowBodyPanel">
|
|
327
|
+
<div ref={logsPanelRef} className="logWindowBodyPanel">
|
|
304
328
|
{entries.map((entry) => (
|
|
305
329
|
<LogEntryRow key={entry.id} entry={entry} />
|
|
306
330
|
))}
|
|
307
331
|
</div>
|
|
308
|
-
<div className="logWindowBodyPanel">
|
|
332
|
+
<div ref={networksPanelRef} className="logWindowBodyPanel">
|
|
309
333
|
{networkEntries.length > 0 ? (
|
|
310
334
|
networkEntries.map((entry) => (
|
|
311
335
|
<NetworkEntryRow key={entry.id} entry={entry} />
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
export type LogLevel = 'info' | 'warn' | 'error';
|
|
2
2
|
|
|
3
|
+
/** ログメッセージ(文字列のほか、連想配列・配列の場合はアコーディオンで展開表示) */
|
|
4
|
+
export type LogMessage = string | Record<string, unknown> | unknown[];
|
|
5
|
+
|
|
3
6
|
export type LogEntry = {
|
|
4
7
|
id: string;
|
|
5
8
|
level: LogLevel;
|
|
6
|
-
message:
|
|
9
|
+
message: LogMessage;
|
|
7
10
|
source: string;
|
|
8
11
|
};
|
|
9
12
|
|
|
@@ -21,7 +21,7 @@ import type { RestApiContextValue, GraphqlApiContextValue } from './ApiContext';
|
|
|
21
21
|
import { PrinterProvider } from './PrinterContext';
|
|
22
22
|
import { useLogWindowShortcut } from '../hooks/useLogWindowShortcut';
|
|
23
23
|
import { LogWindow } from '../components/LogWindow/LogWindow';
|
|
24
|
-
import type { LogEntry, NetworkEntry } from '../components/LogWindow/types';
|
|
24
|
+
import type { LogEntry, LogMessage, NetworkEntry } from '../components/LogWindow/types';
|
|
25
25
|
import type { Env } from '@yargram/core';
|
|
26
26
|
import type {
|
|
27
27
|
ApolloClient as ApolloClientType,
|
|
@@ -174,7 +174,10 @@ type YargramPrinterConfig = {
|
|
|
174
174
|
};
|
|
175
175
|
|
|
176
176
|
/** LogWindow 設定(Escape 5 回で表示) */
|
|
177
|
-
type YargramLogWindowConfig =
|
|
177
|
+
type YargramLogWindowConfig = {
|
|
178
|
+
/** 表示する行数(2, 3 など)。未指定時はウィンドウのデフォルト高さ */
|
|
179
|
+
visibleRows?: number;
|
|
180
|
+
};
|
|
178
181
|
|
|
179
182
|
/** 認証設定。本番のみログインを要求する場合は true、カスタム時はオブジェクト */
|
|
180
183
|
type YargramAuthConfig =
|
|
@@ -246,6 +249,7 @@ function LogWindowGate({
|
|
|
246
249
|
networkEntries,
|
|
247
250
|
isLogWindowOpen,
|
|
248
251
|
closeLogWindow,
|
|
252
|
+
logWindowConfig,
|
|
249
253
|
}: {
|
|
250
254
|
instanceId: string;
|
|
251
255
|
defaultPosition: { x: number; y: number };
|
|
@@ -259,6 +263,7 @@ function LogWindowGate({
|
|
|
259
263
|
networkEntries: NetworkEntry[];
|
|
260
264
|
isLogWindowOpen: boolean;
|
|
261
265
|
closeLogWindow: () => void;
|
|
266
|
+
logWindowConfig?: YargramLogWindowConfig;
|
|
262
267
|
}) {
|
|
263
268
|
if (!isLogWindowOpen || typeof document === 'undefined') {
|
|
264
269
|
return null;
|
|
@@ -269,6 +274,7 @@ function LogWindowGate({
|
|
|
269
274
|
key={instanceId}
|
|
270
275
|
entries={logEntries}
|
|
271
276
|
networkEntries={networkEntries}
|
|
277
|
+
visibleRows={logWindowConfig?.visibleRows}
|
|
272
278
|
draggable
|
|
273
279
|
animateOnOpen
|
|
274
280
|
onClose={closeLogWindow}
|
|
@@ -389,17 +395,19 @@ export function YargramProvider({
|
|
|
389
395
|
|
|
390
396
|
const wrappedPrinter = useMemo(() => {
|
|
391
397
|
const base = createPrinter(env);
|
|
398
|
+
const toConsoleStr = (msg: LogMessage): string =>
|
|
399
|
+
typeof msg === 'string' ? msg : JSON.stringify(msg);
|
|
392
400
|
return {
|
|
393
|
-
info: (msg:
|
|
394
|
-
base.info(msg);
|
|
401
|
+
info: (msg: LogMessage) => {
|
|
402
|
+
base.info(toConsoleStr(msg));
|
|
395
403
|
addLogEntryRef.current({ level: 'info', message: msg, source: 'app' });
|
|
396
404
|
},
|
|
397
|
-
warn: (msg:
|
|
398
|
-
base.warn(msg);
|
|
405
|
+
warn: (msg: LogMessage) => {
|
|
406
|
+
base.warn(toConsoleStr(msg));
|
|
399
407
|
addLogEntryRef.current({ level: 'warn', message: msg, source: 'app' });
|
|
400
408
|
},
|
|
401
|
-
error: (msg:
|
|
402
|
-
base.error(msg);
|
|
409
|
+
error: (msg: LogMessage) => {
|
|
410
|
+
base.error(toConsoleStr(msg));
|
|
403
411
|
addLogEntryRef.current({ level: 'error', message: msg, source: 'app' });
|
|
404
412
|
},
|
|
405
413
|
};
|
|
@@ -624,6 +632,7 @@ export function YargramProvider({
|
|
|
624
632
|
key={instanceId}
|
|
625
633
|
entries={logEntries}
|
|
626
634
|
networkEntries={networkEntries}
|
|
635
|
+
visibleRows={logWindow?.visibleRows}
|
|
627
636
|
draggable
|
|
628
637
|
animateOnOpen
|
|
629
638
|
onClose={closeLogWindow}
|
|
@@ -657,6 +666,7 @@ export function YargramProvider({
|
|
|
657
666
|
networkEntries={networkEntries}
|
|
658
667
|
isLogWindowOpen={isLogWindowOpen}
|
|
659
668
|
closeLogWindow={closeLogWindow}
|
|
669
|
+
logWindowConfig={logWindow}
|
|
660
670
|
/>
|
|
661
671
|
</>
|
|
662
672
|
) : (
|