@railtownai/railtracks-visualizer 0.0.29 → 0.0.30
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/README.md +2 -0
- package/dist/cjs/index.js +51 -19
- package/dist/esm/index.js +52 -20
- package/dist/types/components/AgenticFlowVisualizer.d.ts +2 -0
- package/package.json +5 -3
package/README.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# RailTracks Visualizer
|
|
2
2
|
|
|
3
|
+
[](https://github.com/RailtownAI/railtracks-visualizer/actions/workflows/ci.yaml)
|
|
4
|
+
|
|
3
5
|
A React-based visualizer for RailTracks agentic flows
|
|
4
6
|
|
|
5
7
|
## 🚀 Quick Start
|
package/dist/cjs/index.js
CHANGED
|
@@ -16351,6 +16351,8 @@ const InputItemTextarea = styled(index$1)`
|
|
|
16351
16351
|
`;
|
|
16352
16352
|
|
|
16353
16353
|
const DEFAULT_COUNTUP_DURATION = 0.6;
|
|
16354
|
+
const DEFAULT_POPOVER_WIDTH = 350;
|
|
16355
|
+
const DEFAULT_POPOVER_HEIGHT = 500;
|
|
16354
16356
|
// Helper component for animating currency values
|
|
16355
16357
|
const CountUpCurrency = ({ value, prefix = "", suffix = "" })=>{
|
|
16356
16358
|
return /*#__PURE__*/ React.createElement(CountUp, {
|
|
@@ -16453,8 +16455,8 @@ const NodeDetailsPopover = ({ isVisible, onClose, nodeData, triggerRef })=>{
|
|
|
16453
16455
|
const rect = triggerRef.current.getBoundingClientRect();
|
|
16454
16456
|
const viewportWidth = window.innerWidth;
|
|
16455
16457
|
const viewportHeight = window.innerHeight;
|
|
16456
|
-
const popoverWidth =
|
|
16457
|
-
const popoverHeight =
|
|
16458
|
+
const popoverWidth = DEFAULT_POPOVER_WIDTH; // Match the width from styled component
|
|
16459
|
+
const popoverHeight = DEFAULT_POPOVER_HEIGHT; // Approximate max height
|
|
16458
16460
|
const gap = 12; // Gap between node and popover
|
|
16459
16461
|
// Check if the rect is valid (has non-zero dimensions and is in viewport)
|
|
16460
16462
|
const isValidRect = rect.width > 0 && rect.height > 0 && rect.top >= 0 && rect.left >= 0;
|
|
@@ -16702,8 +16704,8 @@ const PopoverPortal = styled.div`
|
|
|
16702
16704
|
pointer-events: none;
|
|
16703
16705
|
`;
|
|
16704
16706
|
const PopoverContent = styled.div`
|
|
16705
|
-
width:
|
|
16706
|
-
max-height:
|
|
16707
|
+
width: ${DEFAULT_POPOVER_WIDTH}px;
|
|
16708
|
+
max-height: ${DEFAULT_POPOVER_HEIGHT}px;
|
|
16707
16709
|
background-color: ${(props)=>props.theme?.colors?.background || "hsl(0 0% 100%)"};
|
|
16708
16710
|
border: 1px solid ${(props)=>props.theme?.colors?.border || "hsl(214.3 31.8% 91.4%)"};
|
|
16709
16711
|
border-radius: 0.5rem;
|
|
@@ -20149,7 +20151,6 @@ SheetDescription.displayName = Description.displayName;
|
|
|
20149
20151
|
}
|
|
20150
20152
|
// Lay out each tree, centered
|
|
20151
20153
|
// Calculate the starting position to center the entire layout in the container
|
|
20152
|
-
// Ensure we don't have negative startX which would cause rightward offset
|
|
20153
20154
|
const startX = Math.max(0, (containerWidth - totalWidth) / 2);
|
|
20154
20155
|
let xCursor = startX;
|
|
20155
20156
|
for (const root of roots){
|
|
@@ -20195,16 +20196,28 @@ const nodeTypes = {
|
|
|
20195
20196
|
Tool: Node$1,
|
|
20196
20197
|
Coordinator: Node$1
|
|
20197
20198
|
};
|
|
20198
|
-
const AgenticFlowVisualizer = ({ flowData: propFlowData, width = "
|
|
20199
|
+
const AgenticFlowVisualizer = ({ flowData: propFlowData, width = "100dvw", height = "100dvh", className = "", defaultZoom = 1, defaultPan = {
|
|
20199
20200
|
x: 0,
|
|
20200
20201
|
y: 0
|
|
20201
|
-
}, disableAutoFit = true, showTimeline = false, minNodeSpacing =
|
|
20202
|
+
}, disableAutoFit = true, defaultAutoFitDuration = 1000, defaultAutoFitDelay = 250, showTimeline = false, minNodeSpacing = 300, onInspect })=>{
|
|
20202
20203
|
const { theme, isDarkMode } = useTheme();
|
|
20203
20204
|
const themeColors = theme.colors;
|
|
20205
|
+
// Helper function to determine if we should apply minimum dimensions
|
|
20206
|
+
const shouldApplyMinDimensions = React.useCallback(()=>{
|
|
20207
|
+
const widthStr = typeof width === "string" ? width : `${width}px`;
|
|
20208
|
+
const heightStr = typeof height === "string" ? height : `${height}px`;
|
|
20209
|
+
// Don't apply minimum dimensions if using viewport units
|
|
20210
|
+
const hasViewportUnits = /\b\d*\.?\d+(vw|vh|vmin|vmax)\b/.test(widthStr) || /\b\d*\.?\d+(vw|vh|vmin|vmax)\b/.test(heightStr);
|
|
20211
|
+
return !hasViewportUnits;
|
|
20212
|
+
}, [
|
|
20213
|
+
width,
|
|
20214
|
+
height
|
|
20215
|
+
]);
|
|
20204
20216
|
// Use prop data directly, no hooks needed
|
|
20205
20217
|
const flowData = propFlowData;
|
|
20206
20218
|
// Show no data state if no flowData is available
|
|
20207
20219
|
if (!flowData) {
|
|
20220
|
+
const applyMinDimensions = shouldApplyMinDimensions();
|
|
20208
20221
|
return /*#__PURE__*/ React.createElement("div", {
|
|
20209
20222
|
style: {
|
|
20210
20223
|
width: typeof width === "number" ? `${width}px` : width,
|
|
@@ -20213,8 +20226,10 @@ const AgenticFlowVisualizer = ({ flowData: propFlowData, width = "100%", height
|
|
|
20213
20226
|
borderRadius: "8px",
|
|
20214
20227
|
background: themeColors.muted,
|
|
20215
20228
|
position: "relative",
|
|
20216
|
-
|
|
20217
|
-
|
|
20229
|
+
...applyMinDimensions && {
|
|
20230
|
+
minWidth: "800px",
|
|
20231
|
+
minHeight: "600px"
|
|
20232
|
+
},
|
|
20218
20233
|
display: "flex",
|
|
20219
20234
|
alignItems: "center",
|
|
20220
20235
|
justifyContent: "center"
|
|
@@ -20324,9 +20339,8 @@ const AgenticFlowVisualizer = ({ flowData: propFlowData, width = "100%", height
|
|
|
20324
20339
|
if (!flowData.nodes) {
|
|
20325
20340
|
return new Map();
|
|
20326
20341
|
}
|
|
20327
|
-
// Use container dimensions for centering
|
|
20328
|
-
|
|
20329
|
-
const containerWidth = Math.max(containerDimensions.width || 800, 1200);
|
|
20342
|
+
// Use actual container dimensions for proper centering
|
|
20343
|
+
const containerWidth = containerDimensions.width || 800;
|
|
20330
20344
|
return calculateAutoLayout(flowData.nodes, flowData.edges || [], {
|
|
20331
20345
|
minNodeSpacing,
|
|
20332
20346
|
containerWidth
|
|
@@ -20351,6 +20365,22 @@ const AgenticFlowVisualizer = ({ flowData: propFlowData, width = "100%", height
|
|
|
20351
20365
|
}, [
|
|
20352
20366
|
flowData.edges
|
|
20353
20367
|
]);
|
|
20368
|
+
const reactFlowInstance = useReactFlow();
|
|
20369
|
+
// Pan function that can be called by child components
|
|
20370
|
+
React.useCallback((direction, amount)=>{
|
|
20371
|
+
if (!reactFlowInstance) return;
|
|
20372
|
+
const currentViewport = reactFlowInstance.getViewport();
|
|
20373
|
+
const panAmount = direction === "right" ? amount : -amount;
|
|
20374
|
+
reactFlowInstance.setViewport({
|
|
20375
|
+
x: currentViewport.x - panAmount,
|
|
20376
|
+
y: currentViewport.y,
|
|
20377
|
+
zoom: currentViewport.zoom
|
|
20378
|
+
}, {
|
|
20379
|
+
duration: 300
|
|
20380
|
+
});
|
|
20381
|
+
}, [
|
|
20382
|
+
reactFlowInstance
|
|
20383
|
+
]);
|
|
20354
20384
|
// Convert flow data to ReactFlow format with step filtering
|
|
20355
20385
|
const nodes = React.useMemo(()=>{
|
|
20356
20386
|
const stepNodes = getNodesForStep(currentStep);
|
|
@@ -20461,7 +20491,6 @@ const AgenticFlowVisualizer = ({ flowData: propFlowData, width = "100%", height
|
|
|
20461
20491
|
y: svgP.y
|
|
20462
20492
|
};
|
|
20463
20493
|
};
|
|
20464
|
-
const reactFlowInstance = useReactFlow();
|
|
20465
20494
|
// Pan to hub node (most connected node) on initial load, unless disabled or custom settings provided
|
|
20466
20495
|
React.useEffect(()=>{
|
|
20467
20496
|
if (disableAutoFit || !reactFlowInstance || nodes.length === 0) {
|
|
@@ -20500,31 +20529,34 @@ const AgenticFlowVisualizer = ({ flowData: propFlowData, width = "100%", height
|
|
|
20500
20529
|
id: hubNodeId
|
|
20501
20530
|
}
|
|
20502
20531
|
],
|
|
20503
|
-
duration:
|
|
20532
|
+
duration: defaultAutoFitDuration,
|
|
20504
20533
|
padding: 0.2,
|
|
20505
20534
|
minZoom: defaultZoom,
|
|
20506
|
-
maxZoom:
|
|
20535
|
+
maxZoom: defaultZoom
|
|
20507
20536
|
});
|
|
20508
|
-
},
|
|
20537
|
+
}, defaultAutoFitDelay); // Small delay to ensure nodes are rendered
|
|
20509
20538
|
}
|
|
20510
20539
|
}, [
|
|
20511
20540
|
nodes,
|
|
20512
20541
|
edges,
|
|
20513
20542
|
reactFlowInstance,
|
|
20514
20543
|
disableAutoFit,
|
|
20515
|
-
defaultZoom
|
|
20544
|
+
defaultZoom,
|
|
20545
|
+
defaultAutoFitDuration,
|
|
20546
|
+
defaultAutoFitDelay
|
|
20516
20547
|
]);
|
|
20517
20548
|
return /*#__PURE__*/ React.createElement("div", {
|
|
20518
20549
|
ref: containerRef,
|
|
20519
20550
|
style: {
|
|
20520
20551
|
width: typeof width === "number" ? `${width}px` : width,
|
|
20521
20552
|
height: typeof height === "number" ? `${height}px` : height,
|
|
20553
|
+
minWidth: "800px",
|
|
20554
|
+
minHeight: "600px",
|
|
20555
|
+
boxSizing: "border-box",
|
|
20522
20556
|
border: `1px solid ${themeColors.border}`,
|
|
20523
20557
|
borderRadius: "8px",
|
|
20524
20558
|
overflow: "hidden",
|
|
20525
20559
|
position: "relative",
|
|
20526
|
-
minWidth: "800px",
|
|
20527
|
-
minHeight: "600px",
|
|
20528
20560
|
background: themeColors.background
|
|
20529
20561
|
},
|
|
20530
20562
|
className: className
|
package/dist/esm/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import React__default, { memo, useState, useCallback,
|
|
2
|
+
import React__default, { memo, useMemo, useState, useCallback, forwardRef, createContext, useContext, useRef, useLayoutEffect, useEffect, createElement } from 'react';
|
|
3
3
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
4
4
|
import * as ReactDOM from 'react-dom';
|
|
5
5
|
import ReactDOM__default, { createPortal } from 'react-dom';
|
|
@@ -16331,6 +16331,8 @@ const InputItemTextarea = styled(index$1)`
|
|
|
16331
16331
|
`;
|
|
16332
16332
|
|
|
16333
16333
|
const DEFAULT_COUNTUP_DURATION = 0.6;
|
|
16334
|
+
const DEFAULT_POPOVER_WIDTH = 350;
|
|
16335
|
+
const DEFAULT_POPOVER_HEIGHT = 500;
|
|
16334
16336
|
// Helper component for animating currency values
|
|
16335
16337
|
const CountUpCurrency = ({ value, prefix = "", suffix = "" })=>{
|
|
16336
16338
|
return /*#__PURE__*/ React__default.createElement(CountUp, {
|
|
@@ -16433,8 +16435,8 @@ const NodeDetailsPopover = ({ isVisible, onClose, nodeData, triggerRef })=>{
|
|
|
16433
16435
|
const rect = triggerRef.current.getBoundingClientRect();
|
|
16434
16436
|
const viewportWidth = window.innerWidth;
|
|
16435
16437
|
const viewportHeight = window.innerHeight;
|
|
16436
|
-
const popoverWidth =
|
|
16437
|
-
const popoverHeight =
|
|
16438
|
+
const popoverWidth = DEFAULT_POPOVER_WIDTH; // Match the width from styled component
|
|
16439
|
+
const popoverHeight = DEFAULT_POPOVER_HEIGHT; // Approximate max height
|
|
16438
16440
|
const gap = 12; // Gap between node and popover
|
|
16439
16441
|
// Check if the rect is valid (has non-zero dimensions and is in viewport)
|
|
16440
16442
|
const isValidRect = rect.width > 0 && rect.height > 0 && rect.top >= 0 && rect.left >= 0;
|
|
@@ -16682,8 +16684,8 @@ const PopoverPortal = styled.div`
|
|
|
16682
16684
|
pointer-events: none;
|
|
16683
16685
|
`;
|
|
16684
16686
|
const PopoverContent = styled.div`
|
|
16685
|
-
width:
|
|
16686
|
-
max-height:
|
|
16687
|
+
width: ${DEFAULT_POPOVER_WIDTH}px;
|
|
16688
|
+
max-height: ${DEFAULT_POPOVER_HEIGHT}px;
|
|
16687
16689
|
background-color: ${(props)=>props.theme?.colors?.background || "hsl(0 0% 100%)"};
|
|
16688
16690
|
border: 1px solid ${(props)=>props.theme?.colors?.border || "hsl(214.3 31.8% 91.4%)"};
|
|
16689
16691
|
border-radius: 0.5rem;
|
|
@@ -20129,7 +20131,6 @@ SheetDescription.displayName = Description.displayName;
|
|
|
20129
20131
|
}
|
|
20130
20132
|
// Lay out each tree, centered
|
|
20131
20133
|
// Calculate the starting position to center the entire layout in the container
|
|
20132
|
-
// Ensure we don't have negative startX which would cause rightward offset
|
|
20133
20134
|
const startX = Math.max(0, (containerWidth - totalWidth) / 2);
|
|
20134
20135
|
let xCursor = startX;
|
|
20135
20136
|
for (const root of roots){
|
|
@@ -20175,16 +20176,28 @@ const nodeTypes = {
|
|
|
20175
20176
|
Tool: Node$1,
|
|
20176
20177
|
Coordinator: Node$1
|
|
20177
20178
|
};
|
|
20178
|
-
const AgenticFlowVisualizer = ({ flowData: propFlowData, width = "
|
|
20179
|
+
const AgenticFlowVisualizer = ({ flowData: propFlowData, width = "100dvw", height = "100dvh", className = "", defaultZoom = 1, defaultPan = {
|
|
20179
20180
|
x: 0,
|
|
20180
20181
|
y: 0
|
|
20181
|
-
}, disableAutoFit = true, showTimeline = false, minNodeSpacing =
|
|
20182
|
+
}, disableAutoFit = true, defaultAutoFitDuration = 1000, defaultAutoFitDelay = 250, showTimeline = false, minNodeSpacing = 300, onInspect })=>{
|
|
20182
20183
|
const { theme, isDarkMode } = useTheme();
|
|
20183
20184
|
const themeColors = theme.colors;
|
|
20185
|
+
// Helper function to determine if we should apply minimum dimensions
|
|
20186
|
+
const shouldApplyMinDimensions = useCallback(()=>{
|
|
20187
|
+
const widthStr = typeof width === "string" ? width : `${width}px`;
|
|
20188
|
+
const heightStr = typeof height === "string" ? height : `${height}px`;
|
|
20189
|
+
// Don't apply minimum dimensions if using viewport units
|
|
20190
|
+
const hasViewportUnits = /\b\d*\.?\d+(vw|vh|vmin|vmax)\b/.test(widthStr) || /\b\d*\.?\d+(vw|vh|vmin|vmax)\b/.test(heightStr);
|
|
20191
|
+
return !hasViewportUnits;
|
|
20192
|
+
}, [
|
|
20193
|
+
width,
|
|
20194
|
+
height
|
|
20195
|
+
]);
|
|
20184
20196
|
// Use prop data directly, no hooks needed
|
|
20185
20197
|
const flowData = propFlowData;
|
|
20186
20198
|
// Show no data state if no flowData is available
|
|
20187
20199
|
if (!flowData) {
|
|
20200
|
+
const applyMinDimensions = shouldApplyMinDimensions();
|
|
20188
20201
|
return /*#__PURE__*/ React__default.createElement("div", {
|
|
20189
20202
|
style: {
|
|
20190
20203
|
width: typeof width === "number" ? `${width}px` : width,
|
|
@@ -20193,8 +20206,10 @@ const AgenticFlowVisualizer = ({ flowData: propFlowData, width = "100%", height
|
|
|
20193
20206
|
borderRadius: "8px",
|
|
20194
20207
|
background: themeColors.muted,
|
|
20195
20208
|
position: "relative",
|
|
20196
|
-
|
|
20197
|
-
|
|
20209
|
+
...applyMinDimensions && {
|
|
20210
|
+
minWidth: "800px",
|
|
20211
|
+
minHeight: "600px"
|
|
20212
|
+
},
|
|
20198
20213
|
display: "flex",
|
|
20199
20214
|
alignItems: "center",
|
|
20200
20215
|
justifyContent: "center"
|
|
@@ -20304,9 +20319,8 @@ const AgenticFlowVisualizer = ({ flowData: propFlowData, width = "100%", height
|
|
|
20304
20319
|
if (!flowData.nodes) {
|
|
20305
20320
|
return new Map();
|
|
20306
20321
|
}
|
|
20307
|
-
// Use container dimensions for centering
|
|
20308
|
-
|
|
20309
|
-
const containerWidth = Math.max(containerDimensions.width || 800, 1200);
|
|
20322
|
+
// Use actual container dimensions for proper centering
|
|
20323
|
+
const containerWidth = containerDimensions.width || 800;
|
|
20310
20324
|
return calculateAutoLayout(flowData.nodes, flowData.edges || [], {
|
|
20311
20325
|
minNodeSpacing,
|
|
20312
20326
|
containerWidth
|
|
@@ -20331,6 +20345,22 @@ const AgenticFlowVisualizer = ({ flowData: propFlowData, width = "100%", height
|
|
|
20331
20345
|
}, [
|
|
20332
20346
|
flowData.edges
|
|
20333
20347
|
]);
|
|
20348
|
+
const reactFlowInstance = useReactFlow();
|
|
20349
|
+
// Pan function that can be called by child components
|
|
20350
|
+
useCallback((direction, amount)=>{
|
|
20351
|
+
if (!reactFlowInstance) return;
|
|
20352
|
+
const currentViewport = reactFlowInstance.getViewport();
|
|
20353
|
+
const panAmount = direction === "right" ? amount : -amount;
|
|
20354
|
+
reactFlowInstance.setViewport({
|
|
20355
|
+
x: currentViewport.x - panAmount,
|
|
20356
|
+
y: currentViewport.y,
|
|
20357
|
+
zoom: currentViewport.zoom
|
|
20358
|
+
}, {
|
|
20359
|
+
duration: 300
|
|
20360
|
+
});
|
|
20361
|
+
}, [
|
|
20362
|
+
reactFlowInstance
|
|
20363
|
+
]);
|
|
20334
20364
|
// Convert flow data to ReactFlow format with step filtering
|
|
20335
20365
|
const nodes = useMemo(()=>{
|
|
20336
20366
|
const stepNodes = getNodesForStep(currentStep);
|
|
@@ -20441,7 +20471,6 @@ const AgenticFlowVisualizer = ({ flowData: propFlowData, width = "100%", height
|
|
|
20441
20471
|
y: svgP.y
|
|
20442
20472
|
};
|
|
20443
20473
|
};
|
|
20444
|
-
const reactFlowInstance = useReactFlow();
|
|
20445
20474
|
// Pan to hub node (most connected node) on initial load, unless disabled or custom settings provided
|
|
20446
20475
|
useEffect(()=>{
|
|
20447
20476
|
if (disableAutoFit || !reactFlowInstance || nodes.length === 0) {
|
|
@@ -20480,31 +20509,34 @@ const AgenticFlowVisualizer = ({ flowData: propFlowData, width = "100%", height
|
|
|
20480
20509
|
id: hubNodeId
|
|
20481
20510
|
}
|
|
20482
20511
|
],
|
|
20483
|
-
duration:
|
|
20512
|
+
duration: defaultAutoFitDuration,
|
|
20484
20513
|
padding: 0.2,
|
|
20485
20514
|
minZoom: defaultZoom,
|
|
20486
|
-
maxZoom:
|
|
20515
|
+
maxZoom: defaultZoom
|
|
20487
20516
|
});
|
|
20488
|
-
},
|
|
20517
|
+
}, defaultAutoFitDelay); // Small delay to ensure nodes are rendered
|
|
20489
20518
|
}
|
|
20490
20519
|
}, [
|
|
20491
20520
|
nodes,
|
|
20492
20521
|
edges,
|
|
20493
20522
|
reactFlowInstance,
|
|
20494
20523
|
disableAutoFit,
|
|
20495
|
-
defaultZoom
|
|
20524
|
+
defaultZoom,
|
|
20525
|
+
defaultAutoFitDuration,
|
|
20526
|
+
defaultAutoFitDelay
|
|
20496
20527
|
]);
|
|
20497
20528
|
return /*#__PURE__*/ React__default.createElement("div", {
|
|
20498
20529
|
ref: containerRef,
|
|
20499
20530
|
style: {
|
|
20500
20531
|
width: typeof width === "number" ? `${width}px` : width,
|
|
20501
20532
|
height: typeof height === "number" ? `${height}px` : height,
|
|
20533
|
+
minWidth: "800px",
|
|
20534
|
+
minHeight: "600px",
|
|
20535
|
+
boxSizing: "border-box",
|
|
20502
20536
|
border: `1px solid ${themeColors.border}`,
|
|
20503
20537
|
borderRadius: "8px",
|
|
20504
20538
|
overflow: "hidden",
|
|
20505
20539
|
position: "relative",
|
|
20506
|
-
minWidth: "800px",
|
|
20507
|
-
minHeight: "600px",
|
|
20508
20540
|
background: themeColors.background
|
|
20509
20541
|
},
|
|
20510
20542
|
className: className
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@railtownai/railtracks-visualizer",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.30",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"author": "Railtown AI",
|
|
6
6
|
"description": "A visualizer for RailTracks agentic flows",
|
|
@@ -53,18 +53,19 @@
|
|
|
53
53
|
},
|
|
54
54
|
"scripts": {
|
|
55
55
|
"build:lib": "rollup -c",
|
|
56
|
+
"build:size": "npm pack --dry-run",
|
|
56
57
|
"build:spa": "vite build",
|
|
57
58
|
"build:types": "tsc -p tsconfig.types.json",
|
|
58
|
-
"build:size": "npm pack --dry-run",
|
|
59
59
|
"build": "npm run build:types && npm run build:lib && npm run build:spa",
|
|
60
60
|
"clean": "rm -rf dist build test-results .railtracks/ui/*",
|
|
61
61
|
"dev": "rm -rf .railtracks/ui/* && vite build && cp -r build/* .railtracks/ui",
|
|
62
62
|
"lint:fix": "prettier --write \"src/**/*.{js,jsx,ts,tsx,json,css,md}\"",
|
|
63
|
+
"lint:license": "license-checker --summary --excludePrivatePackages --failOn 'AGPL-1.0;AGPL-3.0;EPL-1.0;EPL-2.0;GPL-1.0;GPL-2.0;GPL-3.0;LGPL-2.0;LGPL-2.1;LGPL-3.0;'",
|
|
63
64
|
"lint": "prettier --check \"src/**/*.{js,jsx,ts,tsx,json,css,md}\"",
|
|
64
65
|
"start": "storybook dev -p 6006",
|
|
65
66
|
"storybook:build": "cross-env NODE_ENV=production storybook build",
|
|
66
|
-
"storybook:preview": "npx http-server ./storybook-static",
|
|
67
67
|
"storybook:deploy": "gh-pages -d storybook-static",
|
|
68
|
+
"storybook:preview": "npx http-server ./storybook-static",
|
|
68
69
|
"test:ui": "vitest --ui",
|
|
69
70
|
"test": "vitest run --silent",
|
|
70
71
|
"up": "ncu -u -x react -x react-dom -x @types/react -x @types/react-dom && npm install"
|
|
@@ -95,6 +96,7 @@
|
|
|
95
96
|
"cross-env": "^10.0.0",
|
|
96
97
|
"gh-pages": "6.3.0",
|
|
97
98
|
"jsdom": "26.1.0",
|
|
99
|
+
"license-checker": "25.0.1",
|
|
98
100
|
"npm-check-updates": "18.1.0",
|
|
99
101
|
"playwright": "^1.55.0",
|
|
100
102
|
"prettier": "3.6.2",
|