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
9 changes: 4 additions & 5 deletions buf.gen.yaml
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
---
version: "v2"
plugins:
- remote: "buf.build/community/timostamm-protobuf-ts:v2.9.1"
- remote: "buf.build/bufbuild/es:v2.4.0"
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This swaps in the new codegen.

out: "src/spicedb-common/protodefs"
include_imports: true
opt:
- "long_type_string"
- "generate_dependencies"
- "optimize_code_size"
- "target=ts"
inputs:
- module: "buf.build/authzed/api:v1.40.0"
- module: "buf.build/authzed/api:v1.41.0"
paths:
- "authzed/api/v0"
- git_repo: "https://github.com/authzed/spicedb"
Expand Down
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
"dependencies": {
"@apollo/client": "^3.7.3",
"@apollo/link-context": "^2.0.0-beta.3",
"@bufbuild/protobuf": "^2.4.0",
"@connectrpc/connect": "^2.0.2",
"@connectrpc/connect-web": "^2.0.2",
"@fontsource/roboto": "^5.1.1",
"@fortawesome/fontawesome-svg-core": "^6.4.0",
"@fortawesome/free-solid-svg-icons": "^6.2.1",
Expand All @@ -16,8 +19,6 @@
"@material-ui/icons": "^4.11.3",
"@material-ui/lab": "^4.0.0-alpha.61",
"@monaco-editor/react": "^4.3.1",
"@protobuf-ts/grpcweb-transport": "^2.9.4",
"@protobuf-ts/plugin": "^2.6.0",
"@radix-ui/react-alert-dialog": "^1.1.11",
"@radix-ui/react-select": "^2.2.2",
"@radix-ui/react-slot": "^1.2.0",
Expand Down
89 changes: 41 additions & 48 deletions src/components/CheckDebugTraceView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,8 @@ import {
CheckDebugTrace,
CheckDebugTrace_Permissionship,
CheckDebugTrace_PermissionType,
} from "../spicedb-common/protodefs/authzed/api/v1/debug";
import {
Struct,
Value,
} from "../spicedb-common/protodefs/google/protobuf/struct";
Comment on lines -8 to -11
Copy link
Contributor Author

Choose a reason for hiding this comment

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

There's lots of places where we were using Struct that we no longer need to, because protobuf-es automatically converts a normal JS object to Structs and Values where needed. This is one of the big ergonomic benefits.

} from "../spicedb-common/protodefs/authzed/api/v1/debug_pb";
import type { JsonObject, JsonValue } from "@bufbuild/protobuf";
import { createStyles, makeStyles, Theme } from "@material-ui/core/styles";
import CheckCircleIcon from "@material-ui/icons/CheckCircle";
import ChevronRightIcon from "@material-ui/icons/ChevronRight";
Expand Down Expand Up @@ -105,8 +102,8 @@ export function CheckDebugTraceView(props: {
);
});

if (t.resolution.oneofKind === "subProblems") {
t.resolution.subProblems.traces.forEach(appendExpanded);
if (t.resolution.case === "subProblems") {
t.resolution.value.traces.forEach(appendExpanded);
Comment on lines +105 to +106
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is the difference in how protobuf-es represents oneOfKind fields.

}
};

Expand Down Expand Up @@ -145,18 +142,16 @@ function CheckDebugTraceItems(props: {
const isNotMember = hasNotPermission(props.trace);

const children =
props.trace.resolution.oneofKind === "subProblems"
? props.trace.resolution.subProblems.traces.map(
(subTrace, index) => {
return (
<CheckDebugTraceItems
key={index}
trace={subTrace}
localParseService={props.localParseService}
/>
);
},
)
props.trace.resolution.case === "subProblems"
? props.trace.resolution.value.traces.map((subTrace, index) => {
return (
<CheckDebugTraceItems
key={index}
trace={subTrace}
localParseService={props.localParseService}
/>
);
})
: [];

if (
Expand Down Expand Up @@ -285,14 +280,18 @@ function CaveatTreeItem(props: {
);
}

function ContextTreeView(context: Struct | undefined) {
function ContextTreeView(context: JsonObject | undefined) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

The value of a Struct on a message is just a JsonObject as far as client code is concerned, so we convert these functions to handle them.

if (context === undefined) {
return null;
}

return Object.keys(context.fields).map((key) => {
if (context === null) {
return null;
}

return Object.keys(context).map((key) => {
let label = <span>{key}</span>;
const [value, isItemValue] = ContextTreeValue(context?.fields[key]);
const [value, isItemValue] = ContextTreeValue(context[key]);
if (!isItemValue) {
label = (
<span>
Expand All @@ -309,31 +308,25 @@ function ContextTreeView(context: Struct | undefined) {
});
}

function ContextTreeValue(value: Value) {
switch (value.kind.oneofKind) {
case "nullValue":
return [<code>null</code>, false];

case "numberValue":
return [<code>{value.kind.numberValue.toString()}</code>, false];

case "stringValue":
return [<code>{value.kind.stringValue}</code>, false];

case "boolValue":
return [<code>{value.kind.boolValue.toString()}</code>, false];

case "structValue":
return [ContextTreeView(value.kind.structValue), true];

case "listValue":
return [
value.kind.listValue.values.map((v) => {
return <TreeItem nodeId="">{ContextTreeValue(v)}</TreeItem>;
}),
true,
];
function ContextTreeValue(value: JsonValue) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This function needed to change a bit - rather than switching on a string field, we switch on the type of the value itself.

if (value === null) {
return [<code>null</code>, false];
}

return [null, false];
if (typeof value === "boolean") {
return [<code>{value.toString()}</code>, false];
}
if (Array.isArray(value)) {
return [
value.map((v) => {
return <TreeItem nodeId="">{ContextTreeValue(v)}</TreeItem>;
}),
true,
];
}
// NOTE: we've already handled null and array above, so this will match on objects.
if (typeof value === "object") {
return [ContextTreeView(value), true];
}
// If we've gotten this far, we have a number or a string and we can render it straight out.
return [<code>{value}</code>, false];
}
2 changes: 1 addition & 1 deletion src/components/DatastoreRelationshipEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
import {
DeveloperError,
DeveloperError_Source,
} from "../spicedb-common/protodefs/developer/v1/developer";
} from "../spicedb-common/protodefs/developer/v1/developer_pb";
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Lots of these kinds of changes - just import name changes.

import { Theme } from "@glideapps/glide-data-grid";
import { useCallback, useMemo, useState } from "react";
import useDeepCompareEffect from "use-deep-compare-effect";
Expand Down
2 changes: 1 addition & 1 deletion src/components/EditorDisplay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { RelationshipFound } from "../spicedb-common/parsing";
import {
DeveloperError,
DeveloperWarning,
} from "../spicedb-common/protodefs/developer/v1/developer";
} from "../spicedb-common/protodefs/developer/v1/developer_pb";
import { createStyles, makeStyles } from "@material-ui/core/styles";
import useMediaQuery from "@material-ui/core/useMediaQuery";
import Editor, { DiffEditor, useMonaco } from "@monaco-editor/react";
Expand Down
36 changes: 23 additions & 13 deletions src/components/EmbeddedPlayground.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ import {
RelationshipFound,
parseRelationship,
} from "../spicedb-common/parsing";
import { DeveloperServiceClient } from "../spicedb-common/protodefs/authzed/api/v0/developer.client";
import { GrpcWebFetchTransport } from "@protobuf-ts/grpcweb-transport";
import { RpcError } from "@protobuf-ts/runtime-rpc";
import {
CheckOperationParametersSchema,
CheckOperationsResult,
CheckOperationsResult_Membership,
} from "../spicedb-common/protodefs/developer/v1/developer";
CheckOperationsResultSchema,
} from "../spicedb-common/protodefs/developer/v1/developer_pb";
import { DeveloperService } from "../spicedb-common/protodefs/authzed/api/v0/developer_pb";
import { createGrpcWebTransport } from "@connectrpc/connect-web";
import { createClient, ConnectError } from "@connectrpc/connect";
import { useDeveloperService } from "../spicedb-common/services/developerservice";
import {
faCaretDown,
Expand Down Expand Up @@ -44,6 +46,7 @@ import { ShareLoader } from "./ShareLoader";

import { ParsedObjectDefinition } from "../spicedb-common/parsers/dsl/dsl";
import "./fonts.css";
import { create } from "@bufbuild/protobuf";

const useStyles = makeStyles(() =>
createStyles({
Expand Down Expand Up @@ -281,9 +284,13 @@ function EmbeddedPlaygroundUI(props: { datastore: DataStore }) {
return;
}

const service = new DeveloperServiceClient(
new GrpcWebFetchTransport({ baseUrl: developerEndpoint }),
const client = createClient(
DeveloperService,
createGrpcWebTransport({
baseUrl: developerEndpoint,
}),
);

const schema = datastore.getSingletonByKind(
DataStoreItemKind.SCHEMA,
).editableContents!;
Expand All @@ -299,7 +306,7 @@ function EmbeddedPlaygroundUI(props: { datastore: DataStore }) {

// Invoke sharing.
try {
const { response } = await service.share({
const response = await client.share({
schema,
relationshipsYaml,
assertionsYaml,
Expand All @@ -308,7 +315,7 @@ function EmbeddedPlaygroundUI(props: { datastore: DataStore }) {
const reference = response.shareReference;
window.open(`${window.location.origin}/s/${reference}`);
} catch (error: unknown) {
if (error instanceof RpcError) {
if (error instanceof ConnectError) {
showAlert({
title: "Error sharing",
content: error.message,
Expand Down Expand Up @@ -482,14 +489,17 @@ function EmbeddedQuery(props: { services: Services }) {
}

const request = devService.newRequest(schemaText, relsText);
let checkResult: CheckOperationsResult = {
membership: CheckOperationsResult_Membership.UNKNOWN,
};
request?.check(
let checkResult: CheckOperationsResult = create(
CheckOperationsResultSchema,
{
membership: CheckOperationsResult_Membership.UNKNOWN,
},
);
request?.check(
create(CheckOperationParametersSchema, {
resource: relationship.resourceAndRelation!,
subject: relationship.subject!,
},
}),
Comment on lines +492 to +502
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Rather than the message types having their own constructors, you have a Schema object that you hand to a create function. It's a little more verbose in some ways, but the create function lets you pass in normal JS objects and it Just Works, which is nifty.

(r: CheckOperationsResult) => {
checkResult = r;
},
Expand Down
17 changes: 10 additions & 7 deletions src/components/FullPlayground.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import { DiscordChatCrate } from "../playground-ui/DiscordChatCrate";
import { useGoogleAnalytics } from "../playground-ui/GoogleAnalyticsHook";
import TabLabel from "../playground-ui/TabLabel";
import { Example } from "../spicedb-common/examples";
import { DeveloperServiceClient } from "../spicedb-common/protodefs/authzed/api/v0/developer.client";
import { GrpcWebFetchTransport } from "@protobuf-ts/grpcweb-transport";
import { RpcError } from "@protobuf-ts/runtime-rpc";
import { DeveloperService } from "../spicedb-common/protodefs/authzed/api/v0/developer_pb";
import { createGrpcWebTransport } from "@connectrpc/connect-web";
import { createClient, ConnectError } from "@connectrpc/connect";
import { useDeveloperService } from "../spicedb-common/services/developerservice";
import { useZedTerminalService } from "../spicedb-common/services/zedterminalservice";
import { parseValidationYAML } from "../spicedb-common/validationfileformat";
Expand Down Expand Up @@ -498,8 +498,11 @@ export function ThemedAppView(props: { datastore: DataStore }) {
status: SharingStatus.SHARING,
});

const service = new DeveloperServiceClient(
new GrpcWebFetchTransport({ baseUrl: developerEndpoint }),
const client = createClient(
DeveloperService,
createGrpcWebTransport({
baseUrl: developerEndpoint,
}),
);

const schema = datastore.getSingletonByKind(
Expand All @@ -517,7 +520,7 @@ export function ThemedAppView(props: { datastore: DataStore }) {

// Invoke sharing.
try {
const { response } = await service.share({
const response = await client.share({
schema,
relationshipsYaml,
assertionsYaml,
Expand All @@ -533,7 +536,7 @@ export function ThemedAppView(props: { datastore: DataStore }) {
shareReference: reference,
});
} catch (error: unknown) {
if (error instanceof RpcError) {
if (error instanceof ConnectError) {
showAlert({
title: "Error sharing",
content: error.message,
Expand Down
27 changes: 14 additions & 13 deletions src/components/ShareLoader.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { useAlert } from "../playground-ui/AlertProvider";
import { useConfirmDialog } from "../playground-ui/ConfirmDialogProvider";
import LoadingView from "../playground-ui/LoadingView";
import { DeveloperServiceClient } from "../spicedb-common/protodefs/authzed/api/v0/developer.client";
import { GrpcWebFetchTransport } from "@protobuf-ts/grpcweb-transport";
import { LookupShareResponse_LookupStatus } from "../spicedb-common/protodefs/authzed/api/v0/developer";
import { RpcError } from "@protobuf-ts/runtime-rpc";
import { LookupShareResponse_LookupStatus } from "../spicedb-common/protodefs/authzed/api/v0/developer_pb";
import { DeveloperService } from "../spicedb-common/protodefs/authzed/api/v0/developer_pb";
import { createGrpcWebTransport } from "@connectrpc/connect-web";
import { createClient, ConnectError } from "@connectrpc/connect";
import Alert from "@material-ui/lab/Alert";
import React, { useEffect, useState } from "react";
import "react-reflex/styles.css";
Expand Down Expand Up @@ -66,8 +66,11 @@ export function ShareLoader(props: {
if (!endpoint) {
return;
}
const service = new DeveloperServiceClient(
new GrpcWebFetchTransport({ baseUrl: endpoint }),
const client = createClient(
DeveloperService,
createGrpcWebTransport({
baseUrl: endpoint,
}),
);

// TODO: use routing for this instead of string manipulation
Expand All @@ -80,12 +83,11 @@ export function ShareLoader(props: {
const shareReference = pieces[0];

try {
const { response, status } = await service.lookupShared({
const response = await client.lookupShared({
shareReference,
});
if (
status.code ===
LookupShareResponse_LookupStatus.FAILED_TO_LOOKUP.toString()
response.status === LookupShareResponse_LookupStatus.FAILED_TO_LOOKUP
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Shape change - status is on the object.

) {
setLoadingStatus(SharedLoadingStatus.LOAD_ERROR);
if (props.sharedRequired) {
Expand All @@ -103,8 +105,7 @@ export function ShareLoader(props: {

// Unknown reference.
if (
status.code ===
LookupShareResponse_LookupStatus.UNKNOWN_REFERENCE.toString()
response.status === LookupShareResponse_LookupStatus.UNKNOWN_REFERENCE
) {
setLoadingStatus(SharedLoadingStatus.LOAD_ERROR);
if (props.sharedRequired) {
Expand Down Expand Up @@ -162,10 +163,10 @@ export function ShareLoader(props: {

setLoadingStatus(SharedLoadingStatus.LOADED);
} catch (error: unknown) {
if (error instanceof RpcError)
if (error instanceof ConnectError)
await showAlert({
title: "Error loading shared playground",
content: error?.message,
content: error.message,
buttonTitle: "Okay",
});
navigate({ to: "/", replace: true });
Expand Down
2 changes: 1 addition & 1 deletion src/components/panels/errordisplays.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
DeveloperError,
DeveloperError_Source,
DeveloperWarning,
} from "../../spicedb-common/protodefs/developer/v1/developer";
} from "../../spicedb-common/protodefs/developer/v1/developer_pb";
import { Theme, createStyles, makeStyles } from "@material-ui/core/styles";
import Alert from "@material-ui/lab/Alert";
import "react-reflex/styles.css";
import { Link } from "@tanstack/react-router";
import { DataStoreItemKind, DataStorePaths } from "../../services/datastore";

export const ERROR_SOURCE_TO_ITEM = {

Check warning on line 12 in src/components/panels/errordisplays.tsx

View workflow job for this annotation

GitHub Actions / Run Linters and Typechecking

Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components
[DeveloperError_Source.SCHEMA]: DataStoreItemKind.SCHEMA,
[DeveloperError_Source.RELATIONSHIP]: DataStoreItemKind.RELATIONSHIPS,
[DeveloperError_Source.ASSERTION]: DataStoreItemKind.ASSERTIONS,
Expand Down
2 changes: 1 addition & 1 deletion src/components/panels/problems.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { RelationshipFound } from "../../spicedb-common/parsing";
import {
DeveloperError,
DeveloperWarning,
} from "../../spicedb-common/protodefs/developer/v1/developer";
} from "../../spicedb-common/protodefs/developer/v1/developer_pb";
import Paper from "@material-ui/core/Paper";
import { createStyles, makeStyles, Theme } from "@material-ui/core/styles";
import ErrorOutlineIcon from "@material-ui/icons/ErrorOutline";
Expand Down
Loading
Loading