Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
7ac84b2
Add vertical orientation and icon-only mode to SegmentGroup
kube Apr 1, 2026
f4a6d54
Add basic simulate mode view and enable mode switching
kube Apr 2, 2026
eb5c06e
Add Scenario type, Drawer component, and Create Scenario UI
kube Apr 3, 2026
d80f035
Add showAsInitialState property to Place
kube Apr 3, 2026
49ee066
Extract shared scenario form and add View Scenario drawer
kube Apr 3, 2026
adbb0b0
Add LSP support for scenario expression editors
kube Apr 12, 2026
bdbfa5f
Move simulation error display from Settings to Diagnostics tab
kube Apr 12, 2026
ba91af4
Make parameters list scrollable in simulation settings
kube Apr 12, 2026
c58c320
Add scenario picker and Metrics section to Simulation Settings
kube Apr 13, 2026
46ff8f6
Prevent scrolling in single-line CodeEditor
kube Apr 13, 2026
16c4b02
Expose scenario parameters via `scenario` object in LSP
kube Apr 13, 2026
b333f9a
Wire scenario form to TanStack Form with LSP-gated submit
kube Apr 13, 2026
bc4adfa
Lint scenario expressions only when relevant
kube Apr 13, 2026
87260f6
Validate scenario name and parameter identifiers
kube Apr 13, 2026
3f2c6d3
Widen drawer with viewport-aware max width
kube Apr 13, 2026
a4011e3
Persist scenarios via Create/Save with Zod validation
kube Apr 14, 2026
339e763
Store selected scenario in SimulationContext
kube Apr 14, 2026
8506982
Add scenario expression compiler and wire into SimulationContext
kube Apr 14, 2026
39cc172
Add Create Scenario button to Simulation Settings
kube Apr 14, 2026
65b6688
Add Edit Scenario button and remove icon button gap
kube Apr 14, 2026
50cdd2a
Reduce gap
kube Apr 14, 2026
4de5e57
Override context params/marking from compiled scenario and polish picker
kube Apr 14, 2026
8656ec7
Remove Metrics section from Simulation Settings
kube Apr 14, 2026
1327ca1
Add Metrics tab and disable Metrics/Experiments in Simulate view
kube Apr 14, 2026
de07794
Update Positioner zIndex
kube Apr 14, 2026
08152ea
Refactor initialState to discriminated union, support colored places
kube Apr 14, 2026
d13a212
Rename Earth to Planet in satellite examples and simplify scenarios
kube Apr 14, 2026
4ccd2d9
Flag RawMaterial and AvailableMachines as initial state in Production…
kube Apr 14, 2026
37a72f8
Add ratio param type, code-mode compilation, and UI polish
kube Apr 14, 2026
e8db409
Show read-only spreadsheet for colored places when scenario is active
kube Apr 14, 2026
1325374
Add "All Around the World" scenario to Satellites example
kube Apr 14, 2026
ae12462
Fix satellite velocity arrow disappearing for negative velocities
kube Apr 14, 2026
d15b23f
Reduce parameter label weight in scenario form
kube Apr 14, 2026
893323b
Add changeset
kube Apr 14, 2026
9c45baa
Replace initial-state switch with checkbox in place properties
kube Apr 15, 2026
8ba40ab
Clarify default-starting-place hint text
kube Apr 15, 2026
b1fa3e5
Add inline validation and empty-state hints to scenario form
kube Apr 15, 2026
1224c70
Cap simulation-settings parameter row width
kube Apr 15, 2026
eeef0e5
Fix petrinaut lint and typecheck errors
kube Apr 15, 2026
7621ec1
Externalise use-sync-external-store in petrinaut lib build
kube Apr 15, 2026
b43a945
Rework Satellites Launcher scenarios around user-tweakable params
kube Apr 15, 2026
183e681
Rename satellites scenario params and put launch_rate first
kube Apr 15, 2026
c7bdaa0
Fix stale scenario param refs in satellite parameterOverrides
kube Apr 15, 2026
b420fa8
Close .constructor-chain escape in scenario expression sandbox
kube Apr 15, 2026
00d7c3b
Add Default Production scenario to Production Machines
kube Apr 15, 2026
f1560c4
Disable scenario picker while simulation is active
kube Apr 15, 2026
8199aa8
Auto-snakify scenario parameter identifier on blur
kube Apr 15, 2026
265f689
Use Switch for boolean scenario param default, fix NumberInput steps
kube Apr 16, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/warm-scenarios-shine.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@hashintel/petrinaut": patch
---

Add Scenarios: reusable simulation configurations with parameter overrides and initial state expressions
1 change: 1 addition & 0 deletions libs/@hashintel/petrinaut/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
"@hashintel/ds-helpers": "workspace:^",
"@hashintel/refractive": "workspace:^",
"@monaco-editor/react": "4.8.0-rc.3",
"@tanstack/react-form": "1.29.0",
"@xyflow/react": "12.10.1",
"elkjs": "0.11.0",
"fuzzysort": "3.1.0",
Expand Down
8 changes: 8 additions & 0 deletions libs/@hashintel/petrinaut/panda.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,14 @@ export default defineConfig({
from: { opacity: "1", transform: "scale(1)" },
to: { opacity: "0", transform: "scale(0.96)" },
},
"drawer-in": {
from: { opacity: "0", transform: "translateX(100px)" },
to: { opacity: "1", transform: "translateX(0)" },
},
"drawer-out": {
from: { opacity: "1", transform: "translateX(0)" },
to: { opacity: "0", transform: "translateX(100px)" },
},
},
},
},
Expand Down
168 changes: 22 additions & 146 deletions libs/@hashintel/petrinaut/src/components/dialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,16 @@ import type { ComponentProps, ReactNode } from "react";
import { TbX } from "react-icons/tb";

import { usePortalContainerRef } from "../state/portal-container-context";
import {
Body,
Card as PanelCard,
closeButtonStyle,
Footer,
Header as PanelHeader,
outerStyle,
} from "./panel-primitives";

// -- Styles ------------------------------------------------------------------
// -- Dialog-specific styles ---------------------------------------------------

const backdropStyle = css({
position: "fixed",
Expand Down Expand Up @@ -37,21 +45,10 @@ const positionerStyle = css({
zIndex: "sticky",
});

/** Outer gray container β€” matches Figma "size=sm, glass=false" frame. */
const outerStyle = css({
backgroundColor: "neutral.s10",
borderRadius: "2xl",
padding: "1",
display: "flex",
flexDirection: "column",
gap: "1",
const dialogOuterStyle = css({
maxWidth: "[400px]",
width: "[90vw]",
maxHeight: "[85vh]",
overflow: "clip",
userSelect: "none",
boxShadow:
"[0px 0px 1px 0px rgba(0,0,0,0.02), 0px 1px 1px -0.5px rgba(0,0,0,0.04), 0px 6px 6px -3px rgba(0,0,0,0.04), 0px 12px 12px -6px rgba(0,0,0,0.03), 0px 24px 24px -12px rgba(0,0,0,0.02)]",
"&[data-state=open]": {
animation: "dialogContentIn 150ms ease-out",
},
Expand All @@ -60,94 +57,8 @@ const outerStyle = css({
},
});

/** Inner white card that holds header + body. */
const cardStyle = css({
position: "relative",
backgroundColor: "neutral.s00",
borderRadius: "xl",
boxShadow:
"[0px 0px 0px 1px rgba(0,0,0,0.08), 0px 12px 32px 0px rgba(0,0,0,0.02)]",
overflow: "clip",
display: "flex",
flexDirection: "column",
width: "full",
zIndex: "[2]",
flex: "[1 1 auto]",
minHeight: "[0]",
});

const closeButtonStyle = css({
position: "absolute",
top: "2",
right: "2",
display: "flex",
alignItems: "center",
justifyContent: "center",
width: "[30px]",
height: "[30px]",
fontSize: "base",
color: "neutral.s100",
backgroundColor: "[transparent]",
border: "none",
borderRadius: "lg",
cursor: "pointer",
zIndex: "[3]",
_hover: {
backgroundColor: "neutral.bg.min.hover",
},
});

const headerStyle = css({
display: "flex",
flexDirection: "column",
gap: "1",
paddingX: "5",
paddingTop: "4",
paddingBottom: "4",
paddingRight: "[46px]",
borderBottom: "[1px solid {colors.neutral.a10}]",
flexShrink: "[0]",
});

const titleStyle = css({
fontSize: "lg",
fontWeight: "semibold",
lineHeight: "[20px]",
color: "neutral.fg.heading",
margin: "[0]",
});

const descriptionStyle = css({
fontSize: "sm",
fontWeight: "medium",
lineHeight: "[1.25]",
color: "neutral.s90",
margin: "[0]",
});

const bodyStyle = css({
padding: "5",
overflowY: "auto",
flex: "[1]",
});

const footerStyle = css({
display: "flex",
alignItems: "center",
justifyContent: "flex-end",
gap: "2",
paddingX: "4",
paddingY: "3",
flexShrink: "[0]",
zIndex: "[1]",
});

// -- Subcomponents -----------------------------------------------------------

/**
* Dialog content portalled into the shared .petrinaut-root container.
* Renders the outer gray frame that wraps both the Card and Footer.
*/
const Content = ({
children,
className,
Expand All @@ -161,70 +72,35 @@ const Content = ({
<Portal container={portalContainerRef}>
<ArkDialog.Backdrop className={backdropStyle} />
<ArkDialog.Positioner className={positionerStyle}>
<ArkDialog.Content className={cx(outerStyle, className)}>
<ArkDialog.Content
className={cx(outerStyle, dialogOuterStyle, className)}
>
{children}
</ArkDialog.Content>
</ArkDialog.Positioner>
</Portal>
);
};

/**
* Inner white card that holds Header + Body.
* Includes an absolute-positioned close button in the top-right corner.
*/
const Card = ({ children }: { children: ReactNode }) => (
<div className={cardStyle}>
<PanelCard
closeButton={
<ArkDialog.CloseTrigger className={closeButtonStyle} aria-label="Close">
<TbX />
</ArkDialog.CloseTrigger>
}
>
{children}
<ArkDialog.CloseTrigger className={closeButtonStyle} aria-label="Close">
<TbX />
</ArkDialog.CloseTrigger>
</div>
</PanelCard>
);

/**
* Dialog header with title and optional description.
* Sits inside Card, has a subtle bottom border.
*/
const Header = ({
children,
description,
}: {
children: ReactNode;
description?: ReactNode;
}) => (
<div className={headerStyle}>
<ArkDialog.Title className={titleStyle}>{children}</ArkDialog.Title>
{description != null && (
<ArkDialog.Description className={descriptionStyle}>
{description}
</ArkDialog.Description>
)}
</div>
);

/**
* Scrollable body area inside the Card.
*/
const Body = ({
children,
className,
}: {
children: ReactNode;
className?: string;
}) => <div className={cx(bodyStyle, className)}>{children}</div>;

/**
* Footer area for action buttons. Sits outside the Card,
* in the outer gray frame.
*/
const Footer = ({
children,
className,
}: {
children: ReactNode;
className?: string;
}) => <div className={cx(footerStyle, className)}>{children}</div>;
}) => <PanelHeader description={description}>{children}</PanelHeader>;
Comment thread
kube marked this conversation as resolved.
Comment thread
kube marked this conversation as resolved.

// -- Compound export ---------------------------------------------------------

Expand Down
Loading
Loading