Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improvements to playground #15

Merged
merged 4 commits into from
Aug 7, 2024
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
9 changes: 7 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,13 @@ NODE_OPTIONS=--openssl-legacy-provider vercel build
vercel deploy --prebuilt
```

> ℹ️ Git Large File Storage (LFS) must be enabled in your Vercel project settings.
> ℹ️ Git Large File Storage (LFS) must be enabled in your Vercel project settings.

### NodeJS

The `build` directory in the project root directory after running `yarn build` will contain an optimized production React application that can be served using your preferred NodeJS hosting method.

> ℹ️ Node v18.x is required.
> ℹ️ Node v18.x is required.

For example:

Expand All @@ -84,6 +84,11 @@ Setup git submodules: `git submodule update --init --recursive`

Run `yarn install` in the _root_ project directory.

## Running for development

1. Copy the files in the `wasm` root directory into `playground/public/static`
2. Run `yarn start` from the `playground` subdirectory

## Updating wasm dependencies

The project contains prebuilt WASM files for versions of both SpiceDB and zed. To update the versions, edit the [wasm-config.json] file with the desired tag/commit hash and then run from the project root:
Expand Down
25 changes: 23 additions & 2 deletions playground/src/components/EditorDisplay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import registerDSLanguage, {
import { useDebouncedChecker } from '@code/playground-ui/src/debouncer';
import { TextRange } from '@code/spicedb-common/src/include/protobuf-parser';
import { RelationshipFound } from '@code/spicedb-common/src/parsing';
import { DeveloperError } from '@code/spicedb-common/src/protodevdefs/developer/v1/developer';
import { DeveloperError, DeveloperWarning } from '@code/spicedb-common/src/protodevdefs/developer/v1/developer';
import { Theme, createStyles, makeStyles } from '@material-ui/core/styles';
import useMediaQuery from '@material-ui/core/useMediaQuery';
import Editor, { DiffEditor, useMonaco } from '@monaco-editor/react';
Expand Down Expand Up @@ -208,6 +208,7 @@ export function EditorDisplay(props: EditorDisplayProps) {
return;
}


Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change

markers.push({
startLineNumber: invalid.lineNumber + 1,
startColumn: 0,
Expand All @@ -220,9 +221,29 @@ export function EditorDisplay(props: EditorDisplayProps) {
);
}

// Generate markers for all other kinds of errors.
const contents = currentItem?.editableContents ?? '';
const finder = lineColumn(contents);
const lines = contents.split('\n');

// Generate markers for warnings.
if (currentItem.kind === DataStoreItemKind.SCHEMA) {
props.services.problemService.warnings.forEach(
(warning: DeveloperWarning) => {
const line = lines[warning.line -1];
const index = line.indexOf(warning.sourceCode, warning.column - 1);
markers.push({
startLineNumber: warning.line,
startColumn: index + 1,
endLineNumber: warning.line,
endColumn: index + warning.sourceCode.length + 1,
message: warning.message,
severity: monacoRef.MarkerSeverity.Warning,
});
}
);
}

// Generate markers for all other kinds of errors.
const allErrors = [
...props.services.problemService.requestErrors,
...props.services.problemService.validationErrors,
Expand Down
2 changes: 1 addition & 1 deletion playground/src/components/ExamplesDropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ export function ExamplesDropdown(props: {
{examples !== undefined &&
examples.map((example) => {
return (
<MenuItem onClick={() => exampleSelected(example)}>
<MenuItem onClick={() => exampleSelected(example)} key={example.id}>
<ListItemText
primary={example.title}
secondary={example.subtitle}
Expand Down
17 changes: 13 additions & 4 deletions playground/src/components/FullPlayground.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1159,18 +1159,27 @@ const TabLabelWithCount = (props: {
}) => {
const classes = useSummaryStyles();
const problemService = props.problemService;
const problemCount = problemService.getProblemCount(props.kind);
const errorCount = problemService.getErrorCount(props.kind);
const warningCount = props.kind === DataStoreItemKind.SCHEMA ? problemService.warnings.length : 0;

return (
<div className={classes.problemTab}>
<TabLabel icon={props.icon} title={props.title} />
<span
style={{ display: problemCount > 0 ? 'inline-flex' : 'none' }}
style={{ display: errorCount > 0 ? 'inline-flex' : 'none' }}
className={clsx(classes.badge, {
[classes.failBadge]: problemCount > 0,
[classes.failBadge]: errorCount > 0,
})}
>
{problemCount}
{errorCount}
</span>
<span
style={{ display: warningCount > 0 ? 'inline-flex' : 'none' }}
className={clsx(classes.badge, {
[classes.warningBadge]: warningCount > 0,
})}
>
{warningCount}
</span>
</div>
);
Expand Down
6 changes: 5 additions & 1 deletion playground/src/components/panels/base/common.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,10 @@ export const useSummaryStyles = makeStyles((theme: Theme) =>
backgroundColor: theme.palette.error.dark,
color: theme.palette.getContrastText(theme.palette.error.dark),
},
warningBadge: {
backgroundColor: theme.palette.warning.dark,
color: theme.palette.getContrastText(theme.palette.warning.dark),
},
checkTab: {
display: 'grid',
alignItems: 'center',
Expand All @@ -93,7 +97,7 @@ export const useSummaryStyles = makeStyles((theme: Theme) =>
},
problemTab: {
display: 'grid',
gridTemplateColumns: 'auto auto',
gridTemplateColumns: 'auto auto auto',
columnGap: '10px',
alignItems: 'center',
},
Expand Down
27 changes: 27 additions & 0 deletions playground/src/components/panels/errordisplays.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {
DeveloperError,
DeveloperError_Source,
DeveloperWarning,
} from '@code/spicedb-common/src/protodevdefs/developer/v1/developer';
import { Theme, createStyles, makeStyles } from '@material-ui/core/styles';
import Alert from '@material-ui/lab/Alert';
Expand Down Expand Up @@ -89,6 +90,19 @@ export function DeveloperErrorDisplay(props: { error: DeveloperError }) {
);
}

export function DeveloperWarningDisplay(props: { warning: DeveloperWarning }) {
const classes = useErrorDisplayStyles();
return (
<Alert
className={classes.validationError}
variant="outlined"
severity="warning"
>
{props.warning.message}
</Alert>
);
}

const useSourceDisplayStyles = makeStyles((theme: Theme) =>
createStyles({
link: {
Expand All @@ -101,6 +115,19 @@ const useSourceDisplayStyles = makeStyles((theme: Theme) =>
})
);

export function DeveloperWarningSourceDisplay(props: {warning: DeveloperWarning}) {
const vw = props.warning;
const classes = useSourceDisplayStyles();

return <div className={classes.validationErrorContext}>
In{' '}
<Link className={classes.link} to={DataStorePaths.Schema()}>
Schema
</Link>
:
</div>
}

export function DeveloperSourceDisplay(props: { error: DeveloperError }) {
const ve = props.error;
const classes = useSourceDisplayStyles();
Expand Down
34 changes: 27 additions & 7 deletions playground/src/components/panels/problems.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import TabLabel from '@code/playground-ui/src/TabLabel';
import { RelationshipFound } from '@code/spicedb-common/src/parsing';
import { DeveloperError } from '@code/spicedb-common/src/protodevdefs/developer/v1/developer';
import { DeveloperError, DeveloperWarning } from '@code/spicedb-common/src/protodevdefs/developer/v1/developer';
import Paper from '@material-ui/core/Paper';
import { createStyles, makeStyles, Theme } from '@material-ui/core/styles';
import ErrorOutlineIcon from '@material-ui/icons/ErrorOutline';
Expand All @@ -11,7 +11,7 @@ import { Link } from 'react-router-dom';
import { DataStorePaths } from '../../services/datastore';
import { TourElementClass } from '../GuidedTour';
import { PanelProps, PanelSummaryProps, useSummaryStyles } from './base/common';
import { DeveloperErrorDisplay, DeveloperSourceDisplay } from './errordisplays';
import { DeveloperErrorDisplay, DeveloperSourceDisplay, DeveloperWarningDisplay, DeveloperWarningSourceDisplay } from './errordisplays';
import { PlaygroundPanelLocation } from './panels';

var _ = React;
Expand Down Expand Up @@ -51,24 +51,32 @@ export function ProblemsSummary(
props: PanelSummaryProps<PlaygroundPanelLocation>
) {
const classes = useSummaryStyles();
const problemCount = props.services.problemService.problemCount;
const errorCount = props.services.problemService.errorCount;
const warningCount = props.services.problemService.warnings.length;

return (
<div className={clsx(classes.problemTab, TourElementClass.problems)}>
<TabLabel
icon={
<ErrorOutlineIcon
htmlColor={props.services.problemService.hasProblems ? '' : 'grey'}
htmlColor={props.services.problemService.errorCount > 0 ? '' : 'grey'}
/>
}
title="Problems"
/>
<span
className={clsx(classes.badge, {
[classes.failBadge]: problemCount > 0,
[classes.failBadge]: errorCount > 0,
})}
>
{problemCount}
{errorCount}
</span>
<span
className={clsx(classes.badge, {
[classes.warningBadge]: warningCount > 0,
})}
>
{warningCount}
</span>
</div>
);
Expand All @@ -85,7 +93,7 @@ export function ProblemsPanel(props: PanelProps<PlaygroundPanelLocation>) {
{props.services.problemService.invalidRelationships.map(
(invalid: RelationshipFound, index: number) => {
if (!('errorMessage' in invalid.parsed)) {
return;
return <div/>;
}

return (
Expand Down Expand Up @@ -122,6 +130,18 @@ export function ProblemsPanel(props: PanelProps<PlaygroundPanelLocation>) {
);
}
)}
{props.services.problemService.warnings.map(
(dw: DeveloperWarning, index: number) => {
return (
<Paper className={classes.errorContainer} key={`dw${index}`}>
<div>
<DeveloperWarningSourceDisplay warning={dw} />
<DeveloperWarningDisplay warning={dw} />
</div>
</Paper>
);
}
)}
</div>
);
}
18 changes: 14 additions & 4 deletions playground/src/services/check.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
CheckOperationsResult_Membership,
DeveloperError,
DeveloperResponse,
DeveloperWarning,
} from '@code/spicedb-common/src/protodevdefs/developer/v1/developer';
import {
DeveloperService,
Expand Down Expand Up @@ -47,6 +48,7 @@ export interface LiveCheckRunState {
lastRun?: Date;
requestErrors?: DeveloperError[];
serverErr?: DeveloperServiceError;
warnings?: DeveloperWarning[];
}

export interface LiveCheckService {
Expand All @@ -73,7 +75,7 @@ function runEditCheckWasm(
developerService: DeveloperService,
datastore: DataStore,
items: LiveCheckItem[]
): DeveloperResponse | undefined {
): [DeveloperResponse, DeveloperWarning[]] | undefined {
const schema =
datastore.getSingletonByKind(DataStoreItemKind.SCHEMA).editableContents ??
'';
Expand All @@ -86,6 +88,12 @@ function runEditCheckWasm(
return;
}

// Add a check for warnings.
let warnings: DeveloperWarning[] = [];
request.schemaWarnings((result) => {
warnings = result.warnings;
});

// Build the relationships to be checked, validating as we go.
items.forEach((item: LiveCheckItem) => {
const parsed = parseRelationship(liveCheckItemToString(item));
Expand Down Expand Up @@ -130,7 +138,7 @@ function runEditCheckWasm(
);
});

return request.execute();
return [request.execute(), warnings];
}

/**
Expand All @@ -154,12 +162,12 @@ export function useLiveCheckService(
}

setState({ status: LiveCheckStatus.CHECKING });
const response = runEditCheckWasm(
const r = runEditCheckWasm(
developerService,
datastore,
itemsToCheck
);
if (response === undefined) {
if (r === undefined) {
setState({ status: LiveCheckStatus.NOT_CHECKING });

if (itemsToCheck.length > 0) {
Expand All @@ -174,6 +182,7 @@ export function useLiveCheckService(
return;
}

const [response, warnings] = r;
const serverErr: string | undefined = response.internalError || undefined;
const devErrs: DeveloperError[] = response.developerErrors
? response.developerErrors.inputErrors
Expand All @@ -189,6 +198,7 @@ export function useLiveCheckService(
lastRun: new Date(),
requestErrors: devErrs,
serverErr: serverErr,
warnings: warnings,
});
},
[developerService, devServiceStatus, datastore]
Expand Down
Loading
Loading