Skip to content

Commit

Permalink
Create tree-react-api package (#20573)
Browse files Browse the repository at this point in the history
## Description

Add tree-react-api package.

This package provides some experimental utilities for working with
SharedTree, react and DataObjects.
  • Loading branch information
CraigMacomber authored May 2, 2024
1 parent 018bb13 commit eda9e6d
Show file tree
Hide file tree
Showing 29 changed files with 683 additions and 137 deletions.
1 change: 1 addition & 0 deletions examples/data-objects/inventory-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
},
"dependencies": {
"@fluid-example/example-utils": "workspace:~",
"@fluid-experimental/tree-react-api": "workspace:~",
"@fluidframework/aqueduct": "workspace:~",
"@fluidframework/core-interfaces": "workspace:~",
"@fluidframework/datastore-definitions": "workspace:~",
Expand Down
6 changes: 4 additions & 2 deletions examples/data-objects/inventory-app/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@
import { ContainerViewRuntimeFactory } from "@fluid-example/example-utils";
import React from "react";

import { InventoryList, InventoryListFactory } from "./inventoryList.js";
import type { IReactTreeDataObject } from "@fluid-experimental/tree-react-api";
import { InventoryListFactory } from "./inventoryList.js";
import { MainView } from "./view/inventoryList.js";
import type { Inventory } from "./schema.js";

export const fluidExport = new ContainerViewRuntimeFactory(
InventoryListFactory,
(tree: InventoryList) =>
(tree: IReactTreeDataObject<typeof Inventory>) =>
React.createElement(tree.TreeViewComponent, { viewComponent: MainView }),
);
20 changes: 3 additions & 17 deletions examples/data-objects/inventory-app/src/inventoryList.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,8 @@
* Licensed under the MIT License.
*/

// Lint rule can be disabled once eslint config is upgraded to 5.3.0+
// eslint-disable-next-line import/no-internal-modules
import { DataObjectFactory } from "@fluidframework/aqueduct/internal";
import { treeDataObjectInternal } from "@fluid-experimental/tree-react-api/internal";
import { treeConfiguration } from "./schema.js";

import { TreeDataObject, factory } from "./reactSharedTreeView.js";
import { type Inventory, treeConfiguration } from "./schema.js";

// For use with lower level APIs, like ContainerViewRuntimeFactory from "@fluid-example/example-utils".
export class InventoryList extends TreeDataObject<typeof Inventory> {
public readonly key = "tree";
public readonly config = treeConfiguration;
}

export const InventoryListFactory = new DataObjectFactory(
"@fluid-experimental/inventory-list",
InventoryList,
[factory],
{},
);
export const InventoryListFactory = treeDataObjectInternal("tree", treeConfiguration).factory;
15 changes: 2 additions & 13 deletions examples/data-objects/inventory-app/src/view/inventoryList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,14 @@
* Licensed under the MIT License.
*/

import { Tree } from "@fluidframework/tree";
import { useTree } from "@fluid-experimental/tree-react-api";
import * as React from "react";

import { Inventory } from "../schema.js";

import { Counter } from "./counter.js";

export const MainView: React.FC<{ root: Inventory }> = ({ root: inventory }) => {
// Use a React effect hook to invalidate this component when the inventory changes.
// We do this by incrementing a counter, which is passed as a dependency to the effect hook.
const [invalidations, setInvalidations] = React.useState(0);

// React effect hook that increments the 'invalidation' counter whenever inventory or any of its children change.
React.useEffect(() => {
// Returns the cleanup function to be invoked when the component unmounts.
return Tree.on(inventory, "treeChanged", () => {
setInvalidations((i) => i + 1);
});
}, [invalidations, inventory]);
useTree(inventory);

const counters: JSX.Element[] = [];

Expand Down
28 changes: 0 additions & 28 deletions examples/data-objects/inventory-app/tests/main.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,31 +22,3 @@ describe.skip("Integration Tests", () => {
// await expect(page).toClick("button", { text: "Roll" });
});
});

describe("Unit tests", () => {
// Demonstrates use with high level service-client container API's like AzureClient and OdspClient.
it("treeDataObject works with container schema", () => {
// TODO: There is no service implementation agnostic client abstraction that can be referred to here (ex: shared by AzureClient and OdspClient).
// This makes documenting compatibility with that implicit common API difficult.
// It also makes writing service agnostic code at that abstraction level harder.
// This should be fixed.
//
// TODO:
// Writing an app at this abstraction level currently requires a lot of boilerplate which also requires extra dependencies.
// Since `@fluid-example/example-utils` doesn't provide that boilerplate and neither do the public packages, there isn't a concise way to actually use this container in this example.
// This should be fixed.
//
// TODO:
// The commonly used boilerplate for setting up a ContainerSchema based application configures the dev-tools, which would be great to include in this example,
// but can't be included due to dependency layering issues.
//
// TODO: THis test setup fails to import files from src, and also errors on unused values, so this can't be enabled.
// const containerSchema = {
// initialObjects: {
// // TODO: it seems odd that DataObjects in container schema need both a key under initialObjects where they are,
// // as well as a key under the root data object, and SharedObjects only need one key.
// tree: treeDataObject("tree", treeConfiguration),
// },
// } satisfies ContainerSchema;
});
});
11 changes: 11 additions & 0 deletions experimental/framework/tree-react-api/.eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/*!
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
* Licensed under the MIT License.
*/

module.exports = {
extends: [require.resolve("@fluidframework/eslint-config-fluid/strict"), "prettier"],
parserOptions: {
project: ["./tsconfig.json", "./src/test/tsconfig.json"],
},
};
13 changes: 13 additions & 0 deletions experimental/framework/tree-react-api/.mocharc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/*!
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
* Licensed under the MIT License.
*/

"use strict";

const getFluidTestMochaConfig = require("@fluid-internal/mocha-test-setup/mocharc-common");

const packageDir = __dirname;
const config = getFluidTestMochaConfig(packageDir);
config.spec = process.env.MOCHA_SPEC ?? "lib/test";
module.exports = config;
6 changes: 6 additions & 0 deletions experimental/framework/tree-react-api/.npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
nyc
*.log
**/*.tsbuildinfo
src/test
dist/test
**/_api-extractor-temp/**
1 change: 1 addition & 0 deletions experimental/framework/tree-react-api/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# @fluid-experimental/tree-react-api
21 changes: 21 additions & 0 deletions experimental/framework/tree-react-api/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
Copyright (c) Microsoft Corporation and contributors. All rights reserved.

MIT License

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
91 changes: 91 additions & 0 deletions experimental/framework/tree-react-api/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# @fluid-experimental/tree-react-api

Utilities for using SharedTree with React.

This package aims to assist SharedTree based React applications handle some common cases by providing code such applications can share.
This should improve the quality of such applications by allowing them to share and improve a single implementation of this logic
(for example ensuring they all handle out of schema documents properly), while reducing the need for boilerplate.

## Known Issues and Limitations

These are a mix of issues that were encountered when authoring this package, as well as limitations of this package.

Some of this logic would be useful for non-react applications: to avoid creating even more septate packages, that logic is not split into its own package.
If there is clear demand for this to be done, it might be done in the future.

There is no service implementation agnostic client abstraction that can be referred to here (ex: shared by TinyliciousClient, AzureClient and OdspClient).
This makes documenting compatibility with that implicit common API difficult.
It also makes writing service agnostic code at that abstraction level harder.

There does not appear to be a local service implementation of the above mentioned abstraction, which makes testing the code in the package harder.

The commonly used boilerplate for setting up a ContainerSchema based application configures the dev-tools,
but currently can't be included in this package due to dependency layering issues.

<!-- AUTO-GENERATED-CONTENT:START (LIBRARY_PACKAGE_README) -->

<!-- prettier-ignore-start -->
<!-- NOTE: This section is automatically generated using @fluid-tools/markdown-magic. Do not update these generated contents directly. -->

**IMPORTANT: This package is experimental.**
**Its APIs may change without notice.**

**Do not use in production scenarios.**

## Using Fluid Framework libraries

When taking a dependency on a Fluid Framework library, we recommend using a `^` (caret) version range, such as `^1.3.4`.
While Fluid Framework libraries may use different ranges with interdependencies between other Fluid Framework libraries,
library consumers should always prefer `^`.

## Installation

To get started, install the package by running the following command:

```bash
npm i @fluid-experimental/tree-react-api
```

## API Documentation

API documentation for **@fluid-experimental/tree-react-api** is available at <https://fluidframework.com/docs/apis/tree-react-api>.

## Contribution Guidelines

There are many ways to [contribute](https://github.com/microsoft/FluidFramework/blob/main/CONTRIBUTING.md) to Fluid.

- Participate in Q&A in our [GitHub Discussions](https://github.com/microsoft/FluidFramework/discussions).
- [Submit bugs](https://github.com/microsoft/FluidFramework/issues) and help us verify fixes as they are checked in.
- Review the [source code changes](https://github.com/microsoft/FluidFramework/pulls).
- [Contribute bug fixes](https://github.com/microsoft/FluidFramework/blob/main/CONTRIBUTING.md).

Detailed instructions for working in the repo can be found in the [Wiki](https://github.com/microsoft/FluidFramework/wiki).

This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [[email protected]](mailto:[email protected]) with any additional questions or comments.

This project may contain Microsoft trademarks or logos for Microsoft projects, products, or services.
Use of these trademarks or logos must follow Microsoft’s [Trademark & Brand Guidelines](https://www.microsoft.com/trademarks).
Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship.

## Help

Not finding what you're looking for in this README? Check out our [GitHub
Wiki](https://github.com/microsoft/FluidFramework/wiki) or [fluidframework.com](https://fluidframework.com/docs/).

Still not finding what you're looking for? Please [file an
issue](https://github.com/microsoft/FluidFramework/wiki/Submitting-Bugs-and-Feature-Requests).

Thank you!

## Trademark

This project may contain Microsoft trademarks or logos for Microsoft projects, products, or services.

Use of these trademarks or logos must follow Microsoft's [Trademark & Brand Guidelines](https://www.microsoft.com/en-us/legal/intellectualproperty/trademarks/usage/general).

Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship.

<!-- prettier-ignore-end -->

<!-- AUTO-GENERATED-CONTENT:END -->
4 changes: 4 additions & 0 deletions experimental/framework/tree-react-api/api-extractor-lint.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json",
"extends": "../../../common/build/build-common/api-extractor-lint.esm.primary.json"
}
4 changes: 4 additions & 0 deletions experimental/framework/tree-react-api/api-extractor.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json",
"extends": "../../../common/build/build-common/api-extractor-base.esm.primary.json"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
## API Report File for "@fluid-experimental/tree-react-api"

> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
```ts

import { DataObject } from '@fluidframework/aqueduct/internal';
import type { DataObjectClass } from '@fluidframework/fluid-static';
import type { IFluidDataStoreFactory } from '@fluidframework/runtime-definitions/internal';
import type { IFluidLoadable } from '@fluidframework/core-interfaces';
import { ImplicitFieldSchema } from '@fluidframework/tree/internal';
import * as React_2 from 'react';
import { SchemaIncompatible } from '@fluidframework/tree/internal';
import { TreeConfiguration } from '@fluidframework/tree/internal';
import { TreeFieldFromImplicitField } from '@fluidframework/tree/internal';
import { TreeNode } from '@fluidframework/tree';
import { TreeView } from '@fluidframework/tree/internal';

// @public
export interface IReactTreeDataObject<TSchema extends ImplicitFieldSchema> extends ITreeDataObject<TSchema> {
readonly TreeViewComponent: (props: TreeViewProps<TSchema>) => React_2.JSX.Element;
}

// @public
export interface ITreeDataObject<TSchema extends ImplicitFieldSchema> {
readonly config: TreeConfiguration<TSchema>;
readonly key: string;
readonly tree: TreeView<TSchema>;
}

// @public
export interface SchemaIncompatibleProps {
readonly error: SchemaIncompatible;
readonly upgradeSchema: () => void;
}

// @public
export function treeDataObject<TSchema extends ImplicitFieldSchema>(key: string, treeConfiguration: TreeConfiguration<TSchema>): DataObjectClass<IReactTreeDataObject<TSchema> & IFluidLoadable>;

// @internal
export function treeDataObjectInternal<TSchema extends ImplicitFieldSchema>(key: string, treeConfiguration: TreeConfiguration<TSchema>): DataObjectClass<IReactTreeDataObject<TSchema> & IFluidLoadable & DataObject> & {
readonly factory: IFluidDataStoreFactory;
};

// @public
export interface TreeViewProps<TSchema extends ImplicitFieldSchema> {
readonly errorComponent?: React_2.FC<SchemaIncompatibleProps>;
readonly viewComponent: React_2.FC<{
root: TreeFieldFromImplicitField<TSchema>;
}>;
}

// @public
export function useTree(subtreeRoot: TreeNode): void;

```
Loading

0 comments on commit eda9e6d

Please sign in to comment.