Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
155 changes: 43 additions & 112 deletions src/components/ValidationButton.tsx
Original file line number Diff line number Diff line change
@@ -1,149 +1,80 @@
import { DeveloperService } from "../spicedb-common/services/developerservice";
import Button from "@material-ui/core/Button";
import { Theme, createStyles, makeStyles } from "@material-ui/core/styles";
import { alpha } from "@material-ui/core/styles/colorManipulator";
import CheckCircleIcon from "@material-ui/icons/CheckCircle";
import CheckCircleOutlineIcon from "@material-ui/icons/CheckCircleOutline";
import ErrorIcon from "@material-ui/icons/Error";
import PlayCircleFilledIcon from "@material-ui/icons/PlayCircleFilled";
import clsx from "clsx";
import "react-reflex/styles.css";
import { Button } from "./ui/button";
import { DataStore } from "../services/datastore";
import { ValidationState, ValidationStatus } from "../services/validation";
import { TourElementClass } from "./GuidedTour";
import { CheckCircle, CircleX, CirclePlay } from "lucide-react";

const useStyles = makeStyles((theme: Theme) =>
createStyles({
gcm: {
color: "green",
display: "inherit",
},
rem: {
color: "red",
display: "inherit",
},
gray: {
color: "gray",
display: "inherit",
},
lastRun: {
display: "grid",
gridTemplateColumns: "auto 150px",
alignItems: "center",
columnGap: theme.spacing(1),
backgroundColor: "rgba(255, 255, 255, 0.05)",
height: "100%",
padding: "4px",
paddingLeft: "8px",
},
validated: {
backgroundColor: alpha(theme.palette.success.light, 0.2),
},
validationError: {
backgroundColor: alpha(theme.palette.error.light, 0.2),
},
validationDisplay: {
display: "grid",
gridTemplateColumns: "auto auto",
alignItems: "center",
columnGap: theme.spacing(1),
},
}),
);

export function ValidateButton(props: {
export function ValidateButton({
conductValidation,
datastore,
validationState,
developerService,
}: {
conductValidation: () => void;
datastore: DataStore;
validationState: ValidationState;
developerService: DeveloperService;
}) {
const validated =
props.validationState.status === ValidationStatus.VALIDATED ||
props.validationState.status === ValidationStatus.VALIDATION_ERROR;
const upToDate =
validated &&
props.validationState.validationDatastoreIndex ===
props.datastore.currentIndex();

const classes = useStyles();
validationState.validationDatastoreIndex === datastore.currentIndex();
const valid =
upToDate && validationState.status === ValidationStatus.VALIDATED;
const invalid =
upToDate && validationState.status === ValidationStatus.VALIDATION_ERROR;
const loading = validationState.status === ValidationStatus.CALL_ERROR;
const notRun =
validationState.status !== ValidationStatus.CALL_ERROR && !upToDate;

return (
<div className={classes.validationDisplay}>
<div
className={clsx(classes.lastRun, {
[classes.validated]:
upToDate &&
props.validationState.status === ValidationStatus.VALIDATED,
[classes.validationError]:
upToDate &&
props.validationState.status === ValidationStatus.VALIDATION_ERROR,
})}
>
<div className="flex flex-row justify-between">
<div className="flex flex-row px-3 mr-2 w-48 items-center bg-muted rounded-xs">
<ValidationIcon
datastore={props.datastore}
validationState={props.validationState}
datastore={datastore}
validationState={validationState}
className="pr-2"
/>
{upToDate &&
props.validationState.status === ValidationStatus.VALIDATED &&
"Validated!"}
{upToDate &&
props.validationState.status === ValidationStatus.VALIDATION_ERROR &&
"Failed to Validate"}
{props.validationState.status === ValidationStatus.CALL_ERROR &&
"Dev service loading"}
{props.validationState.status !== ValidationStatus.CALL_ERROR &&
!upToDate &&
"Validation not run"}
{valid && "Validated!"}
{invalid && "Failed to Validate"}
{loading && "Dev service loading"}
{notRun && "Validation not run"}
</div>
<Button
variant="contained"
startIcon={<PlayCircleFilledIcon />}
className={TourElementClass.run}
disabled={
props.developerService.state.status !== "ready" ||
props.validationState.status === ValidationStatus.RUNNING
developerService.state.status !== "ready" ||
validationState.status === ValidationStatus.RUNNING
}
onClick={props.conductValidation}
onClick={conductValidation}
variant="outline"
>
<CirclePlay />
Run
</Button>
</div>
);
}

export function ValidationIcon(props: {
small?: boolean;
export function ValidationIcon({
datastore,
validationState,
className,
}: {
datastore: DataStore;
validationState: ValidationState;
className: string;
}) {
const classes = useStyles();
if (
props.validationState.status === ValidationStatus.VALIDATED &&
props.datastore.currentIndex() ===
props.validationState.validationDatastoreIndex
validationState.status === ValidationStatus.VALIDATED &&
datastore.currentIndex() === validationState.validationDatastoreIndex
) {
return (
<span className={classes.gcm}>
<CheckCircleIcon />
</span>
);
return <CheckCircle className={className} fill="green" />;
}

if (
props.validationState.status === ValidationStatus.VALIDATION_ERROR &&
props.datastore.currentIndex() ===
props.validationState.validationDatastoreIndex
validationState.status === ValidationStatus.VALIDATION_ERROR &&
datastore.currentIndex() === validationState.validationDatastoreIndex
) {
return (
<span className={classes.rem}>
<ErrorIcon />
</span>
);
return <CircleX className={className} fill="red" />;
}

return (
<span className={classes.gray}>
<CheckCircleOutlineIcon />
</span>
);
return <CheckCircle className={className} />;
}
136 changes: 69 additions & 67 deletions src/index.css
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
@import "tailwindcss";
@import "tw-animate-css";

@custom-variant dark (&:is(.dark *));
@custom-variant dark (&:where(.dark, .dark *));

body {
margin: 0;
Expand Down Expand Up @@ -52,73 +52,75 @@ code {
--color-sidebar-ring: var(--sidebar-ring);
}

:root {
--radius: 0.625rem;
--background: oklch(1 0 0);
--foreground: oklch(0.147 0.004 49.25);
--card: oklch(1 0 0);
--card-foreground: oklch(0.147 0.004 49.25);
--popover: oklch(1 0 0);
--popover-foreground: oklch(0.147 0.004 49.25);
--primary: oklch(0.216 0.006 56.043);
--primary-foreground: oklch(0.985 0.001 106.423);
--secondary: oklch(0.97 0.001 106.424);
--secondary-foreground: oklch(0.216 0.006 56.043);
--muted: oklch(0.97 0.001 106.424);
--muted-foreground: oklch(0.553 0.013 58.071);
--accent: oklch(0.97 0.001 106.424);
--accent-foreground: oklch(0.216 0.006 56.043);
--destructive: oklch(0.577 0.245 27.325);
--border: oklch(0.923 0.003 48.717);
--input: oklch(0.923 0.003 48.717);
--ring: oklch(0.709 0.01 56.259);
--chart-1: oklch(0.646 0.222 41.116);
--chart-2: oklch(0.6 0.118 184.704);
--chart-3: oklch(0.398 0.07 227.392);
--chart-4: oklch(0.828 0.189 84.429);
--chart-5: oklch(0.769 0.188 70.08);
--sidebar: oklch(0.985 0.001 106.423);
--sidebar-foreground: oklch(0.147 0.004 49.25);
--sidebar-primary: oklch(0.216 0.006 56.043);
--sidebar-primary-foreground: oklch(0.985 0.001 106.423);
--sidebar-accent: oklch(0.97 0.001 106.424);
--sidebar-accent-foreground: oklch(0.216 0.006 56.043);
--sidebar-border: oklch(0.923 0.003 48.717);
--sidebar-ring: oklch(0.709 0.01 56.259);
}
@layer theme {
:root {
--radius: 0.625rem;
--background: oklch(1 0 0);
--foreground: oklch(0.147 0.004 49.25);
--card: oklch(1 0 0);
--card-foreground: oklch(0.147 0.004 49.25);
--popover: oklch(1 0 0);
--popover-foreground: oklch(0.147 0.004 49.25);
--primary: oklch(0.216 0.006 56.043);
--primary-foreground: oklch(0.985 0.001 106.423);
--secondary: oklch(0.97 0.001 106.424);
--secondary-foreground: oklch(0.216 0.006 56.043);
--muted: oklch(0.97 0.001 106.424);
--muted-foreground: oklch(0.553 0.013 58.071);
--accent: oklch(0.97 0.001 106.424);
--accent-foreground: oklch(0.216 0.006 56.043);
--destructive: oklch(0.577 0.245 27.325);
--border: oklch(0.923 0.003 48.717);
--input: oklch(0.923 0.003 48.717);
--ring: oklch(0.709 0.01 56.259);
--chart-1: oklch(0.646 0.222 41.116);
--chart-2: oklch(0.6 0.118 184.704);
--chart-3: oklch(0.398 0.07 227.392);
--chart-4: oklch(0.828 0.189 84.429);
--chart-5: oklch(0.769 0.188 70.08);
--sidebar: oklch(0.985 0.001 106.423);
--sidebar-foreground: oklch(0.147 0.004 49.25);
--sidebar-primary: oklch(0.216 0.006 56.043);
--sidebar-primary-foreground: oklch(0.985 0.001 106.423);
--sidebar-accent: oklch(0.97 0.001 106.424);
--sidebar-accent-foreground: oklch(0.216 0.006 56.043);
--sidebar-border: oklch(0.923 0.003 48.717);
--sidebar-ring: oklch(0.709 0.01 56.259);
}

.dark {
--background: oklch(0.147 0.004 49.25);
--foreground: oklch(0.985 0.001 106.423);
--card: oklch(0.216 0.006 56.043);
--card-foreground: oklch(0.985 0.001 106.423);
--popover: oklch(0.216 0.006 56.043);
--popover-foreground: oklch(0.985 0.001 106.423);
--primary: oklch(0.923 0.003 48.717);
--primary-foreground: oklch(0.216 0.006 56.043);
--secondary: oklch(0.268 0.007 34.298);
--secondary-foreground: oklch(0.985 0.001 106.423);
--muted: oklch(0.268 0.007 34.298);
--muted-foreground: oklch(0.709 0.01 56.259);
--accent: oklch(0.268 0.007 34.298);
--accent-foreground: oklch(0.985 0.001 106.423);
--destructive: oklch(0.704 0.191 22.216);
--border: oklch(1 0 0 / 10%);
--input: oklch(1 0 0 / 15%);
--ring: oklch(0.553 0.013 58.071);
--chart-1: oklch(0.488 0.243 264.376);
--chart-2: oklch(0.696 0.17 162.48);
--chart-3: oklch(0.769 0.188 70.08);
--chart-4: oklch(0.627 0.265 303.9);
--chart-5: oklch(0.645 0.246 16.439);
--sidebar: oklch(0.216 0.006 56.043);
--sidebar-foreground: oklch(0.985 0.001 106.423);
--sidebar-primary: oklch(0.488 0.243 264.376);
--sidebar-primary-foreground: oklch(0.985 0.001 106.423);
--sidebar-accent: oklch(0.268 0.007 34.298);
--sidebar-accent-foreground: oklch(0.985 0.001 106.423);
--sidebar-border: oklch(1 0 0 / 10%);
--sidebar-ring: oklch(0.553 0.013 58.071);
.dark {
--background: oklch(0.147 0.004 49.25);
--foreground: oklch(0.985 0.001 106.423);
--card: oklch(0.216 0.006 56.043);
--card-foreground: oklch(0.985 0.001 106.423);
--popover: oklch(0.216 0.006 56.043);
--popover-foreground: oklch(0.985 0.001 106.423);
--primary: oklch(0.923 0.003 48.717);
--primary-foreground: oklch(0.216 0.006 56.043);
--secondary: oklch(0.268 0.007 34.298);
--secondary-foreground: oklch(0.985 0.001 106.423);
--muted: oklch(0.268 0.007 34.298);
--muted-foreground: oklch(0.709 0.01 56.259);
--accent: oklch(0.268 0.007 34.298);
--accent-foreground: oklch(0.985 0.001 106.423);
--destructive: oklch(0.704 0.191 22.216);
--border: oklch(1 0 0 / 10%);
--input: oklch(1 0 0 / 15%);
--ring: oklch(0.553 0.013 58.071);
--chart-1: oklch(0.488 0.243 264.376);
--chart-2: oklch(0.696 0.17 162.48);
--chart-3: oklch(0.769 0.188 70.08);
--chart-4: oklch(0.627 0.265 303.9);
--chart-5: oklch(0.645 0.246 16.439);
--sidebar: oklch(0.216 0.006 56.043);
--sidebar-foreground: oklch(0.985 0.001 106.423);
--sidebar-primary: oklch(0.488 0.243 264.376);
--sidebar-primary-foreground: oklch(0.985 0.001 106.423);
--sidebar-accent: oklch(0.268 0.007 34.298);
--sidebar-accent-foreground: oklch(0.985 0.001 106.423);
--sidebar-border: oklch(1 0 0 / 10%);
--sidebar-ring: oklch(0.553 0.013 58.071);
}
}

@layer base {
Expand Down
6 changes: 4 additions & 2 deletions src/playground-ui/PlaygroundUIThemed.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,12 @@ export default function PlaygroundUIThemed({
forceDarkMode,
children,
}: PlaygroundUIThemedProps) {
const { setTheme } = useTheme();
const { theme: currentTheme, setTheme } = useTheme();
// Determine whether the user prefers dark or light mode.
const prefersDarkMode = useMediaQuery("(prefers-color-scheme: dark)");
const darkMode = prefersDarkMode || forceDarkMode === true;
const darkMode =
forceDarkMode === true ||
(currentTheme === "system" ? prefersDarkMode : currentTheme === "dark");

useEffect(() => {
if (forceDarkMode) {
Expand Down
Loading