| <!-- | |
| Licensed to the Apache Software Foundation (ASF) under one | |
| or more contributor license agreements. See the NOTICE file | |
| distributed with this work for additional information | |
| regarding copyright ownership. The ASF licenses this file | |
| to you under the Apache License, Version 2.0 (the | |
| "License"); you may not use this file except in compliance | |
| with the License. You may obtain a copy of the License at | |
| http://www.apache.org/licenses/LICENSE-2.0 | |
| Unless required by applicable law or agreed to in writing, | |
| software distributed under the License is distributed on an | |
| "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
| KIND, either express or implied. See the License for the | |
| specific language governing permissions and limitations | |
| under the License. | |
| --> | |
| # Apache Beam Playground | |
| ## About | |
| Beam Playground is an interactive environment to try out Beam transforms and examples. | |
| The vision for the Playground is to be a web application where users can try out Beam | |
| without having to install/initialize a Beam environment. | |
| ## Getting Started | |
| ### Run | |
| See [playground/README.md](../README.md) for details on requirements and setup. | |
| The following command is used to build and serve the frontend app locally: | |
| ```bash | |
| flutter run -d chrome | |
| ``` | |
| ### Build | |
| Run the following command to generate a release build: | |
| ```bash | |
| flutter build web | |
| ``` | |
| This produces `build/web` directory with static files. Deploy them to your web server. | |
| ### Backend Lookup | |
| The file [playground_components/lib/src/constants/backend_urls.dart](playground_components/lib/src/constants/backend_urls.dart) | |
| is the location for backend-related constants. | |
| If the `backendUrlOverrides` map contains a URL for a server then only it will be attempted | |
| for the given container. This is useful for running backend locally. | |
| Otherwise following patterns are tried when looking up the backend servers: | |
| 1. Prepending the frontend host with `router.`, `go.`, `java.`, `python.`, `scio.`. | |
| 2. Prepending the the default production frontend URL with the same. | |
| ### Docker | |
| The app is deployed to production as a Docker container. | |
| You can also run it in Docker locally. This is useful if: | |
| 1. You do not have Flutter and do not want to install it. | |
| 2. You want to mimic the release environment in the closest way possible. | |
| To run the frontend app with Docker, run this in the frontend directory: | |
| ```bash | |
| docker build -t playground-frontend . | |
| docker run -p 1234:8080 playground-frontend | |
| ``` | |
| The container sets up NGINX on port 8080. | |
| This example exposes it as port 1234 on the host, | |
| and the app can be accessed at http://localhost:1234 | |
| ## Code Generation | |
| This project relies on generated code for some functionality: | |
| deserializers, test mocks, constants for asset files, | |
| extracted Beam symbols for the editor, etc. | |
| All generated files are version-controlled, so after checkout the project is immediately runnable. | |
| However, after changes you may need to re-run code generation. | |
| ### Standard Dart Code Generator | |
| Most of the generated files are produced by running the standard Dart code generator. | |
| This only requires Flutter, but must be called on multiple locations. | |
| For convenience, run this single command: | |
| ```bash | |
| ./gradlew :playground:frontend:generateCode | |
| ``` | |
| ### Generating Beam Symbols Dictionaries | |
| Requirements: | |
| - Python 3.8+ with packages: `ast`, `pyyaml`. | |
| Other SDKs will add more requirements as we add extraction scripts for them. | |
| To generate all project's generated files including symbol dictionaries, run: | |
| ```bash | |
| ./gradlew :playground:frontend:generate | |
| ``` | |
| ### Deleting Generated Files | |
| For consistency, it is recommended that you delete and re-generate all files before committing | |
| if you have all required tools on your machine. To delete all generated files, run: | |
| ```bash | |
| ./gradlew :playground:frontend:cleanGenerated | |
| ``` | |
| ## Validation | |
| ### Pre-commit Checks | |
| To run all pre-commit checks, execute this in the beam root: | |
| ```bash | |
| ./gradlew :playground:frontend:precommit | |
| ``` | |
| This includes: | |
| - Tests. | |
| - Linter. | |
| ### Code Style | |
| Code can be automatically reformatted using: | |
| ```bash | |
| flutter format ./lib | |
| ``` | |
| ### Unit Tests | |
| To delete all generated files and re-generate them again and then run tests: | |
| ```bash | |
| ./gradlew :playground:frontend:playground_components:test | |
| ./gradlew :playground:frontend:test | |
| ``` | |
| To run tests without re-generating files: | |
| ```bash | |
| cd playground/frontend/playground_components | |
| flutter test | |
| cd .. | |
| flutter test | |
| ``` | |
| ### Integration Tests | |
| 1. Install Google Chrome: https://www.google.com/chrome/ | |
| 2. Install Chrome Driver: https://chromedriver.chromium.org/downloads | |
| - Note: This GitHub action installs both Chrome and Chrome Driver: | |
| https://github.com/nanasess/setup-chromedriver/blob/a249caaaad10fd12103028fd509853c2229eb6e6/lib/setup-chromedriver.sh | |
| 3. Run it on port 4444: `chromedriver --port=4444` | |
| 4. Run: | |
| ```bash | |
| # To run in a visible Chrome window: | |
| ./gradlew :playground:frontend:integrationTest | |
| # Headless run without a browser window: | |
| ./gradlew :playground:frontend:integrationTest -PdeviceId=web-server | |
| ``` | |
| By default, tests do not expect specific code and output from most examples. | |
| This is because we get the expected example files from GitHub itself at runtime. | |
| Examples in the default GitHub branch may differ from the deployed ones, | |
| and this will break the tests. | |
| To expect specific code and output, run tests like this using any repository owner/name | |
| and commit reference to load the examples from: | |
| ```bash | |
| ./gradlew :playground:frontend:integrationTest -PexamplesRepository=apache/beam -PexamplesRef=master | |
| ``` | |
| ## Localization | |
| The project is in the process of migrating from | |
| [the built-in Flutter localization](https://docs.flutter.dev/development/accessibility-and-localization/internationalization) | |
| to [easy_localization](https://pub.dev/packages/easy_localization). | |
| It temporarily uses both ways. | |
| ### Flutter Built-in Localization | |
| To add a new localization, follow next steps: | |
| 1. Create app_YOUR_LOCALE_CODE.arb file with your key-translation pairs, except description tags, in lib/l10n directory (use app_en.arb as example). | |
| 2. Add Locale('YOUR_LOCALE_CODE') object to static const locales variable in lib/l10n/l10n.dart file. | |
| 3. Run the following command to generate a build and localization files: | |
| ```bash | |
| flutter build web | |
| ``` | |
| ### easy_localization | |
| To add a new localization (using `fr` as an example): | |
| 1. Create `playground_components/assets/translations/fr.yaml`. | |
| Fill it with content copied from an existing translation file in another language. | |
| 2. Create `assets/translations/fr.yaml`. | |
| Fill it with content copied from an existing translation file in another language. | |
| 3. Add the locale to the list in `lib/l10n/l10n.dart`. | |
| ## URLs and Embedding | |
| ### Linking to a single example | |
| #### 1. Linking to a catalog example by path | |
| `https://play.beam.apache.org/?path=SDK_JAVA_AggregationMax&sdk=java` | |
| Handled by `StandardExampleLoader`. | |
| #### 2. Linking to the default catalog example | |
| `https://play.beam.apache.org/?sdk=python&default=true` | |
| Handled by `CatalogDefaultExampleLoader`. | |
| #### 3. Linking to a user-shared example | |
| `https://play.beam.apache.org/?sdk=java&shared=sdFdNV324HC` | |
| Handled by `UserSharedExampleLoader`. | |
| #### 4. Linking to an example by URL | |
| `https://play.beam.apache.org/?sdk=go&url=https://raw.githubusercontent.com/golang/go/master/src/fmt/format.go` | |
| Handled by `HttpExampleLoader`. The server with the example file must allow | |
| the cross-origin access. GitHub is known to allow it. | |
| Some servers may have different cross-origin policies when requested from localhost | |
| and other domains. | |
| #### 5. Linking to an empty editor | |
| `https://play.beam.apache.org/?sdk=go&empty=true` | |
| Handled by `EmptyExampleLoader`. | |
| ### Passing view options | |
| Additional options may be passed with any of the above URL patterns. | |
| For them to work, the example must contain sections with the following syntax: | |
| ``` | |
| // [START section_name] | |
| void method() { | |
| ... | |
| } | |
| // [END section_name] | |
| ``` | |
| See more on the syntax and limitations in the | |
| [README of the editor](https://pub.dev/packages/flutter_code_editor) | |
| that Playground uses. | |
| These options can be combined. | |
| #### Read-only sections | |
| Add `readonly` parameter with comma-separated section names: | |
| `https://play.beam.apache.org/?sdk=go&url=https://raw.githubusercontent.com/GoogleCloudPlatform/golang-samples/main/iam/snippets/roles_get.go&readonly=iam_get_role` | |
| #### Folding everything except sections | |
| Add `unfold` parameter with comma-separated section names: | |
| `https://play.beam.apache.org/?sdk=go&url=https://raw.githubusercontent.com/GoogleCloudPlatform/golang-samples/main/iam/snippets/roles_get.go&unfold=iam_get_role` | |
| This folds all foldable blocks that do not overlap with | |
| any of the given sections. | |
| #### Hiding everything except a section | |
| Add `show` parameter with a single section name: | |
| `https://play.beam.apache.org/?sdk=go&url=https://raw.githubusercontent.com/GoogleCloudPlatform/golang-samples/main/iam/snippets/roles_get.go&show=iam_get_role` | |
| It is still the whole snippet that is sent for execution although only the given section | |
| is visible. | |
| This also makes the editor read-only so the user cannot add code that conflicts | |
| with the hidden text. | |
| ### Linking to multiple examples | |
| With the above URLs, when the SDK is switched the following will be shown: | |
| - The catalog default example for the new SDK in the standalone playground. | |
| - The empty editor for the new SDK in the embedded playground. | |
| This can be changed by linking to multiple examples, up to one per SDK. | |
| For this purpose, make a JSON array with any combination of parameters that | |
| are allowed for loading single examples, for instance: | |
| ```json | |
| [ | |
| { | |
| "sdk": "java", | |
| "path": "SDK_JAVA_AggregationMax" | |
| }, | |
| { | |
| "sdk": "go", | |
| "url": "https://raw.githubusercontent.com/GoogleCloudPlatform/golang-samples/main/iam/snippets/roles_get.go", | |
| "readonly": "iam_get_role" | |
| } | |
| ] | |
| ``` | |
| Then pass it in`examples` query parameter like this: | |
| `https://play.beam.apache.org/?sdk=go&examples=[{"sdk":"java","path":"SDK_JAVA_AggregationMax"},{"sdk":"go","url":"https://raw.githubusercontent.com/GoogleCloudPlatform/golang-samples/main/iam/snippets/roles_get.go","readonly":"iam_get_role"}]` | |
| This starts with the Go example loaded from the URL. | |
| If SDK is then switched to Java, the `AggregationMax` catalog example is loaded for it. | |
| If SDK is switched to any other one, the default example for that SDK is loaded | |
| because no override was provided. | |
| ### Embedded vs Standalone Playground URLs | |
| Embedded Playground is a simplified interface supporting all the same features | |
| as the primary interface which is also known as the Standalone Playground. | |
| The embedded Playground URLs start with `https://play.beam.apache.org/embedded` | |
| and use the same query string parameters as the standalone playground. | |
| Additionally the Embedded playground supports the following parameters: | |
| - `editable=0` to make the editor read-only. | |
| ### Embedding into HTML | |
| Use the `<iframe>` tag to embed playground with any of the above URL patterns, for example: | |
| ```html | |
| <iframe | |
| src="https://play-dev.beam.apache.org/embedded?path=SDK_JAVA_AggregationMax&sdk=java" | |
| width="800px" | |
| height="500px" | |
| allow="clipboard-write" | |
| /> | |
| ``` | |
| Note that for the simplified embedded interface you need to use `/embedded` in the URL | |
| otherwise the more complex default interface is shown. | |
| Such URLs and `iframe` code can also be generated by clicking "Share my code" button | |
| in the Standalone Playground. | |
| ### Embedding into the Beam documentation | |
| Beam documentation is written in Markdown and uses [Hugo Markdown preprocessor](https://gohugo.io). | |
| Use the custom shortcodes to embed Playground into the documentation: | |
| - `playground` shortcode, see [a comment in it](https://github.com/apache/beam/blob/master/website/www/site/layouts/shortcodes/playground.html) for a complete example. | |
| - `playground_snippet` shortcode, see [a comment in it](https://github.com/apache/beam/blob/master/website/www/site/layouts/shortcodes/playground_snippet.html) for all supported options. | |
| These shortcodes generate an `iframe` with the URLs described above. | |
| ## Contribution guide | |
| If you'd like to contribute to the Apache Beam Playground website, read | |
| our [contribution guide](CONTRIBUTE.md) where you can find detailed instructions on how to work with | |
| the playground. |