Skip to content

Commit

Permalink
Merge pull request #9 from player-ui/console-ds
Browse files Browse the repository at this point in the history
Console, Table and Stacked View
  • Loading branch information
rafbcampos authored Mar 28, 2024
2 parents 2cfe251 + 31cfea9 commit 5624558
Show file tree
Hide file tree
Showing 56 changed files with 1,889 additions and 326 deletions.
3 changes: 3 additions & 0 deletions .bazelignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ plugin/node_modules
list/node_modules
docs/storybook/node_modules
docs/site/node_modules
console/node_modules
stacked-view/node_modules
table/node_modules

# Backup files
_backup
Expand Down
89 changes: 56 additions & 33 deletions addon-storybook/src/addons/events/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import {
Tr,
Th,
Td,
TableCaption,
TableContainer,
} from "@chakra-ui/react";
import { useSelector } from "react-redux";
Expand All @@ -20,33 +19,50 @@ interface EventsPanelProps {
active: boolean;
}

const prettifyEventPayload = (evt: EventType) => {
switch (evt.type) {
case "log":
return JSON.stringify({ message: evt.message, severity: evt.severity });
case "dataChange":
return JSON.stringify({
binding: evt.binding,
from: evt.from,
to: evt.to,
});
case "metric":
return JSON.stringify({
metricType: evt.metricType,
message: evt.message,
});
case "stateChange":
return JSON.stringify({
state: evt.state,
error: evt.error,
outcome: evt.outcome,
});
}
const useTablePros = () => {
const rows = useSelector<StateType, EventType[]>((state) => state.events);

const parsedRows = rows.map((row) =>
Object.entries(row).reduce((acc, [key, value]) => {
if (key === "time") {
return {
...acc,
[key]: new Date(value).toLocaleString(),
};
}

if (value === null || value === undefined) {
return {
...acc,
[key]: "",
};
}

if (typeof value === "object") {
return {
...acc,
[key]: JSON.stringify(value),
};
}

return { ...acc, [key]: value };
}, {} as Record<string, string>)
);

// Get the keys to use as column headers (checking all the rows for cases where we have different keys):
const headers = rows?.length
? Array.from(new Set(rows.flatMap((row) => Object.keys(row))))
: undefined;

return {
headers,
rows: parsedRows,
} as const;
};

/** The panel to show events */
export const EventsPanel = (props: EventsPanelProps) => {
const events = useSelector<StateType, EventType[]>((state) => state.events);
const { headers, rows } = useTablePros();
const contentType = useContentKind();

if (!props.active) {
Expand All @@ -61,23 +77,30 @@ export const EventsPanel = (props: EventsPanelProps) => {
);
}

if (!rows.length) {
return (
<Placeholder>
No events have been recorded for this story yet.
</Placeholder>
);
}

return (
<TableContainer>
<Table variant="simple">
<TableCaption>Events</TableCaption>
<Thead>
<Tr>
<Th>Time</Th>
<Th>Type</Th>
<Th>Payload</Th>
{headers?.map((key) => (
<Th key={key}>{key}</Th>
))}
</Tr>
</Thead>
<Tbody>
{events.map((evt) => (
<Tr key={evt.id}>
<Td>{evt.time}</Td>
<Td>{evt.type}</Td>
<Td>{prettifyEventPayload(evt)}</Td>
{rows.map((row, index) => (
<Tr key={index}>
{headers?.map((key) => (
<Td key={key}>{row[key as keyof typeof row] ?? ""}</Td>
))}
</Tr>
))}
</Tbody>
Expand Down
4 changes: 2 additions & 2 deletions asset-template/src/dsl/__tests__/index.test.tsx.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
import { {{pascalCase assetName}} } from "../";

describe("DSL: {{pascalCase assetName}}", () => {
test("Renders action", async () => {
test("Renders {{assetName}}", async () => {
const rendered = await render(
<{{pascalCase assetName}} exp={e`my_expression`} binding={b`my_binding`}>
<{{pascalCase assetName}}.Label>
Expand All @@ -35,7 +35,7 @@ describe("DSL: {{pascalCase assetName}}", () => {

expect(rendered.jsonValue).toStrictEqual({
id: "root",
type: "action",
type: "{{assetName}}",
label: {
asset: {
id: "label",
Expand Down
2 changes: 1 addition & 1 deletion asset-template/src/dsl/index.tsx.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export const {{pascalCase assetName}} = (props: AssetPropsWithChildren<{{pascalC
}

return (
<Asset type="action" {...rest}>
<Asset type="{{assetName}}" {...rest}>
<property name="binding">{binding.toValue()}</property>
{props.children}
</Asset>
Expand Down
2 changes: 1 addition & 1 deletion asset-template/src/types/index.ts.hbs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { Asset } from "@player-ui/types";

export interface {{pascalCase assetName}}Asset extends Asset<"action"> {
export interface {{pascalCase assetName}}Asset extends Asset<"{{assetName}}"> {
// DSL properties
// /** Value */
// value?: AssetWrapper;
Expand Down
35 changes: 35 additions & 0 deletions console/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
load("@npm//:defs.bzl", "npm_link_all_packages")
load("@rules_player//javascript:defs.bzl", "js_pipeline")
load("//helpers:defs.bzl", "tsup_config", "vitest_config")

npm_link_all_packages(name = "node_modules")

tsup_config(name = "tsup_config")

vitest_config(name = "vitest_config")

js_pipeline(
package_name = "@devtools-ui/console",
test_deps = [
":node_modules",
"//:vitest_config",
],
deps = [
":node_modules/@devtools-ui/collection",
":node_modules/@devtools-ui/text",
"//:node_modules/@chakra-ui/react",
"//:node_modules/@emotion/react",
"//:node_modules/@emotion/styled",
"//:node_modules/@player-tools/dsl",
"//:node_modules/@player-ui/asset-transform-plugin",
"//:node_modules/@player-ui/player",
"//:node_modules/@player-ui/react",
"//:node_modules/@player-ui/types",
"//:node_modules/@types/react",
"//:node_modules/dlv",
"//:node_modules/eslint-plugin-storybook",
"//:node_modules/framer-motion",
"//:node_modules/react",
"//:node_modules/@devtools-ds/console"
],
)
92 changes: 92 additions & 0 deletions console/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# @devtools-ui/console

## Overview

`@devtools-ui/console` is a component package designed to be leveraged by a [Player-UI assets plugin](https://player-ui.github.io/next/plugins).

It provides a [Console]([TODO: add link to storybook]) component that can be used to [TODO: define component features].

This package is part of a mono-repo built with Bazel, ensuring fast and reliable builds.

## Installation

To install `@devtools-ui/console`, you can use pnpm or yarn:

```sh
pnpm i @devtools-ui/console
```

or

```sh
yarn add @devtools-ui/console
```

## Usage

You can leverage this asset through the `@devtools-ui/plugin`:

```ts
import { Console } from "@devtools-ui/plugin";

// and use it to define your Player-UI content:
myFlow = {
id: "my_flow",
views: [<Console exp={e`my_expression`} binding={b`my_binding`} />],
};
```

For more information on how to author Player-UI content using DSL, please check our [Player-UI docs](https://player-ui.github.io/next/dsl#tsxjsx-content-authoring-player-dsl).

Or, your can leverage this asset in your own plugin:

```ts
// TransformPlugin.ts
import type { Player, PlayerPlugin } from "@player-ui/player";
import { AssetTransformPlugin } from "@player-ui/asset-transform-plugin";
import { consoleTransform } from "@devtools-ui/console";

export class TransformsPlugin implements PlayerPlugin {
name = "my-plugin-transforms";

apply(player: Player) {
player.registerPlugin(
new AssetTransformPlugin([[{ type: "console" }, consoleTransform]])
);
}
}
```

```ts
// AssetRegistryPlugin.ts
import React from "react";
import type { Player } from "@player-ui/player";
import type {
ExtendedPlayerPlugin,
ReactPlayer,
ReactPlayerPlugin,
} from "@player-ui/react";
import { AssetProviderPlugin } from "@player-ui/asset-provider-plugin-react";
import { TransformsPlugin } from "./TransformPlugin";
import { ConsoleAsset, ConsoleComponent } from "@devtools-ui/console";

export class AssetsRegistryPlugin
implements ReactPlayerPlugin, ExtendedPlayerPlugin<[ConsoleAsset]>
{
name = "my-plugin";

applyReact(reactPlayer: ReactPlayer) {
reactPlayer.registerPlugin(
new AssetProviderPlugin([["console", ConsoleComponent]])
);
}

apply(player: Player) {
player.registerPlugin(new TransformsPlugin());
}
}
```

## Contributing

We welcome contributions to `@devtools-ui/console`! Please see the [CONTRIBUTING.md](TODO: link to the file) file for more information on how to contribute.
9 changes: 9 additions & 0 deletions console/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"name": "@devtools-ui/console",
"version": "0.0.0-PLACEHOLDER",
"main": "src/index.ts",
"dependencies": {
"@devtools-ui/text": "workspace:*",
"@devtools-ui/collection": "workspace:*"
}
}
9 changes: 9 additions & 0 deletions console/src/component/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import React from "react";
import { Console } from "@devtools-ds/console";
import type { TransformedConsole } from "../types";

export const ConsoleComponent = (props: TransformedConsole) => {
const { evaluate, history } = props;

return <Console execute={evaluate} history={history} />;
};
19 changes: 19 additions & 0 deletions console/src/dsl/__tests__/index.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import React from "react";
import { describe, expect, test } from "vitest";
import { render, expression as e, binding as b } from "@player-tools/dsl";
import { Console } from "../";

describe("DSL: Console", () => {
test("Renders console", async () => {
const rendered = await render(
<Console exp={e`my_expression`} binding={b`my_binding`} />
);

expect(rendered.jsonValue).toStrictEqual({
id: "root",
type: "console",
exp: "my_expression",
binding: "my_binding",
});
});
});
39 changes: 39 additions & 0 deletions console/src/dsl/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import React from "react";
import {
AssetPropsWithChildren,
Asset,
isTemplateStringInstance,
BindingTemplateInstance,
} from "@player-tools/dsl";
import type { ConsoleAsset } from "../types";

/**
* Defines the component DSL representation for the Console asset,
* a component that emulates a REPL environment that you see in browsers.
*/
export const Console = (
props: Omit<AssetPropsWithChildren<ConsoleAsset>, "binding"> & {
/** Binding as template string */
binding: BindingTemplateInstance;
}
) => {
const { exp, binding } = props;

// Extracting the exp value from the props
let expValue: ConsoleAsset["exp"];

if (isTemplateStringInstance(exp)) {
expValue = exp.toValue();
} else if (Array.isArray(exp)) {
expValue = exp.map((e) => (typeof e === "string" ? e : e.toValue()));
} else if (exp) {
expValue = exp;
}

return (
<Asset type="console">
{exp && <property name="exp">{expValue}</property>}
{binding && <property name="binding">{binding.toValue()}</property>}
</Asset>
);
};
4 changes: 4 additions & 0 deletions console/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export * from "./types";
export * from "./component";
export * from "./dsl";
export * from "./transform";
Loading

0 comments on commit 5624558

Please sign in to comment.