From a5efba6564d911c530d90200643447914d9de95e Mon Sep 17 00:00:00 2001 From: Darkhan Nausharipov <31556582+nausharipov@users.noreply.github.com> Date: Fri, 13 Jan 2023 21:53:06 +0600 Subject: [PATCH] [ToB] [Frontend] Authentication, unit progress, complete unit, SDK selection (#24457) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Content tree navigation (#23593) Unit content navigation (#23593) Update URL on node click (#23593) Active unit color (#23593) removeListener in unit (#23593) First unit is opened on group title click (#23593) WIP by Alexey Inkin (#23593) selectedUnitColor (#23593) Unit borderRadius (#23593) RegExp todo (#23593) added referenced collection package to remove warning (#23593) small refinement (#23593) expand on group tap, padding, openNode (#23593) group expansion bug fix (#23593) selected & unselected progress indicators (#23593) * AnimatedBuilders instead of StatefulWidgets in unit & group (#23593) * fixed _getNodeAncestors (#23593) * get sdkId (#23593) * addressing comments (#23593) * sdkId getter & StatelessExpansionTile (#23593) * expand & collapse group (#23593) * StatelessExpansionTile (#23593) * license (#23593) * ValueChanged and ValueKey in StatelessExpansionTile (#23593) * optional SDK selector in tour scaffold * AppNotifier * moved AppNotifier into _initializeState * StorageKeys * remove listener * auth, complete unit, user progress AuthNotifier draft (#23692) Comments (#23692) Comments (#23692)(1) sign in with google works (#23692) new configs (#23692) get user progress draft (#23692) comment fixes (#23692) sign in in IntroTextBody (#23692) reverted config (#23692) comment fixes (#23692) WIP before rebase (merge) (#23692) Squashed commit of the following: commit bff4919ff00ec3b5d7186efde41c884dfc4c8344 Merge: 79ba69483a ce8d618c77 Author: Alexey Romanenko <33895511+aromanenko-dev@users.noreply.github.com> Date: Thu Nov 17 10:34:02 2022 +0100 Merge pull request #24186: Uses _all to follow alias/datastreams when estimating index size commit 79ba69483a84ea0278d0b0ddb141200739607c77 Merge: 245fea9040 b7e860a762 Author: Chamikara Jayalath Date: Wed Nov 16 20:47:40 2022 -0800 Merge pull request #24218: Update Python wheel format for RC validation commit 245fea904014cd58d4148807463dbaa40000774c Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed Nov 16 18:12:33 2022 -0800 Bump loader-utils from 1.4.1 to 1.4.2 in /sdks/python/apache_beam/runners/interactive/extensions/apache-beam-jupyterlab-sidepanel (#24191) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> commit e1de8e78deeb5d17617fda6591429eaaf8abb8a2 Author: Yi Hu Date: Wed Nov 16 20:48:06 2022 -0500 Fix PythonLint (#24219) commit b7e860a7621771c300dcec625655f87e62591323 Author: Chamikara Jayalath Date: Wed Nov 16 17:28:31 2022 -0800 updates commit c2feb09ea49dd815b69c65e531ce34128756d988 Author: Chamikara Jayalath Date: Wed Nov 16 17:06:08 2022 -0800 updates commit ce8d618c77d23e20a1ddb128bb8183048597d096 Author: egalpin Date: Wed Nov 16 16:43:57 2022 -0800 Adds test for following aliases when estimating index size commit 959719d01c627328c0ca2849d2b7e2c9b322d4d1 Author: Chamikara Jayalath Date: Wed Nov 16 15:16:06 2022 -0800 Temporary update Python RC validation job commit b952b41788acc20edbe5b75b2196f30dbf8fdeb0 Author: Yi Hu Date: Wed Nov 16 14:18:12 2022 -0500 Python TextIO Performance Test (#23951) * Python TextIO Performance Test * Add filebasedio_perf_test module for unified test framework for Python file-based IOs * Fix MetricsReader publishes metrics duplicately if more than one load test declared. This is because MetricsReader.publishers was static class variable * Fix pylint * Distribute Python performance tests random time at a day instead of all at 3PM * Add information about length conversion commit 017f2cbde124af40a43be99ec88289fcf63c1c95 Merge: fef8acdbc0 88dba4f494 Author: Chamikara Jayalath Date: Wed Nov 16 10:39:52 2022 -0800 Merge pull request #24187: Add a reference to Java RunInference example commit fef8acdbc0ecbcc85b49144adaf8830e3bc6b2de Merge: 6e9187e67e ead245539d Author: Ahmet Altay Date: Wed Nov 16 10:24:53 2022 -0800 Merge pull request #24199 from Laksh47/issue#24196 refs: issue-24196, fix broken hyperlink commit 6e9187e67e1bd8f73997f437f0ed4c29880ed73b Author: Darkhan Nausharipov <31556582+nausharipov@users.noreply.github.com> Date: Wed Nov 16 22:33:50 2022 +0600 [Tour of Beam] [Frontend] Content tree URLs (#23776) * Content tree navigation (#23593) Unit content navigation (#23593) Update URL on node click (#23593) Active unit color (#23593) removeListener in unit (#23593) First unit is opened on group title click (#23593) WIP by Alexey Inkin (#23593) selectedUnitColor (#23593) Unit borderRadius (#23593) RegExp todo (#23593) added referenced collection package to remove warning (#23593) small refinement (#23593) expand on group tap, padding, openNode (#23593) group expansion bug fix (#23593) selected & unselected progress indicators (#23593) * AnimatedBuilders instead of StatefulWidgets in unit & group (#23593) * fixed _getNodeAncestors (#23593) * get sdkId (#23593) * addressing comments (#23593) * sdkId getter & StatelessExpansionTile (#23593) * expand & collapse group (#23593) * StatelessExpansionTile (#23593) * license (#23593) * ValueChanged and ValueKey in StatelessExpansionTile (#23593) Co-authored-by: darkhan.nausharipov Co-authored-by: Alexey Inkin commit b33fac2aa533d77cfa47f88466c8cd6bd3f3e864 Author: Bruno Volpato Date: Wed Nov 16 10:51:11 2022 -0500 Use only ValueProviders in SpannerConfig (#24156) commit 5f013ab6567ec75b460b2081d7f89d332320caff Author: Robert Burke Date: Wed Nov 16 07:23:10 2022 -0800 revert upgrade to go 1.19 for action unit tests (#24189) commit 9337f4dbecc929886f8559949a082a649fd9d1bb Author: Yi Hu Date: Wed Nov 16 10:18:42 2022 -0500 Fix Python PostCommit Example CustomPTransformIT on portable (#24159) * Fix Python PostCommit Examples on portable * Fix custom_ptransform pipeline options gets modified * Specify flinkConfDir commit ead245539d01dec0f3e08699c1e1cc6777a5ef0e Author: Laksh Date: Wed Nov 16 09:32:46 2022 -0500 refs: issue-24196, fix broken hyperlink commit e83a996d4374d467d95bcfad7166905622ec615c Merge: 2fc56ec663 ffdee0b6ed Author: Jan Lukavský Date: Wed Nov 16 15:15:31 2022 +0100 Merge pull request #24192: Re-use serializable pipeline options when already available. commit ffdee0b6edb8638c78a65ec85c727ea5dde1cb2f Author: Jozef Vilcek Date: Mon Nov 14 16:48:18 2022 +0100 Re-use serializable pipeline options when already available (#24192) commit 88dba4f494829b2b3530b767fb8c5252e0d2ba44 Author: Chamikara Jayalath Date: Tue Nov 15 16:21:22 2022 -0800 Add a reference to Java RunInference example commit 2fc56ec663e335cfcf37dc57d471f79b601414f4 Merge: f763186987 83f1bc19b9 Author: Kenn Knowles Date: Tue Nov 15 16:16:47 2022 -0800 Merge pull request #24142: Fix arguments to checkState in BatchViewOverrides commit f763186987c00ba1d26efdc35406436a1fa69a9a Merge: c2bc2135e9 0d7ca04182 Author: Ning Kang Date: Tue Nov 15 15:25:20 2022 -0800 Addresses #24161 Updated README of Interactive Beam commit c2bc2135e9bce715990a5d5551e2bc2dc0311da4 Author: Doug Judd Date: Tue Nov 15 14:48:26 2022 -0800 Strip FGAC database role from changestreams metadata requests (#24177) Co-authored-by: Doug Judd commit af637974f96ad1b5110d7dea3f9a26c68e19a51b Author: Jack McCluskey <34928439+jrmccluskey@users.noreply.github.com> Date: Tue Nov 15 17:16:43 2022 -0500 Add custom inference function support to the PyTorch model handler (#24062) * Initial type def and function signature * [Draft] Add custom inference fn support to Pytorch Model Handler * Formatting * Split out default * Remove Keyed version for testing * Move device optimization * Make default available for import, add to test classes * Remove incorrect default from keyed test * Keyed impl * Fix device arg * custom inference test * formatting * Add helpers to define custom inference functions using model methods * Trailing whitespace * Unit tests * Fix incorrect getattr syntax * Type typo * Fix docstring * Fix keyed helper, add basic generate route * Modify generate() to be different than forward() * formatting * Remove extra generate() def commit a014637106970a0a0e9eb7944aa5caf79fa5fd37 Author: egalpin Date: Tue Nov 15 13:57:54 2022 -0800 Uses _all to follow alias/datastreams when estimating index size Fixes #24117 commit 0d7ca041823bc2b09f76f86fdfd1d0b9508c9c88 Author: Ning Kang Date: Tue Nov 15 13:57:27 2022 -0800 Minor update commit e8fc759d756f4a987e41d2b9da56b906a6cd7736 Author: Ning Kang Date: Tue Nov 15 13:52:18 2022 -0800 Updated README of Interactive Beam Removed deprecated cache_dir runner param in favor of the cache_root global option. commit 08d5f72e5f35d41f3e9fa9fe799caea6bed1b7a7 Author: Anand Inguva <34158215+AnandInguva@users.noreply.github.com> Date: Tue Nov 15 16:34:21 2022 -0500 [Python]Support pipe operator as Union (PEP -604) (#24106) Fixes https://github.com/apache/beam/issues/21972 commit 526e7a58b62682582c27173ab21ed8667ddab766 Author: Scott Strong Date: Tue Nov 15 16:26:45 2022 -0500 Using Teardown context instead of deprecated finalize (#24180) * Using Teardown context instead of deprecated finalize * making function public Co-authored-by: Scott Strong commit fb4d1d4dea7b26ed538a9f6aca0ed41e8c300e37 Author: Danny McCormick Date: Tue Nov 15 16:25:22 2022 -0500 Fix broken json for notebook (#24183) commit f98db2008a97f4546d036ddf0dddfee8c87eb58a Author: Robert Burke Date: Tue Nov 15 12:49:23 2022 -0800 Update automation to use Go 1.19 (#24175) Co-authored-by: lostluck <13907733+lostluck@users.noreply.github.com> commit e5f58504eef1fdeebe0402cda8a2df259169c704 Author: Brian Hulette Date: Tue Nov 15 12:25:13 2022 -0800 Add error reporting for BatchConverter match failure (#24022) * add error reporting for BatchConverters * Test pytorch * Finish up torch tests * yapf * yapf * Remove else commit 3037747f66f0d71d65b6c65745b4f8942c22f05a Author: Danny McCormick Date: Tue Nov 15 14:13:04 2022 -0500 Fix broken notebook (#24179) commit b2b1c739ce37690923891934ee317f799db937a2 Author: MakarkinSAkvelon <67736809+MakarkinSAkvelon@users.noreply.github.com> Date: Tue Nov 15 21:53:06 2022 +0500 [Playground] Move Playground in GKE and Infrastructure change (#23928) * changes to updated master branch * Change workflow * ingress changes * Certificate was added * Updates for cloud build backend * Update main.tf * Create main.tf * Create variables.tf * Update variables.tf * Update main.tf * Update variables.tf * Update main.tf * Create output.tf * Update output.tf * Update output.tf * Update main.tf * Update build.gradle.kts * Update output.tf * Update main.tf * Update main.tf * Update main.tf * Update variables.tf * Update main.tf * Update variables.tf * Update main.tf * Update main.tf * Update main.tf * Update main.tf * Update main.tf * Update main.tf * Update variables.tf * Update main.tf * Update variables.tf * Update main.tf * Update variables.tf * Update main.tf * Update main.tf * Update main.tf * Update main.tf * Update main.tf * Update main.tf * Update main.tf * Update main.tf * Update output.tf * Update main.tf * Update main.tf * Update output.tf * Create variables.tf * Update main.tf * Update main.tf * Delete playground/terraform/infrastructure/cluddns directory * Update main.tf * Update output.tf * Update output.tf * Update build.gradle.kts * Update build.gradle.kts * Update build.gradle.kts * Update build.gradle.kts * Update build.gradle.kts * Update build.gradle.kts * Update README.md * Update README.md * helm folder name was changed * Update README.md * Update build.gradle.kts * Update build.gradle.kts * Update build.gradle.kts * Updates to readme * Fix DNS name * HelmChart was changed * Some workflows were changed * Remove unused file * playground-examples return * add license information * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * remove "stg" folder * Update README.md * Remove unused files * DNS Removed * var name changed * remove DNSName from var file * 1 * Clear terraform * remove unused records * gradle check * grade last change * issue fix * fix * 1 * run * test * Index creation for Gradle * Add IndexCreation in gradle * Update README.md * Update README.md * Fix names for Frontend * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Redis fix * services fix * Update variables.tf * change order in gradle * Fix Config.g.dart file issue * Update README.md * Playground workflow update Co-authored-by: Sergey Makarkin Co-authored-by: Sergey Makarkin Co-authored-by: ruslan-ikhsan Co-authored-by: Alex Kosolapov commit 85df5f2eb2f299e28b36be0cce7b9c19d62124da Author: Yi Hu Date: Tue Nov 15 11:38:13 2022 -0500 Eliminate CalciteUtil.CharType logical type (#24013) * Eliminate CalciteUtils.CharType logical type * Replace CalciteUtils.CharType to String Note that CalciteUtils still omits the precision of BINARY/VARBINARY/CHAR/VARCHAR as what it originally did. Support of the precision of these calcite types involves make use of making use of the overload method RelDataTypeFactory.createSqlType(var1, var2). * Replace every reference of CalciteUtil.CharType to generic PassThroughLogicalType check * Add TODO to Support sql types with arguments * Use VariableString in LogicalTypeTestCase commit f349f41010c5b238ff6020f7de718f938eef3c5e Author: alexeyinkin Date: Tue Nov 15 20:04:01 2022 +0400 Configure flutter_code_editor options with Hugo shortcode (#23926) (#24031) * Configure flutter_code_editor options with Hugo shortcode (#23926) * Minor fixes (#23926) * Refactor after review (#23926) commit 0f4ca6363b3ce0e5de3ad36517bb406aa6391a18 Author: Rebecca Szper <98840847+rszper@users.noreply.github.com> Date: Tue Nov 15 06:10:13 2022 -0800 Editorial review of the ML notebooks. (#24125) * Editorial review of the ML notebooks. * Editorial review of the ML notebooks. * Editorial review of the ML notebooks. * Update examples/notebooks/beam-ml/custom_remote_inference.ipynb Co-authored-by: Danny McCormick * Updating based on feedback * Update examples/notebooks/beam-ml/run_inference_sklearn.ipynb Co-authored-by: Danny McCormick * Update examples/notebooks/beam-ml/run_inference_tensorflow.ipynb Co-authored-by: Danny McCormick * Update examples/notebooks/beam-ml/run_inference_tensorflow.ipynb Co-authored-by: Danny McCormick * Update examples/notebooks/beam-ml/run_inference_tensorflow.ipynb Co-authored-by: Danny McCormick * Updating based on feedback Co-authored-by: Danny McCormick commit 5bd34ede026253326ebff1a7e4f9edb5f71b4a2c Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue Nov 15 07:17:28 2022 -0500 Bump github.com/aws/aws-sdk-go-v2/feature/s3/manager in /sdks (#24131) Bumps [github.com/aws/aws-sdk-go-v2/feature/s3/manager](https://github.com/aws/aws-sdk-go-v2) from 1.3.2 to 1.11.39. - [Release notes](https://github.com/aws/aws-sdk-go-v2/releases) - [Changelog](https://github.com/aws/aws-sdk-go-v2/blob/main/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-go-v2/compare/v1.3.2...feature/s3/manager/v1.11.39) --- updated-dependencies: - dependency-name: github.com/aws/aws-sdk-go-v2/feature/s3/manager dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> commit 2ee809fa0ca7689dd0279e186ebc02d9569a8429 Merge: e3b9bdb2e6 563c66d6fd Author: Alexey Romanenko <33895511+aromanenko-dev@users.noreply.github.com> Date: Tue Nov 15 11:01:14 2022 +0100 Merge pull request #23065: [Website] Update copy icon styles commit e3b9bdb2e607d85a4017ba7839000e92a0ad83c4 Author: Moritz Mack Date: Tue Nov 15 10:40:50 2022 +0100 [Dockerized Jenkins] Fix build of dockerized jenkins (fixes #24053) (#24054) commit faaac2ab6e010374cb2be0e95a5dd345836a2a2c Author: Moritz Mack Date: Tue Nov 15 10:38:59 2022 +0100 [Dockerized Jenkins] Update README how to use local repo (#24055) commit 689e70b5131620540faf52e2f1e2dca7a36f269d Author: Damon Date: Mon Nov 14 17:34:29 2022 -0800 Implement embedded WebAssembly example (#24081) commit e1bf6c42950e8013f35e35fb9fee8017e01e5010 Merge: eddac84126 10337d2868 Author: Robert Bradshaw Date: Mon Nov 14 15:22:14 2022 -0800 Merge pull request #24160 Rename the test_splits flag to direct_test_splits. commit eddac841261228a2c63fa9b225c520ae0f853806 Author: Pablo Date: Mon Nov 14 15:05:05 2022 -0800 More dataset templates to clean up (#24162) commit 2adb68bd12743566cc89b596bf204d7c807eb62d Author: Pablo Date: Mon Nov 14 13:28:13 2022 -0800 Adding a quickstart to README for the TS SDK (#23509) * More of a quickstart for the TS SDK * Update sdks/typescript/README.md Co-authored-by: Danny McCormick * Update sdks/typescript/README.md Co-authored-by: Danny McCormick Co-authored-by: Danny McCormick commit 10337d28685ad5712e2ad8608977ec5c5e0e6b6b Author: Robert Bradshaw Date: Mon Nov 14 12:46:32 2022 -0800 Rename the test_splits flag to direct_test_splits. This avoids possible flag conflicts. commit 48c70cc30742b45b17a1d18ece2f0d079bee3915 Author: arne-alex <108519096+arne-alex@users.noreply.github.com> Date: Mon Nov 14 21:33:02 2022 +0100 Merge pull request #23333: Track time on Cloud Dataflow streaming data reads and export via heartbeats commit 9c83de646ab52bd0b05e3346190dd55cd68b2a8b Author: Johanna Öjeling <51084516+johannaojeling@users.noreply.github.com> Date: Mon Nov 14 21:19:44 2022 +0100 Add more tests for S3 filesystem (#24138) commit 9e9c6d797ba52b460f83131431c8e53aebbbc9ac Merge: d5d76b9745 c600444e1d Author: Ning Kang Date: Mon Nov 14 12:06:15 2022 -0800 Merge pull request #24029 from apache/dependabot/npm_and_yarn/sdks/python/apache_beam/runners/interactive/extensions/apache-beam-jupyterlab-sidepanel/loader-utils-1.4.1 Bump loader-utils from 1.4.0 to 1.4.1 in /sdks/python/apache_beam/runners/interactive/extensions/apache-beam-jupyterlab-sidepanel commit d5d76b974592d45de368ab641647ca5cc4ec12ec Author: Yi Hu Date: Mon Nov 14 15:03:28 2022 -0500 Support SqlTypes Date and Timestamp (MicrosInstant) in AvroUtils (#23969) * Support SqlTypes Date and Timestamp (MicrosInstant) in AvroUtils * Add TODO about java.time migration commit 330cc2010c9f4a2d4e30318bf50a4109ec1cd392 Author: Pablo Date: Mon Nov 14 12:02:10 2022 -0800 Cleanup stale BQ datasets (#24158) * Cleanup stale BQ datasets * addressing comments commit 4a044999b8ed4bcd41f816f3a23ccb5da00c4c38 Merge: e563b9dd2f 5bd75c25de Author: Heejong Lee Date: Mon Nov 14 11:16:00 2022 -0800 Merge pull request #24076 from chamikaramj/multilang_java_updates Updates Multi-lang Java quickstart commit e563b9dd2f3aa0484e6cdc08869991b5e438023e Author: Evgeny Antyshev Date: Mon Nov 14 20:56:35 2022 +0300 [Tour Of Beam] verify that unit exists when saving progress (#24118) * AIO * Update learning/tour-of-beam/backend/integration_tests/auth_test.go Co-authored-by: Danny McCormick * nit Co-authored-by: Danny McCormick commit 774923e0dd089de870bfa5c77063ae2b28f79347 Merge: 71785de528 1ad0cbc445 Author: Kenn Knowles Date: Mon Nov 14 09:52:26 2022 -0800 Merge pull request #24141: Fix checkArgument format in GcsPath commit 71785de52864313c2e3b14fe72a2a63281343617 Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon Nov 14 11:54:37 2022 -0500 Bump github.com/aws/aws-sdk-go-v2/config from 1.17.10 to 1.18.0 in /sdks (#24151) Bumps [github.com/aws/aws-sdk-go-v2/config](https://github.com/aws/aws-sdk-go-v2) from 1.17.10 to 1.18.0. - [Release notes](https://github.com/aws/aws-sdk-go-v2/releases) - [Changelog](https://github.com/aws/aws-sdk-go-v2/blob/main/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-go-v2/compare/config/v1.17.10...config/v1.18.0) --- updated-dependencies: - dependency-name: github.com/aws/aws-sdk-go-v2/config dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> commit 50d591d6cb3e799bee4e29dfc593c693a86e6276 Author: Bruno Volpato Date: Mon Nov 14 11:50:01 2022 -0500 Change DataflowBatchWorkerHarness doWork error level to INFO (#24135) commit 5a72696bfda09fdb905ba8e58b636f8494ef955f Merge: ee0a5836d6 0633fe9634 Author: Kenn Knowles Date: Mon Nov 14 08:12:12 2022 -0800 Merge pull request #24149: Remove extraneous jetbrains annotation commit ee0a5836d69b776834eb3bd9b2bd02eb5252c333 Merge: d001a69e1a 137799672e Author: Kenn Knowles Date: Mon Nov 14 08:11:00 2022 -0800 Merge pull request #24132: Fix checkArgument format string in AvroIO commit d001a69e1a58701d6ed4fcb5e3fb7a0921301dad Author: Yi Hu Date: Mon Nov 14 10:56:54 2022 -0500 Test Dataproc 2.1 with Flink load tests (#24129) * Test Dataproc 2.1 with Flink load tests * Minor fix flink_cluster script commit caabd9be52887ad70c8a4269395c893811ac6a84 Author: Israel Herraiz Date: Mon Nov 14 16:03:39 2022 +0100 Make MonotonicWatermarkEstimator work like its Java SDK equivalent (#24146) * Make MonotonicWatermarkEstimator work like its Java SDK equivalent The current implementation of MonotonicWatermarkEstimator raises an exception with late messages, which makes the watermark estimator barely usable in real world scenarios. This PR fixes #20041 by making this watermark estimator work like its Java SDK equivalent (`WatermarkEstimators.MonotonicallyIncreasing`). * Update unit tests too * Make linter happy commit 451f6b3e7f58d0a3782ad942c6a1fd9f63932024 Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon Nov 14 09:48:23 2022 -0500 Bump golang.org/x/net from 0.1.0 to 0.2.0 in /sdks (#24153) Bumps [golang.org/x/net](https://github.com/golang/net) from 0.1.0 to 0.2.0. - [Release notes](https://github.com/golang/net/releases) - [Commits](https://github.com/golang/net/compare/v0.1.0...v0.2.0) --- updated-dependencies: - dependency-name: golang.org/x/net dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> commit 2bb03d62e2d7dc2d8e39040fc9adebccbde74fde Merge: 4e39ef2041 623083cd0a Author: Alexey Romanenko <33895511+aromanenko-dev@users.noreply.github.com> Date: Mon Nov 14 15:01:13 2022 +0100 Merge pull request #24000: [Website] Change headers size from h4,h3 to h2 commit 563c66d6fd32165da14a07747f2764c17a5d24ea Author: bulat safiullin Date: Wed Sep 7 18:28:42 2022 +0600 [Website] update pre tag copy link styles #23064 commit 4e39ef20410ee51c6040317bcd60171e64c5171f Merge: 223768f782 105ed6fedc Author: Alexey Romanenko <33895511+aromanenko-dev@users.noreply.github.com> Date: Mon Nov 14 10:55:33 2022 +0100 Merge pull request #24115: [Website] update go-dependencies.md java-dependencies.md links commit 223768f782f771f0033b8d0686d86cf4c71fad75 Merge: aa0a35dabf a9da2abee6 Author: Kenn Knowles Date: Sun Nov 13 18:53:13 2022 -0800 Merge pull request #24136: Fix checkArgument format string in ExecutionStateTracker commit 0633fe9634fe61df7cbc0ecac205d81124fd504a Author: Kenneth Knowles Date: Sat Nov 12 15:15:16 2022 -0800 Remove extraneous jetbrains annotation commit 83f1bc19b95935e60ca1f4027d4b60c7e738a84a Author: Kenneth Knowles Date: Sat Nov 12 14:16:09 2022 -0800 Fix arguments to checkState in BatchViewOverrides commit 1ad0cbc44594d8405bf4b07a126265238013a02a Author: Kenneth Knowles Date: Sat Nov 12 13:41:02 2022 -0800 Fix checkArgument format in GcsPath commit aa0a35dabf9c2a0d9822faff06d939d9a77a3ab6 Author: Kenn Knowles Date: Fri Nov 11 20:26:30 2022 -0800 Fix checkArgument format string in TestStream (#24134) commit a9da2abee6455bc2cf0f18ba5f6cd7bbaeae669f Author: Kenneth Knowles Date: Fri Nov 11 16:54:27 2022 -0800 Fix checkArgument format string in ExecutionStateTracker commit 369e2ba8622d3474c14c39b941b2c618842d1e47 Author: Ryan Thompson Date: Fri Nov 11 19:46:07 2022 -0500 Add a ValidatesContainer integration test for use_sibling_sdk_workers (#24099) commit 137799672eb559a7586262e6a8a73d1ab3580e44 Author: Kenneth Knowles Date: Fri Nov 11 15:30:01 2022 -0800 Fix checkArgument format string in AvroIO commit 5d2dbf957e4e82fb3980726940df02ac67e563cd Author: Anand Inguva <34158215+AnandInguva@users.noreply.github.com> Date: Fri Nov 11 15:57:28 2022 -0500 Update staging of Python wheels (#24114) Fixes https://github.com/apache/beam/issues/24110 commit c2021bee1eba0322b43c90841397859048296b21 Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri Nov 11 15:33:14 2022 -0500 Bump google.golang.org/api from 0.102.0 to 0.103.0 in /sdks (#24049) Bumps [google.golang.org/api](https://github.com/googleapis/google-api-go-client) from 0.102.0 to 0.103.0. - [Release notes](https://github.com/googleapis/google-api-go-client/releases) - [Changelog](https://github.com/googleapis/google-api-go-client/blob/main/CHANGES.md) - [Commits](https://github.com/googleapis/google-api-go-client/compare/v0.102.0...v0.103.0) --- updated-dependencies: - dependency-name: google.golang.org/api dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> commit 6557c91c79480b9d90573d52d257a11c2b160196 Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri Nov 11 11:47:12 2022 -0800 Bump github.com/aws/aws-sdk-go-v2/service/s3 in /sdks (#24112) Bumps [github.com/aws/aws-sdk-go-v2/service/s3](https://github.com/aws/aws-sdk-go-v2) from 1.29.1 to 1.29.2. - [Release notes](https://github.com/aws/aws-sdk-go-v2/releases) - [Changelog](https://github.com/aws/aws-sdk-go-v2/blob/main/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-go-v2/compare/service/s3/v1.29.1...service/s3/v1.29.2) --- updated-dependencies: - dependency-name: github.com/aws/aws-sdk-go-v2/service/s3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> commit 96f9da1ab652156cd143d57e3aa3d94836338f2b Author: Yi Hu Date: Fri Nov 11 14:34:22 2022 -0500 More cleanup containers (#24105) * More cleanup containers * prebuilt_beam_sdk/beam_python_prebuilt_sdk no longer exists in gcr.io Add correct paths to cleanup * Bump grace time to 15 days * Run job daily as in code comment * Set grace period to 30 days commit 836766ddb83d37463e4b036f156b8d7e15e3864b Author: Ritesh Ghorse Date: Fri Nov 11 14:30:30 2022 -0500 upgrade testcontainer dependency (#24123) commit 9fcd20c3712536f2d4580beead678cdbb6fd4746 Author: Damon Date: Fri Nov 11 11:12:11 2022 -0800 Implement PubsubRowToMessage transform (#23897) * Begin PubsubRowToMessage Impl * Complete working draft * Unit tests validate user and non-user fields * Finish tests on supporting methods * Pass checks before finalizing tests * WIP * fix timestamp * finalize tests * Finalize code comments * Clean up check findings * Add InputSchemaFactory * Patch code comment typo commit 3a6fcc1ca4d07a467464ed1214a94b5c9c147295 Author: Evgeny Antyshev Date: Fri Nov 11 19:13:45 2022 +0300 disable (#24121) commit 027fb142038b45c443d87af96cac082264c43188 Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri Nov 11 10:26:23 2022 -0500 Bump cloud.google.com/go/bigtable from 1.17.0 to 1.18.0 in /sdks (#24113) Bumps [cloud.google.com/go/bigtable](https://github.com/googleapis/google-cloud-go) from 1.17.0 to 1.18.0. - [Release notes](https://github.com/googleapis/google-cloud-go/releases) - [Changelog](https://github.com/googleapis/google-cloud-go/blob/main/CHANGES.md) - [Commits](https://github.com/googleapis/google-cloud-go/compare/pubsub/v1.17.0...pubsub/v1.18.0) --- updated-dependencies: - dependency-name: cloud.google.com/go/bigtable dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> commit b2d28a64bb0837dd97e8be7f97f31f88d380f110 Author: Danny McCormick Date: Fri Nov 11 08:45:14 2022 -0500 Add TFX support in pydoc (#23960) * Add TFX support in pydoc * Wording commit 105ed6fedcb6ff33d4a43940c342a653e67cb25e Author: bulat safiullin Date: Thu Nov 10 17:47:54 2022 +0600 [Website] update go-dependencies.md java-dependencies.md programming-guide.md links #24084 commit 4b96193250a63b27721a8c5e1a3bd6ecff983093 Author: Brian Hulette Date: Thu Nov 10 16:51:06 2022 -0800 Remove TheNeuralBit from the pool of Python reviewers (#24108) commit 8f8f089a5f565f179905984cef3522a0577d9219 Author: Sanil Jain Date: Thu Nov 10 16:47:31 2022 -0800 Wire SamzaPipelineOptions to Exeption listener interface (#24109) commit b3186ba91f9bb22764d47b78eb2b7ff017080f75 Author: Ahmed Abualsaud <65791736+ahmedabu98@users.noreply.github.com> Date: Thu Nov 10 18:04:50 2022 -0500 Support using BigQueryIO Storage Read API with SchemaTransforms (#23827) * support schema transform for bq direct read method * use vendor Strings import * add BigQueryServices argument to config object * suppress nullability errors * add package-info.java file to providers subdirectory * removing accidentally created file * added documentation and moved configuration filclass into provider class * validate config params before expansion. config has a validaate me method * updated URN identifier to follow standards commit a4a94da1936d8cd2f8d1145fd2e8329fe06a2990 Author: Oleh Borysevych Date: Fri Nov 11 00:28:43 2022 +0200 fixing linter error (#24104) commit 156a6099d71a155c3379340a0b98256306e1755e Author: Danny McCormick Date: Thu Nov 10 17:26:15 2022 -0500 Add blog post on new ML resources (#24071) * Create ml-resources.md * Add ensemble notebook image * Add image link * Fix image link * Add ml-landing page image * Add image + move around * Add paragraph on upcoming changes * Remove bad whitespace commit 38742d40c895f5d38ee6ee5eb328d11b3262307e Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu Nov 10 16:12:40 2022 -0500 Bump github.com/aws/aws-sdk-go-v2/config from 1.5.0 to 1.17.10 in /sdks (#24080) Bumps [github.com/aws/aws-sdk-go-v2/config](https://github.com/aws/aws-sdk-go-v2) from 1.5.0 to 1.17.10. - [Release notes](https://github.com/aws/aws-sdk-go-v2/releases) - [Changelog](https://github.com/aws/aws-sdk-go-v2/blob/main/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-go-v2/compare/v1.5.0...config/v1.17.10) --- updated-dependencies: - dependency-name: github.com/aws/aws-sdk-go-v2/config dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> commit 92cef32915c40d353b51529a87d8f0131b0a3538 Author: BjornPrime <32173247+BjornPrime@users.noreply.github.com> Date: Thu Nov 10 15:30:37 2022 -0500 Num failed inferences (#23830) * created test_increment_num_failed_inferences and test_num_failed_inferences_no_failures * added assertRaises to test_increment_num_failed_inferences * added num_failed_inferences to _MetricsCollector * changed error handling and update() implementation * updated metric name in tests * removed unnecessary else blocking * removed unnecessary inference_args from test_increment_failed_batches_counter() * changed final test_increment_failed_batches_counter assertion * clarified error handling and updated failed_batches_counter initialization * decreased examples array length to 1 to ensure repeatability * troubleshooting tests * trying to get test_increment_failed_batches_counter to fail as expected * corrected assertion details * simplified assertRaises and added reminder comment to assertEqual counter * lint test * lint test passed, resetting pre-commit-config.yaml * fixed lingering linting issues * shortened comment line to comply with linting * formatter worked its magic commit 2341f61d48d838ddaf2e4fb990a49987244c3513 Author: Evgeny Antyshev Date: Thu Nov 10 21:24:55 2022 +0300 [Tour Of Beam] handle CORS pre-flight requests (#24083) * cors * README * nit * nit * -headers, -cache * allow-headers * +1h cache,comment commit 36b0c8f1a76865e4dc3b1eaec1566c3ef9fd4345 Author: Evgeny Antyshev Date: Thu Nov 10 21:21:21 2022 +0300 [Playground] update snippet by persistence_key (#24056) * proto * AIO * -frontend * testify * +license * -build * index * skipKey * Update playground/backend/internal/db/datastore/datastore_db.go Co-authored-by: Danny McCormick Co-authored-by: Danny McCormick commit df553d1a4c6c6cc9b37ada2a6c84c88d8aef38b9 Author: Ahmed Abualsaud <65791736+ahmedabu98@users.noreply.github.com> Date: Thu Nov 10 13:17:36 2022 -0500 Add random string at the end of BigQuery query job name to make it resilient to retries (#24041) * add random string at the end of query job name * use deterministic temp table name commit e439f4120ef4c25aa36e5b03756dc7391bdbd211 Author: Pablo Date: Thu Nov 10 10:06:26 2022 -0800 Improving stale container cleanup script (#24040) * Improving stale container cleanup script * Avoid also latest image * Update .test-infra/tools/stale_dataflow_prebuilt_image_cleaner.sh Co-authored-by: Yi Hu * Update .test-infra/tools/stale_dataflow_prebuilt_image_cleaner.sh Co-authored-by: Yi Hu Co-authored-by: Yi Hu commit 8d585242e158babd8dd2ca5a6d5a49d353be2935 Author: Anand Inguva <34158215+AnandInguva@users.noreply.github.com> Date: Thu Nov 10 12:58:41 2022 -0500 [Python]Set pickle library at the Pipeline creation stage (#24069) Fixes https://github.com/apache/beam/issues/21615 commit 08b6a524fecc333a12ce42971733ef64ae7d02f1 Author: Janek Bevendorff Date: Thu Nov 10 18:37:09 2022 +0100 [BEAM-12792] Install pipline dependencies to temporary venv (#16658) commit 74f87b0282a23aa01ecb63288013311d207960aa Merge: 38a85b288a 383ea77bc9 Author: Robert Bradshaw Date: Thu Nov 10 09:10:37 2022 -0800 Merge pull request #23985 Support dynamic sharding in the worker. commit 38a85b288ad10171c444d4092eb969ca5de58af3 Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu Nov 10 10:39:15 2022 -0500 Bump github.com/aws/aws-sdk-go-v2/service/s3 in /sdks (#24077) Bumps [github.com/aws/aws-sdk-go-v2/service/s3](https://github.com/aws/aws-sdk-go-v2) from 1.11.1 to 1.29.1. - [Release notes](https://github.com/aws/aws-sdk-go-v2/releases) - [Changelog](https://github.com/aws/aws-sdk-go-v2/blob/main/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-go-v2/compare/v1.11.1...service/s3/v1.29.1) --- updated-dependencies: - dependency-name: github.com/aws/aws-sdk-go-v2/service/s3 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> commit c5110bae06fb9db6cace1f7657745fa97e3f58af Author: Yi Hu Date: Thu Nov 10 10:33:55 2022 -0500 Fix FhirIO javadoc format broken (#24072) commit 623083cd0a72d86c7ecba7653e9a8564861abc4d Author: bulat safiullin Date: Mon Nov 7 16:08:39 2022 +0600 [Website] change headers size from h4,h3 to h2 #24082 commit 5bd75c25de291e517cc5c5799ae4adaaaaceacb7 Author: Chamikara Jayalath Date: Wed Nov 9 18:04:28 2022 -0800 Updates Multi-lang Java quickstart commit 4522f4ce916223afb3c4edd02a7be6018d0ce5a4 Author: Trevor Gevers Date: Wed Nov 9 18:56:18 2022 -0600 Update datastore_wordcount.py (#23724) commit 96cc252348ce7229731be3c74bf5848d1b004c08 Author: tvalentyn Date: Wed Nov 9 16:08:00 2022 -0800 Remove a duplicate label (#24043) commit 62a6bd1e9317a7658810e9a0eebfe925460e8982 Author: Thiago Nunes Date: Thu Nov 10 08:45:27 2022 +1100 test: add more tests to throughput estimator (#23915) Verifies that getting the throughput when no updates have occurred for the size of the window should return 0. commit e6647c34bb367b3058c42d0201150395c534e7ce Author: Ritesh Ghorse Date: Wed Nov 9 15:12:59 2022 -0500 skip output coder field in exp request (#24066) commit 383ea77bc982416afcbbbe11a4dc1f1424670589 Author: Robert Bradshaw Date: Wed Nov 9 10:49:37 2022 -0800 Reduce flakiness of time-based split manager test. Increase wait time from a tenth to half a second. commit 539fa9159ffc116b2e79e6de2804dfdd1c1e4722 Author: Danny McCormick Date: Wed Nov 9 11:45:20 2022 -0500 Convert initialisms to all caps (#24061) * Convert initialisms to all caps * Fix test refs commit 4941b9633c6ccf9eb8aad554186aac24ca7b7492 Author: Ryan Thompson Date: Wed Nov 9 11:25:48 2022 -0500 added comments for tensorflow notebook (#23726) * added comments for tensorflow notebook * added note to string type commit 858f5048f578548a63e5e4319a7ab5363311c269 Merge: 95c121b254 1929968891 Author: Alexey Romanenko <33895511+aromanenko-dev@users.noreply.github.com> Date: Wed Nov 9 16:35:19 2022 +0100 Merge pull request #24057: [Spark Dataset runner] Enable projection pushdown for Spark dataset runner commit 95c121b2549d3f8fda7668e3759b8991b55d9865 Author: Oleh Borysevych Date: Wed Nov 9 16:03:33 2022 +0200 Fix dependency mismatch in Playground Java runner (#24059) * fixing existing and potential dependency mismatch * extract grpc version commit 1929968891d629c83249c574c28db6c103ba9271 Author: Moritz Mack Date: Wed Nov 9 13:35:12 2022 +0100 [Spark Dataset runner] Enable projection pushdown for Spark dataset runner. commit 63362f5ba60a22e77e54c2df47a844f031036309 Author: Johanna Öjeling <51084516+johannaojeling@users.noreply.github.com> Date: Wed Nov 9 07:49:54 2022 +0100 [Go SDK] S3 implementation of the Beam filesystem (#23992) * Implement filesystem for S3 * Update CHANGES.md commit 73142bad2472e4516831c24a8dfb05c9acebf791 Author: Kanishk Karanawat Date: Tue Nov 8 20:46:04 2022 -0500 Handle Avro schema generation for logical data types in BigQueryAvroUtils (#23620): handle avro logical types for TableFieldSchema to Avro schema conversion Co-authored-by: Kanishk Karanawat commit 8db8fae173056c0d89a36a8a5ce0443b6b9e54fa Author: Robert Burke Date: Tue Nov 8 15:56:53 2022 -0800 [Go] Add pipeline resource hints to CHANGES.md (#24036) commit a84b7dc179fed5dfc1d48dddfb04266de3716e31 Author: Robert Bradshaw Date: Mon Nov 7 16:35:25 2022 -0800 Make mypy happy. commit b9655e7de1a682d8ec4efcafb4d610f794e1b40e Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue Nov 8 12:27:38 2022 -0800 Bump cloud.google.com/go/storage from 1.27.0 to 1.28.0 in /sdks (#24028) Bumps [cloud.google.com/go/storage](https://github.com/googleapis/google-cloud-go) from 1.27.0 to 1.28.0. - [Release notes](https://github.com/googleapis/google-cloud-go/releases) - [Changelog](https://github.com/googleapis/google-cloud-go/blob/main/CHANGES.md) - [Commits](https://github.com/googleapis/google-cloud-go/compare/spanner/v1.27.0...spanner/v1.28.0) --- updated-dependencies: - dependency-name: cloud.google.com/go/storage dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> commit 708e05f0dc6c0a2e62674cd0ecb8a6744ae57d3a Author: Brian Hulette Date: Tue Nov 8 12:18:23 2022 -0800 Retroactively announce Batched DoFn support in 2.42.0 Blog (#24011) * Retroactively announce Batched DoFn support in 2.42.0 * Add to blog as well commit b9ff75a18b40141a8d2340e397fd70382b3d4e8f Author: Israel Herraiz Date: Tue Nov 8 20:03:43 2022 +0100 Update my Twitter handle (#23653) commit bf621ccb88023e0bc09752978c099ac4629086e2 Author: Rebecca Szper <98840847+rszper@users.noreply.github.com> Date: Tue Nov 8 10:50:02 2022 -0800 Editorial review of the ML base API descriptions (#24026) commit f0a6ff46619ee1fd0639fa3f06e04708f69dee74 Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue Nov 8 13:04:03 2022 -0500 Bump cloud.google.com/go/bigtable from 1.16.0 to 1.17.0 in /sdks (#24027) Bumps [cloud.google.com/go/bigtable](https://github.com/googleapis/google-cloud-go) from 1.16.0 to 1.17.0. - [Release notes](https://github.com/googleapis/google-cloud-go/releases) - [Changelog](https://github.com/googleapis/google-cloud-go/blob/main/CHANGES.md) - [Commits](https://github.com/googleapis/google-cloud-go/compare/pubsub/v1.16.0...pubsub/v1.17.0) --- updated-dependencies: - dependency-name: cloud.google.com/go/bigtable dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> commit 7dac3f5ef40b5d24b24d9ce5bec4717284260b85 Author: Lukasz Cwik Date: Tue Nov 8 09:42:29 2022 -0800 [#21250] Trivial removal of loop over something that always has one element (#24014) Multiplexing was put into the PCollectionConsumerRegistry a long time ago and this seems to have been missed during that migration. commit a6a9b23fd5b74142c35948f10d1840b882817246 Author: Robert Burke Date: Tue Nov 8 09:19:49 2022 -0800 [Go] Pipeline Resource Hints (#23990) commit 8cf2a63cc25399109f64b84ddfcd7c74d21e61ce Author: tvalentyn Date: Tue Nov 8 09:19:16 2022 -0800 Update release notes. (#23986) commit c600444e1dfa2f4afaad056bc65fa009a60a32bb Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue Nov 8 06:22:14 2022 +0000 Bump loader-utils Bumps [loader-utils](https://github.com/webpack/loader-utils) from 1.4.0 to 1.4.1. - [Release notes](https://github.com/webpack/loader-utils/releases) - [Changelog](https://github.com/webpack/loader-utils/blob/v1.4.1/CHANGELOG.md) - [Commits](https://github.com/webpack/loader-utils/compare/v1.4.0...v1.4.1) --- updated-dependencies: - dependency-name: loader-utils dependency-type: indirect ... Signed-off-by: dependabot[bot] commit 62d8bdc604dfeccae08d00225bce8c9b9c3ffb28 Merge: d4142f7eab 930c4d2d87 Author: Robert Bradshaw Date: Mon Nov 7 15:31:37 2022 -0800 Merge pull request #23789 Better surfacing of Scala support via Scio. commit 7f7713de09b3b0e400ed02ffdfcb34a6a8b6e1e4 Merge: 5f587b9339 d4142f7eab Author: Robert Bradshaw Date: Mon Nov 7 15:29:27 2022 -0800 Merge branch 'master' into javascript-liquid-sharding commit 5f587b9339b3b19ae5c5b1cf15e3ce218f75d21a Author: Robert Bradshaw Date: Mon Nov 7 15:25:33 2022 -0800 Clarifying comments. commit 60fe3cdddf9d3c27d9493b345d1f5f2a9284a76f Author: Robert Bradshaw Date: Mon Nov 7 15:06:26 2022 -0800 Update style sdks/python/apache_beam/runners/portability/fn_api_runner/fn_runner.py Co-authored-by: Danny McCormick commit d4142f7eab7d5a3d21a3d3930c448fe403880f93 Author: Robert Burke Date: Mon Nov 7 12:11:21 2022 -0800 Switch && for || to fix bug in #23889 resolution (#24017) commit 45100d708d954b25b5a884dc3c7a965f008228c6 Author: Danny McCormick Date: Mon Nov 7 14:53:24 2022 -0500 Add files then check cached diff to get untracked files commit 380d4730d3c52b5c2165bdb84aac11d0feccfe4f Author: scwhittle Date: Mon Nov 7 19:33:37 2022 +0100 Enforce splitting invariants by ensuring split state is reset in the same synchronized block as window index increments. (#23882) * Enforce splitting invariants by ensuring split state is reset in the same synchronized block as window index increments. Fixes #23881. * Add missing currentElement = null; Co-authored-by: Lukasz Cwik commit 8b3fd2e0d652045bf94b83638129bb12562ce738 Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon Nov 7 10:33:26 2022 -0800 Bump google.golang.org/api from 0.101.0 to 0.102.0 in /sdks (#23957) Bumps [google.golang.org/api](https://github.com/googleapis/google-api-go-client) from 0.101.0 to 0.102.0. - [Release notes](https://github.com/googleapis/google-api-go-client/releases) - [Changelog](https://github.com/googleapis/google-api-go-client/blob/main/CHANGES.md) - [Commits](https://github.com/googleapis/google-api-go-client/compare/v0.101.0...v0.102.0) --- updated-dependencies: - dependency-name: google.golang.org/api dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> commit 9533fc3757d3041135cbe2f5078dff0855adc1f1 Author: capthiron <24925821+capthiron@users.noreply.github.com> Date: Mon Nov 7 19:32:18 2022 +0100 feat: implement bigtable io connector with write capabilities (#23411) commit c4218e572aa8a8f46b433b60073a59fdd7fdf148 Merge: 23676a9ec1 a5ee669a43 Author: Alexey Romanenko <33895511+aromanenko-dev@users.noreply.github.com> Date: Mon Nov 7 18:24:45 2022 +0100 Merge pull request #23934: [Website] change case studies page mobile layout commit 23676a9ec17069b309e8803d1fbfeb8009035828 Author: Oleh Borysevych Date: Mon Nov 7 17:24:59 2022 +0200 [Tour of Beam] Learning content for "Introduction" module (#23085) * learning content for introduction module * removing white spaces from md files * delete whitespaces * delete whitespaces in python * delete whitespace #2 * divide pipeline concepts * add pipeline example concepts * adding category tag to python examples * adding category to java examples * adding category to go examples * fixed go example * fixed go example compilation * fixing python duplicate example names * add runner concepts * fixing java examples * add licence for runner unit * some minor fixes for unit names * fixed unit name * resolving CR comments * adding complexity to examples * adding tags * fixed go example compilation * fixed python example with duplicate transform * change indent python * fixing missing pipeline options * change arrow symbol * delete example prefix * minor formatting and readability fixes * add example description * minor fix * minor code review comment Co-authored-by: Abzal Tuganbay commit 98d2ffd69ab9d5c49196a78f7c25daacb57b6478 Author: Brian Hulette Date: Mon Nov 7 07:03:12 2022 -0800 Make `documentation/io/connectors/` canonical (#23877) * Drop documentation/io/built-in/ * Update links in Custom I/O pattern commit c0b41fa045418beb782c0a59e6f5c511da898c53 Author: Danny McCormick Date: Mon Nov 7 09:29:08 2022 -0500 Use git diff instead of git diff-index to avoid file timestamp changes being picked up commit 0476d6498217b7b0e833643c47fef2c4bdaec529 Merge: 1d5fc14031 6ae37b6f82 Author: Alexey Romanenko <33895511+aromanenko-dev@users.noreply.github.com> Date: Mon Nov 7 15:28:59 2022 +0100 Merge pull request #23962: [CdapIO] Add sparkreceiver:2 module. commit 1d5fc14031d583e92018ebfbeaff9b4e3b978fdb Author: Danny McCormick Date: Mon Nov 7 09:14:24 2022 -0500 Remove quiet flag on debug commit c08273b9355566181d2d5c0792130f8d5cc1428c Author: Danny McCormick Date: Mon Nov 7 09:12:26 2022 -0500 Correctly print diff and swallow empty commits for the moment commit 66fb431deb77db5f7f0fac31e6bf3b2c094c8ac5 Author: Danny McCormick Date: Mon Nov 7 09:08:53 2022 -0500 Print diff and scope to state path commit e0e10b9e5432643b884c381d145e5924cc4ef193 Author: Danny McCormick Date: Sun Nov 6 12:12:22 2022 -0500 PR Bot - Dont throw error on return code 1 commit bbcb790461c47d22399c681cd42c434b206eb550 Author: Danny McCormick Date: Sun Nov 6 11:59:32 2022 -0500 Fix pr bot - exec doesn't allow command chaining commit 88f9a66a9f4cc2fe3259d5ebd83ebb472a29dd5e Author: Danny McCormick Date: Sun Nov 6 11:46:34 2022 -0500 Fix diff to stop repeated bot runs commit ddb4f2d53538fea68383fe43221d4074d05d11b9 Author: bullet03 Date: Fri Nov 4 16:11:10 2022 -0700 Website add and update logos (#23899) * [Website] add and update logos * Delete talend.svg:Zone.Identifier commit 6d42219ff547720996489aa29de0d64246db2541 Author: Robert Bradshaw Date: Fri Nov 4 14:30:18 2022 -0700 Enable more portable-runner requiring tests. (#23970) * Enable more portable-runner requiring tests. * Run all basic tests on portable runner as well. * Mark ULR tests. commit 1a643d16112a5f3f1418f1be393de51af65d752b Author: David Cavazos Date: Fri Nov 4 13:45:12 2022 -0700 Beam starter projects blog post (#23964) Co-authored-by: Ahmet Altay commit d10b4a28fff667289c146152535275035f2dedf7 Author: Ryan Thompson Date: Fri Nov 4 16:06:49 2022 -0400 removed trailing whitespace (#23987) commit 3bd697561aab4a5d2aa49d29143695d6d57a834a Author: Robert Bradshaw Date: Fri Nov 4 11:43:47 2022 -0700 Add dynamic splitting support to the worker. commit ed520243f472c7224a1f8c74a0c2e8f81965cbfc Author: Robert Bradshaw Date: Fri Nov 4 11:07:40 2022 -0700 Add the a Reshuffle operation and use it in Create. This allows created sources to be staticly and dynamically split. commit 9283512544b8de169be9cd7795b42284fdf45b87 Author: Robert Bradshaw Date: Fri Nov 4 10:28:51 2022 -0700 Add the ability to schedule splits on the ULR via a pipeline option. This can be used to test arbitrary SDKs for behavioral correctness for dynamic splitting. These splits are wall-time based, which isn't ideal, but easier than setting up and managing a cross-process synchronization channel. commit ed7b560d7ce7dda0b55a067b9d9a1a9d692a7d7a Author: Robert Bradshaw Date: Fri Nov 4 09:46:19 2022 -0700 Compute element counts for all PCollections. commit 1cfdb127983a55c77b3259c4fdd248497b28e250 Author: Jack McCluskey <34928439+jrmccluskey@users.noreply.github.com> Date: Fri Nov 4 15:43:16 2022 -0400 Add custom inference fn suport to the sklearn model handlers (#23642) * Add custom inference fn suport to the sklearn model handlers * Clean up import order * Update typing, add numpy unit test * Add Pandas unit test * Formatting, linting * yapf run * Remove trailing whitespace * import order * Change inference_fn to keyword-only arg commit 8617b86fd792ac555233dd79c8ede34c2ce67ecf Merge: aa178f8252 2496a0d1e0 Author: Robert Bradshaw Date: Fri Nov 4 11:42:21 2022 -0700 Merge pull request #23978 Add basic counter support to the typescript SDK. commit 2496a0d1e0fda74e8fc0f24eee011362426369a2 Merge: 64abcbe4a3 aa178f8252 Author: Robert Bradshaw Date: Fri Nov 4 11:15:47 2022 -0700 Merge branch 'master' into javascript-metrics commit aa178f825223cbb0a6208fad0e02f98292eeded1 Merge: 97628802fe 1807c307aa Author: Robert Bradshaw Date: Fri Nov 4 09:34:11 2022 -0700 Merge pull request #23976 Correctly capture log levels and attach stage information. commit 64abcbe4a3a15160aba3f3163ff8cbf5186bbfdb Author: Robert Bradshaw Date: Fri Nov 4 09:27:22 2022 -0700 Only report counters that were actually used. commit 1807c307aa1e493acb2d8ba542baffefcb96e7e2 Author: Robert Bradshaw Date: Fri Nov 4 08:52:21 2022 -0700 Remove obsolete TODO. commit 97628802fe4cf6640a3b6854e27b410dd5731379 Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri Nov 4 11:47:07 2022 -0400 Bump cloud.google.com/go/datastore from 1.8.0 to 1.9.0 in /sdks (#23916) Bumps [cloud.google.com/go/datastore](https://github.com/googleapis/google-cloud-go) from 1.8.0 to 1.9.0. - [Release notes](https://github.com/googleapis/google-cloud-go/releases) - [Changelog](https://github.com/googleapis/google-cloud-go/blob/main/documentai/CHANGES.md) - [Commits](https://github.com/googleapis/google-cloud-go/compare/asset/v1.8.0...asset/v1.9.0) --- updated-dependencies: - dependency-name: cloud.google.com/go/datastore dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> commit 058c56af735e10184d1501cc08cd16af4d21e64a Author: Ayush Sharma <114604338+ayushthe1@users.noreply.github.com> Date: Fri Nov 4 20:58:11 2022 +0530 [Task]: PR Bot will push commits only if they are non-empty (#23937) * fix pr-bot * fix the git pr bot commit 7dba78d611089a1826c5655ed7ffcdf3f6007eae Author: Danny McCormick Date: Fri Nov 4 09:35:16 2022 -0400 Immediately truncate full restriction on drain of periodic impulse (#23765) * Immediately truncate full restriction on drain of periodic impulse * Whitespace format commit 16852518861514a56ad1b57113e3815cfcc8533a Author: Anand Inguva <34158215+AnandInguva@users.noreply.github.com> Date: Fri Nov 4 08:39:34 2022 -0400 TFX image classification example (#23456) * TFX image classification example * TFX image classification with serving model * Add TF Model Wrapper * Clean up code * Refactoring * Add a test for tfx_bsl RunInference * fixup lint * Refactoring * Fixup lint * Add brief summary for the example * Apply suggestions from code review Co-authored-by: Andy Ye * Refactoring code and add comments * Update help description * reorder imports * Reorder imports again * Add docstring * Refactoring * Add pillow to tfx pipeline requirements * Move inferencePostCommitIT to Python 3.9 suite * Uncomment other postcommit suites Co-authored-by: Andy Ye commit 30b26171b4038c1c976adbc3be386e118b35153b Author: Danny McCormick Date: Fri Nov 4 08:22:17 2022 -0400 Update watermark during periodic sequence/impulse (#23507) * Update watermark during periodic sequence/impulse * Remove extraneous import * Formatting * Linting * Only run on dataflow for guaranteed watermark support * More permissive test to avoid timing issues * Test pipeline options * Fix test * Formatting * Formatting * Apply feedback - cleanup/naming/flink * Format * Unused import commit 1563b9721b4bee5a22d384b282762726247e0703 Author: Brian Hulette Date: Fri Nov 4 05:09:39 2022 -0700 Improve Iterator error message (#23972) commit e3987b5435d39c5fb058d4085eb5e210f8756224 Author: Robert Bradshaw Date: Thu Nov 3 17:39:49 2022 -0700 old prettier change commit 89c8dd5ca23591be6c2778045df32c7d08d9f99e Author: Robert Bradshaw Date: Thu Nov 3 17:12:26 2022 -0700 Add distribution metric type. commit e4e606a8f2652c2fa761a95462f230385b6bcb47 Author: Robert Bradshaw Date: Thu Nov 3 17:09:03 2022 -0700 Support metrics over the portability API. commit e04f3d6fdb39528264cb2a14e60e565991121f1c Author: Robert Bradshaw Date: Thu Nov 3 16:52:51 2022 -0700 Add basic counter setting and getting to the typescript SDK. commit 1daa9c373ac7fbdb696120eeaa2ca9e85a679a1f Author: Robert Bradshaw Date: Thu Nov 3 16:01:59 2022 -0700 Cleanup worker logging. Attempt to correctly capture and propagate log levels and attaches stage information to them. Also remove some excessively verbose logs. commit d3a173cf16355bfe23a9d918afa12cd61d290b59 Author: Robert Bradshaw Date: Thu Nov 3 15:11:40 2022 -0700 Move logging to its own module. commit 6ae37b6f82ae3cd77cc82aff4566d8218a8acc57 Author: vitaly.terentyev Date: Thu Nov 3 19:44:54 2022 +0400 Fix sparkreceiver dependencies commit 8223375d2f9606a29d6498a73c1914a61f3277c4 Author: vitaly.terentyev Date: Thu Nov 3 19:34:04 2022 +0400 Add sparkreceiver:2 module. commit a5ee669a439dc3d13dfc4926c1c5ae2351bb9135 Author: bulat safiullin Date: Wed Nov 2 13:53:08 2022 +0600 [Website] change case-study-card width on mobile commit 930c4d2d87d462b2457369fd06066203a6628a46 Author: Robert Bradshaw Date: Fri Oct 21 12:22:13 2022 -0700 Better surfacing of Scala support via Scio. draft working code test commit Revert "Squashed commit of the following:" This reverts commit 8fc833a5e7abf4cbfb63e56d450631bbfc1985ff. auth files * unit file fix * sdk selection works with auth * show sdk selector in welcome screen * hide back button after navigating from welcome * comments (0) * cache license * non-nullable onChanged * untested refinement * deleted show sdk selector * notifier objects naming * untested refinement (1) * candidate repository * new configs & todos * canCompleteCurrentUnit (#23692) * kOpenLoginOverlay (#23692) * login_overlay (#23692) * unused import (#23692) * deleted file (#23692) * review comments (2) * deleted pubspec.lock * pubspec.lock in gitignore * comment fixes (3) * updating & blocking complete unit button (#23692) * missing await * no final else * pubspec.lock ignored only in PGC * pubspec.lock * comment fixes (4) * rearranged completeUnit (#23692) * renamed user progress model to unit progress (#23692) * clearUpdatingUnitId (#23692) * added async (#23692) * removed "fix exception" todo after filing an issue (#23692) * generated files * renamed user progress cache to unit progress (#23692) * all caches extend cache (#23692) * refined open overlay (#23692) * extracted overlay body (#23692) * moved dismissible overlay (#23692) * specific imports (#23692) * added firebase_options.dart into gradle rat exclusions & added a missing license (#23692) * removed padding from user menu (#23692) * documentation update (#23692) * removed goToContextLine set sdk in UserSharedExampleLoadingDescriptor removed jsonDecode from temporary postUnitComplete (#23692) * sdk getter (#23692) * todo: remove sdkId getter and setter (#23692) * todo: add unit and integration tests (#23692) * updated readme (#23692) * addressing comments (#23692) Co-authored-by: darkhan.nausharipov --- build.gradle.kts | 1 + learning/tour-of-beam/frontend/README.md | 72 ++++++---- .../frontend/lib/auth/notifier.dart | 45 +++++++ .../cache/cache.dart} | 22 +--- .../frontend/lib/cache/content_tree.dart | 17 +-- .../tour-of-beam/frontend/lib/cache/sdk.dart | 13 +- .../frontend/lib/cache/unit_content.dart | 14 +- .../frontend/lib/cache/unit_progress.dart | 103 +++++++++++++++ .../lib/components/builders/content_tree.dart | 6 +- .../lib/components/builders/sdks.dart | 6 +- .../frontend/lib/components/footer.dart | 6 +- .../login/{login_button.dart => button.dart} | 30 ++--- .../{login_content.dart => content.dart} | 69 +++++----- .../lib/components/profile/avatar.dart | 43 +++--- .../{profile_content.dart => user_menu.dart} | 88 +++++++------ .../frontend/lib/components/scaffold.dart | 53 ++++++-- .../frontend/lib/components/sdk_dropdown.dart | 20 ++- .../frontend/lib/constants/sizes.dart | 1 - .../frontend/lib/constants/storage_keys.dart | 21 +++ .../frontend/lib/enums/unit_completion.dart | 26 ++++ .../frontend/lib/firebase_options.dart | 63 +++++++++ .../tour-of-beam/frontend/lib/locator.dart | 14 +- learning/tour-of-beam/frontend/lib/main.dart | 5 + .../frontend/lib/models/unit_progress.dart | 35 +++++ .../frontend/lib/models/unit_progress.g.dart | 13 ++ .../pages/tour/controllers/content_tree.dart | 6 + .../lib/pages/tour/controllers/unit.dart | 45 +++++++ .../frontend/lib/pages/tour/screen.dart | 26 ++-- .../frontend/lib/pages/tour/state.dart | 101 +++++++++----- .../tour/widgets/complete_unit_button.dart | 68 ++++++++++ ...cator.dart => completeness_indicator.dart} | 25 ++-- .../lib/pages/tour/widgets/content.dart | 36 ++--- .../lib/pages/tour/widgets/content_tree.dart | 1 + .../lib/pages/tour/widgets/group_title.dart | 76 ++++++++++- .../pages/tour/widgets/playground_demo.dart | 1 - .../frontend/lib/pages/tour/widgets/unit.dart | 16 ++- .../frontend/lib/pages/welcome/screen.dart | 124 ++++++++++++------ .../frontend/lib/pages/welcome/state.dart | 24 +--- .../lib/repositories/client/client.dart | 5 + .../client/cloud_functions_client.dart | 37 ++++++ .../models/get_user_progress_response.dart | 33 +++++ .../models/get_user_progress_response.g.dart | 15 +++ learning/tour-of-beam/frontend/lib/state.dart | 58 ++++++++ learning/tour-of-beam/frontend/pubspec.lock | 97 +++++++++++++- learning/tour-of-beam/frontend/pubspec.yaml | 4 + .../tour-of-beam/frontend/test/main_test.dart | 21 +++ .../lib/playground_components.dart | 16 +-- .../lib/src/controllers/public_notifier.dart | 27 ++++ .../lib/src/widgets/overlay/body.dart | 22 ++-- .../dismissible.dart} | 2 +- .../lib/src/widgets/overlay/opener.dart | 39 ++++++ 51 files changed, 1323 insertions(+), 388 deletions(-) create mode 100644 learning/tour-of-beam/frontend/lib/auth/notifier.dart rename learning/tour-of-beam/frontend/{test/overflow_test.dart => lib/cache/cache.dart} (58%) create mode 100644 learning/tour-of-beam/frontend/lib/cache/unit_progress.dart rename learning/tour-of-beam/frontend/lib/components/login/{login_button.dart => button.dart} (71%) rename learning/tour-of-beam/frontend/lib/components/login/{login_content.dart => content.dart} (76%) rename learning/tour-of-beam/frontend/lib/components/profile/{profile_content.dart => user_menu.dart} (69%) create mode 100644 learning/tour-of-beam/frontend/lib/constants/storage_keys.dart create mode 100644 learning/tour-of-beam/frontend/lib/enums/unit_completion.dart create mode 100644 learning/tour-of-beam/frontend/lib/firebase_options.dart create mode 100644 learning/tour-of-beam/frontend/lib/models/unit_progress.dart create mode 100644 learning/tour-of-beam/frontend/lib/models/unit_progress.g.dart create mode 100644 learning/tour-of-beam/frontend/lib/pages/tour/controllers/unit.dart create mode 100644 learning/tour-of-beam/frontend/lib/pages/tour/widgets/complete_unit_button.dart rename learning/tour-of-beam/frontend/lib/pages/tour/widgets/{tour_progress_indicator.dart => completeness_indicator.dart} (72%) create mode 100644 learning/tour-of-beam/frontend/lib/repositories/models/get_user_progress_response.dart create mode 100644 learning/tour-of-beam/frontend/lib/repositories/models/get_user_progress_response.g.dart create mode 100644 learning/tour-of-beam/frontend/lib/state.dart create mode 100644 learning/tour-of-beam/frontend/test/main_test.dart create mode 100644 playground/frontend/playground_components/lib/src/controllers/public_notifier.dart rename learning/tour-of-beam/frontend/test/common/test_screen_wrapper.dart => playground/frontend/playground_components/lib/src/widgets/overlay/body.dart (66%) rename playground/frontend/playground_components/lib/src/widgets/{dismissible_overlay.dart => overlay/dismissible.dart} (97%) create mode 100644 playground/frontend/playground_components/lib/src/widgets/overlay/opener.dart diff --git a/build.gradle.kts b/build.gradle.kts index 01423965aa8d..4c5dd4afef23 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -173,6 +173,7 @@ tasks.rat { "learning/tour-of-beam/frontend/**/*.gen.dart", "learning/tour-of-beam/frontend/.metadata", "learning/tour-of-beam/frontend/pubspec.lock", + "learning/tour-of-beam/frontend/lib/firebase_options.dart", // Ignore .gitkeep file "**/.gitkeep", diff --git a/learning/tour-of-beam/frontend/README.md b/learning/tour-of-beam/frontend/README.md index 2e27a05ad163..cba80719dfec 100644 --- a/learning/tour-of-beam/frontend/README.md +++ b/learning/tour-of-beam/frontend/README.md @@ -17,47 +17,67 @@ under the License. --> - # Tour of Beam - These are the main sources of the Tour of Beam website. +# Tour of Beam - # About +These are the main sources of the Tour of Beam website. + +# About ## Getting started -Running, debugging, and testing all require this first step that fetches -dependencies and generates code: + +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: ```bash -cd ../../../playground/frontend/playground_components -flutter pub get -flutter pub run build_runner build -cd ../../../learning/tour-of-beam/frontend -flutter pub get -flutter pub run build_runner build +cd beam +./gradlew :playground:frontend:playground_components:generateCode +cd learning/tour-of-beam/frontend +flutter pub run build_runner build --delete-conflicting-outputs ``` ### Run The following command is used to build and serve the frontend app locally: -`$ flutter run -d chrome` +```bash +flutter run -d chrome +``` + +### Backend Selection + +To change the Google Project that is used as the backend: + +1. Update Firebase configuration: + https://firebase.google.com/docs/flutter/setup?platform=web + +2. In `/lib/config.dart`, update: + 1. Google Project ID and region. + 2. Playground's backend URLs. + +# Deployment + +# Tests +Install ChromeDriver to run integration tests in a browser: https://docs.flutter.dev/testing/integration-tests#running-in-a-browser +Run integration tests: +flutter drive \ + --driver=test_driver/integration_test.dart \ + --target=integration_test/counter_test.dart \ + -d web-server - # Deployment +# Packages - # Tests - Install ChromeDriver to run integration tests in a browser: https://docs.flutter.dev/testing/integration-tests#running-in-a-browser - Run integration tests: - flutter drive \ - --driver=test_driver/integration_test.dart \ - --target=integration_test/counter_test.dart \ - -d web-server +`flutter pub get` - # Packages - `flutter pub get` +# Contribution guide - # Contribution guide - For checks: `./gradlew rat` +For checks: `./gradlew rat` +Exclusions for file checks can be added in the Tour of Beam section of this file: `beam/build.gradle.kts` - # Additional resources +# Additional resources - # Troubleshooting +# Troubleshooting diff --git a/learning/tour-of-beam/frontend/lib/auth/notifier.dart b/learning/tour-of-beam/frontend/lib/auth/notifier.dart new file mode 100644 index 000000000000..2eb7be819f39 --- /dev/null +++ b/learning/tour-of-beam/frontend/lib/auth/notifier.dart @@ -0,0 +1,45 @@ +/* + * 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. + */ + +import 'dart:async'; + +import 'package:firebase_auth/firebase_auth.dart'; +import 'package:firebase_auth_platform_interface/firebase_auth_platform_interface.dart'; +import 'package:flutter/material.dart'; + +class AuthNotifier extends ChangeNotifier { + AuthNotifier() { + FirebaseAuth.instance.authStateChanges().listen((user) { + notifyListeners(); + }); + } + + bool get isAuthenticated => FirebaseAuth.instance.currentUser != null; + + Future getToken() async { + return await FirebaseAuth.instance.currentUser?.getIdToken(); + } + + Future logIn(AuthProvider authProvider) async { + await FirebaseAuth.instance.signInWithPopup(authProvider); + } + + Future logOut() async { + await FirebaseAuth.instance.signOut(); + } +} diff --git a/learning/tour-of-beam/frontend/test/overflow_test.dart b/learning/tour-of-beam/frontend/lib/cache/cache.dart similarity index 58% rename from learning/tour-of-beam/frontend/test/overflow_test.dart rename to learning/tour-of-beam/frontend/lib/cache/cache.dart index 7559b7c5d25e..c11e2790c422 100644 --- a/learning/tour-of-beam/frontend/test/overflow_test.dart +++ b/learning/tour-of-beam/frontend/lib/cache/cache.dart @@ -17,22 +17,12 @@ */ import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:tour_of_beam/locator.dart'; -import 'package:tour_of_beam/pages/tour/screen.dart'; -import 'package:tour_of_beam/pages/tour/state.dart'; -import 'common/test_screen_wrapper.dart'; -void main() async { - await initializeServiceLocator(); +import '../repositories/client/client.dart'; - testWidgets('WelcomeScreen overflow', (tester) async { - tester.binding.window.physicalSizeTestValue = const Size(500, 296); - // TODO(nausharipov): fix the failure - await tester.pumpWidget( - TestScreenWrapper( - child: TourScreen(TourNotifier(initialSdkId: '')), - ), - ); - }); +/// A base class for caching entities from network requests. +abstract class Cache extends ChangeNotifier { + final TobClient client; + + Cache({required this.client}); } diff --git a/learning/tour-of-beam/frontend/lib/cache/content_tree.dart b/learning/tour-of-beam/frontend/lib/cache/content_tree.dart index 296b9a84238c..5f35af7e55e0 100644 --- a/learning/tour-of-beam/frontend/lib/cache/content_tree.dart +++ b/learning/tour-of-beam/frontend/lib/cache/content_tree.dart @@ -18,24 +18,19 @@ import 'dart:async'; -import 'package:flutter/widgets.dart'; - import '../models/content_tree.dart'; -import '../repositories/client/client.dart'; +import 'cache.dart'; -class ContentTreeCache extends ChangeNotifier { - final TobClient client; +class ContentTreeCache extends Cache { + ContentTreeCache({ + required super.client, + }); final _treesBySdkId = {}; final _futuresBySdkId = >{}; - ContentTreeCache({ - required this.client, - }); - ContentTreeModel? getContentTree(String sdkId) { - final future = _futuresBySdkId[sdkId]; - if (future == null) { + if (_futuresBySdkId.containsKey(sdkId)) { unawaited(_loadContentTree(sdkId)); } diff --git a/learning/tour-of-beam/frontend/lib/cache/sdk.dart b/learning/tour-of-beam/frontend/lib/cache/sdk.dart index 068fda06b765..8b26a3c1805b 100644 --- a/learning/tour-of-beam/frontend/lib/cache/sdk.dart +++ b/learning/tour-of-beam/frontend/lib/cache/sdk.dart @@ -18,22 +18,19 @@ import 'dart:async'; -import 'package:flutter/widgets.dart'; import 'package:playground_components/playground_components.dart'; -import '../repositories/client/client.dart'; import '../repositories/models/get_sdks_response.dart'; +import 'cache.dart'; -class SdkCache extends ChangeNotifier { - final TobClient client; +class SdkCache extends Cache { + SdkCache({ + required super.client, + }); final _sdks = []; Future? _future; - SdkCache({ - required this.client, - }); - List getSdks() { if (_future == null) { unawaited(_loadSdks()); diff --git a/learning/tour-of-beam/frontend/lib/cache/unit_content.dart b/learning/tour-of-beam/frontend/lib/cache/unit_content.dart index 25d703064808..d8499a641e27 100644 --- a/learning/tour-of-beam/frontend/lib/cache/unit_content.dart +++ b/learning/tour-of-beam/frontend/lib/cache/unit_content.dart @@ -18,21 +18,17 @@ import 'dart:async'; -import 'package:flutter/widgets.dart'; - import '../models/unit_content.dart'; -import '../repositories/client/client.dart'; +import 'cache.dart'; -class UnitContentCache extends ChangeNotifier { - final TobClient client; +class UnitContentCache extends Cache { + UnitContentCache({ + required super.client, + }); final _unitContents = >{}; final _futures = >>{}; - UnitContentCache({ - required this.client, - }); - UnitContentModel? getUnitContent(String sdkId, String unitId) { final future = _futures[sdkId]?[unitId]; if (future == null) { diff --git a/learning/tour-of-beam/frontend/lib/cache/unit_progress.dart b/learning/tour-of-beam/frontend/lib/cache/unit_progress.dart new file mode 100644 index 000000000000..5649e7464674 --- /dev/null +++ b/learning/tour-of-beam/frontend/lib/cache/unit_progress.dart @@ -0,0 +1,103 @@ +/* + * 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. + */ + +import 'dart:async'; + +import 'package:get_it/get_it.dart'; + +import '../auth/notifier.dart'; +import '../enums/unit_completion.dart'; +import '../repositories/models/get_user_progress_response.dart'; +import '../state.dart'; +import 'cache.dart'; + +class UnitProgressCache extends Cache { + UnitProgressCache({required super.client}); + + final _completedUnitIds = {}; + final _updatingUnitIds = {}; + Future? _future; + + Set getUpdatingUnitIds() => _updatingUnitIds; + + void addUpdatingUnitId(String unitId) { + _updatingUnitIds.add(unitId); + notifyListeners(); + } + + void clearUpdatingUnitId(String unitId) { + _updatingUnitIds.remove(unitId); + notifyListeners(); + } + + bool canCompleteUnit(String? unitId) { + if (unitId == null) { + return false; + } + return _getUnitCompletion(unitId) == UnitCompletion.uncompleted; + } + + UnitCompletion _getUnitCompletion(String unitId) { + final authNotifier = GetIt.instance.get(); + if (!authNotifier.isAuthenticated) { + return UnitCompletion.unauthenticated; + } + if (_updatingUnitIds.contains(unitId)) { + return UnitCompletion.updating; + } + if (isUnitCompleted(unitId)) { + return UnitCompletion.completed; + } + return UnitCompletion.uncompleted; + } + + bool isUnitCompleted(String? unitId) { + return getCompletedUnits().contains(unitId); + } + + Future updateCompletedUnits() async { + final sdkId = GetIt.instance.get().sdkId; + if (sdkId != null) { + await _loadCompletedUnits(sdkId); + } + } + + Set getCompletedUnits() { + if (_future == null) { + unawaited(updateCompletedUnits()); + } + + return _completedUnitIds; + } + + Future _loadCompletedUnits(String sdkId) async { + _future = client.getUserProgress(sdkId); + final result = await _future; + + _completedUnitIds.clear(); + if (result != null) { + for (final unitProgress in result.units) { + if (unitProgress.isCompleted) { + _completedUnitIds.add(unitProgress.id); + } + } + } + + notifyListeners(); + } +} diff --git a/learning/tour-of-beam/frontend/lib/components/builders/content_tree.dart b/learning/tour-of-beam/frontend/lib/components/builders/content_tree.dart index 1ee9a3b87d01..8ef706ead45a 100644 --- a/learning/tour-of-beam/frontend/lib/components/builders/content_tree.dart +++ b/learning/tour-of-beam/frontend/lib/components/builders/content_tree.dart @@ -33,13 +33,13 @@ class ContentTreeBuilder extends StatelessWidget { @override Widget build(BuildContext context) { - final cache = GetIt.instance.get(); + final contentTreeCache = GetIt.instance.get(); return AnimatedBuilder( - animation: cache, + animation: contentTreeCache, builder: (context, child) => builder( context, - cache.getContentTree(sdkId), + contentTreeCache.getContentTree(sdkId), child, ), ); diff --git a/learning/tour-of-beam/frontend/lib/components/builders/sdks.dart b/learning/tour-of-beam/frontend/lib/components/builders/sdks.dart index 8aeea1461300..e6a5c6f97d35 100644 --- a/learning/tour-of-beam/frontend/lib/components/builders/sdks.dart +++ b/learning/tour-of-beam/frontend/lib/components/builders/sdks.dart @@ -31,11 +31,11 @@ class SdksBuilder extends StatelessWidget { @override Widget build(BuildContext context) { - final cache = GetIt.instance.get(); + final sdkCache = GetIt.instance.get(); return AnimatedBuilder( - animation: cache, - builder: (context, child) => builder(context, cache.getSdks(), child), + animation: sdkCache, + builder: (context, child) => builder(context, sdkCache.getSdks(), child), ); } } diff --git a/learning/tour-of-beam/frontend/lib/components/footer.dart b/learning/tour-of-beam/frontend/lib/components/footer.dart index e801836bb898..08af18188f04 100644 --- a/learning/tour-of-beam/frontend/lib/components/footer.dart +++ b/learning/tour-of-beam/frontend/lib/components/footer.dart @@ -16,6 +16,8 @@ * limitations under the License. */ +import 'dart:async'; + import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:playground_components/playground_components.dart'; @@ -90,7 +92,7 @@ class _ReportIssueButton extends StatelessWidget { return TextButton( style: _linkButtonStyle, onPressed: () { - launchUrl(Uri.parse(BeamLinks.reportIssue)); + unawaited(launchUrl(Uri.parse(BeamLinks.reportIssue))); }, child: const Text('ui.reportIssue').tr(), ); @@ -105,7 +107,7 @@ class _PrivacyPolicyButton extends StatelessWidget { return TextButton( style: _linkButtonStyle, onPressed: () { - launchUrl(Uri.parse(BeamLinks.privacyPolicy)); + unawaited(launchUrl(Uri.parse(BeamLinks.privacyPolicy))); }, child: const Text('ui.privacyPolicy').tr(), ); diff --git a/learning/tour-of-beam/frontend/lib/components/login/login_button.dart b/learning/tour-of-beam/frontend/lib/components/login/button.dart similarity index 71% rename from learning/tour-of-beam/frontend/lib/components/login/login_button.dart rename to learning/tour-of-beam/frontend/lib/components/login/button.dart index 36d96faffe5a..2fb2038d6bfd 100644 --- a/learning/tour-of-beam/frontend/lib/components/login/login_button.dart +++ b/learning/tour-of-beam/frontend/lib/components/login/button.dart @@ -20,7 +20,7 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:playground_components/playground_components.dart'; -import 'login_content.dart'; +import 'content.dart'; class LoginButton extends StatelessWidget { const LoginButton(); @@ -29,26 +29,18 @@ class LoginButton extends StatelessWidget { Widget build(BuildContext context) { return TextButton( onPressed: () { - _openOverlay(context); + final closeNotifier = PublicNotifier(); + openOverlay( + context: context, + closeNotifier: closeNotifier, + positioned: Positioned( + right: BeamSizes.size10, + top: BeamSizes.appBarHeight, + child: LoginContent(onLoggedIn: closeNotifier.notifyPublic), + ), + ); }, child: const Text('ui.signIn').tr(), ); } - - void _openOverlay(BuildContext context) { - OverlayEntry? overlay; - overlay = OverlayEntry( - builder: (context) => DismissibleOverlay( - close: () { - overlay?.remove(); - }, - child: const Positioned( - right: BeamSizes.size10, - top: BeamSizes.appBarHeight, - child: LoginContent(), - ), - ), - ); - Overlay.of(context)?.insert(overlay); - } } diff --git a/learning/tour-of-beam/frontend/lib/components/login/login_content.dart b/learning/tour-of-beam/frontend/lib/components/login/content.dart similarity index 76% rename from learning/tour-of-beam/frontend/lib/components/login/login_content.dart rename to learning/tour-of-beam/frontend/lib/components/login/content.dart index aabdd026a511..ae1fe80fa028 100644 --- a/learning/tour-of-beam/frontend/lib/components/login/login_content.dart +++ b/learning/tour-of-beam/frontend/lib/components/login/content.dart @@ -17,51 +17,47 @@ */ import 'package:easy_localization/easy_localization.dart'; +import 'package:firebase_auth_platform_interface/firebase_auth_platform_interface.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; +import 'package:get_it/get_it.dart'; import 'package:playground_components/playground_components.dart'; import '../../assets/assets.gen.dart'; +import '../../auth/notifier.dart'; import '../../constants/sizes.dart'; class LoginContent extends StatelessWidget { - const LoginContent(); + final VoidCallback onLoggedIn; - @override - Widget build(BuildContext context) { - return _Body( - child: Column( - children: [ - Text( - 'ui.signIn', - style: Theme.of(context).textTheme.titleLarge, - ).tr(), - const SizedBox(height: BeamSizes.size10), - const Text( - 'dialogs.signInIf', - textAlign: TextAlign.center, - ).tr(), - const _Divider(), - const _BrandedLoginButtons(), - ], - ), - ); - } -} - -class _Body extends StatelessWidget { - final Widget child; - const _Body({required this.child}); + const LoginContent({ + required this.onLoggedIn, + }); @override Widget build(BuildContext context) { - return Material( - elevation: BeamSizes.size10, - borderRadius: BorderRadius.circular(10), + return OverlayBody( child: Container( width: TobSizes.authOverlayWidth, padding: const EdgeInsets.all(BeamSizes.size24), - child: child, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + 'ui.signIn', + style: Theme.of(context).textTheme.titleLarge, + ).tr(), + const SizedBox(height: BeamSizes.size10), + const Text( + 'dialogs.signInIf', + textAlign: TextAlign.center, + ).tr(), + const _Divider(), + _BrandedLoginButtons( + onLoggedIn: onLoggedIn, + ), + ], + ), ), ); } @@ -82,10 +78,16 @@ class _Divider extends StatelessWidget { } class _BrandedLoginButtons extends StatelessWidget { - const _BrandedLoginButtons(); + final VoidCallback onLoggedIn; + + const _BrandedLoginButtons({ + required this.onLoggedIn, + }); @override Widget build(BuildContext context) { + final authNotifier = GetIt.instance.get(); + final isLightTheme = Theme.of(context).brightness == Brightness.light; final textStyle = MaterialStatePropertyAll(Theme.of(context).textTheme.bodyMedium); @@ -129,7 +131,10 @@ class _BrandedLoginButtons extends StatelessWidget { ), const SizedBox(height: BeamSizes.size16), ElevatedButton.icon( - onPressed: () {}, + onPressed: () async { + await authNotifier.logIn(GoogleAuthProvider()); + onLoggedIn(); + }, style: isLightTheme ? googleLightButtonStyle : darkButtonStyle, icon: SvgPicture.asset(Assets.svg.googleLogo), label: const Text('ui.continueGoogle').tr(), diff --git a/learning/tour-of-beam/frontend/lib/components/profile/avatar.dart b/learning/tour-of-beam/frontend/lib/components/profile/avatar.dart index 2c8c07d9ef17..d4b88584dab6 100644 --- a/learning/tour-of-beam/frontend/lib/components/profile/avatar.dart +++ b/learning/tour-of-beam/frontend/lib/components/profile/avatar.dart @@ -16,42 +16,43 @@ * limitations under the License. */ +import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter/material.dart'; import 'package:playground_components/playground_components.dart'; -import '../../assets/assets.gen.dart'; -import 'profile_content.dart'; +import 'user_menu.dart'; class Avatar extends StatelessWidget { - const Avatar(); + final User user; + const Avatar({required this.user}); @override Widget build(BuildContext context) { + final photoUrl = user.photoURL; return GestureDetector( onTap: () { - _openOverlay(context); + final closeNotifier = PublicNotifier(); + openOverlay( + context: context, + closeNotifier: closeNotifier, + positioned: Positioned( + right: BeamSizes.size10, + top: BeamSizes.appBarHeight, + child: UserMenu( + closeOverlayCallback: closeNotifier.notifyPublic, + user: user, + ), + ), + ); }, child: CircleAvatar( backgroundColor: BeamColors.white, - foregroundImage: AssetImage(Assets.png.laptopLight.path), - ), - ); - } - - void _openOverlay(BuildContext context) { - OverlayEntry? overlay; - overlay = OverlayEntry( - builder: (context) => DismissibleOverlay( - close: () { - overlay?.remove(); - }, - child: const Positioned( - right: BeamSizes.size10, - top: BeamSizes.appBarHeight, - child: ProfileContent(), + foregroundImage: photoUrl == null ? null : NetworkImage(photoUrl), + child: const Icon( + Icons.person, + color: BeamColors.grey3, ), ), ); - Overlay.of(context)?.insert(overlay); } } diff --git a/learning/tour-of-beam/frontend/lib/components/profile/profile_content.dart b/learning/tour-of-beam/frontend/lib/components/profile/user_menu.dart similarity index 69% rename from learning/tour-of-beam/frontend/lib/components/profile/profile_content.dart rename to learning/tour-of-beam/frontend/lib/components/profile/user_menu.dart index f6a0e1a6e82b..5fb49fa7192b 100644 --- a/learning/tour-of-beam/frontend/lib/components/profile/profile_content.dart +++ b/learning/tour-of-beam/frontend/lib/components/profile/user_menu.dart @@ -17,67 +17,72 @@ */ import 'package:easy_localization/easy_localization.dart'; +import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; +import 'package:get_it/get_it.dart'; import 'package:playground_components/playground_components.dart'; import '../../assets/assets.gen.dart'; +import '../../auth/notifier.dart'; import '../../constants/sizes.dart'; -class ProfileContent extends StatelessWidget { - const ProfileContent(); +class UserMenu extends StatelessWidget { + final VoidCallback closeOverlayCallback; + final User user; - @override - Widget build(BuildContext context) { - return _Body( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: const [ - _Info(), - BeamDivider(), - _Buttons(), - ], - ), - ); - } -} - -class _Body extends StatelessWidget { - final Widget child; - - const _Body({required this.child}); + const UserMenu({ + required this.closeOverlayCallback, + required this.user, + }); @override Widget build(BuildContext context) { - return Material( - elevation: BeamSizes.size10, - borderRadius: BorderRadius.circular(10), + return OverlayBody( child: SizedBox( width: TobSizes.authOverlayWidth, - child: child, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _Info(user: user), + const BeamDivider(), + _Buttons( + closeOverlayCallback: closeOverlayCallback, + ), + ], + ), ), ); } } class _Info extends StatelessWidget { - const _Info(); + final User user; + + const _Info({ + required this.user, + }); @override Widget build(BuildContext context) { + final displayName = user.displayName; + final email = user.email; + return Padding( padding: const EdgeInsets.all(BeamSizes.size16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text( - 'Name Surname', - style: Theme.of(context).textTheme.titleLarge, - ), - Text( - 'email@mail.com', - style: Theme.of(context).textTheme.bodySmall, - ), + if (displayName != null) + Text( + displayName, + style: Theme.of(context).textTheme.titleLarge, + ), + if (email != null) + Text( + email, + style: Theme.of(context).textTheme.bodySmall, + ), ], ), ); @@ -85,10 +90,16 @@ class _Info extends StatelessWidget { } class _Buttons extends StatelessWidget { - const _Buttons(); + final VoidCallback closeOverlayCallback; + + const _Buttons({ + required this.closeOverlayCallback, + }); @override Widget build(BuildContext context) { + final authNotifier = GetIt.instance.get(); + return Column( children: [ _IconLabel( @@ -105,7 +116,10 @@ class _Buttons extends StatelessWidget { ), const BeamDivider(), _IconLabel( - onTap: () {}, + onTap: () async { + await authNotifier.logOut(); + closeOverlayCallback(); + }, iconPath: Assets.svg.profileLogout, label: 'ui.signOut'.tr(), ), @@ -123,7 +137,7 @@ class _Buttons extends StatelessWidget { class _IconLabel extends StatelessWidget { final String iconPath; final String label; - final void Function()? onTap; + final VoidCallback? onTap; // TODO(alexeyinkin): Auto-determine. final bool isSvg; diff --git a/learning/tour-of-beam/frontend/lib/components/scaffold.dart b/learning/tour-of-beam/frontend/lib/components/scaffold.dart index f8352140436e..007e6398ecca 100644 --- a/learning/tour-of-beam/frontend/lib/components/scaffold.dart +++ b/learning/tour-of-beam/frontend/lib/components/scaffold.dart @@ -16,11 +16,14 @@ * limitations under the License. */ +import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter/material.dart'; +import 'package:get_it/get_it.dart'; import 'package:playground_components/playground_components.dart'; +import '../state.dart'; import 'footer.dart'; -import 'login/login_button.dart'; +import 'login/button.dart'; import 'logo.dart'; import 'profile/avatar.dart'; import 'sdk_dropdown.dart'; @@ -33,22 +36,18 @@ class TobScaffold extends StatelessWidget { required this.child, }); - // TODO(nausharipov): get state - static const _isAuthorized = true; - @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( + automaticallyImplyLeading: false, title: const Logo(), actions: const [ - _ActionVerticalPadding(child: SdkDropdown()), + _ActionVerticalPadding(child: _SdkSelector()), SizedBox(width: BeamSizes.size12), _ActionVerticalPadding(child: ToggleThemeButton()), SizedBox(width: BeamSizes.size6), - _ActionVerticalPadding( - child: _isAuthorized ? Avatar() : LoginButton(), - ), + _ActionVerticalPadding(child: _Profile()), SizedBox(width: BeamSizes.size16), ], ), @@ -62,6 +61,21 @@ class TobScaffold extends StatelessWidget { } } +class _Profile extends StatelessWidget { + const _Profile(); + + @override + Widget build(BuildContext context) { + return StreamBuilder( + stream: FirebaseAuth.instance.userChanges(), + builder: (context, snapshot) { + final user = snapshot.data; + return user == null ? const LoginButton() : Avatar(user: user); + }, + ); + } +} + class _ActionVerticalPadding extends StatelessWidget { final Widget child; @@ -75,3 +89,26 @@ class _ActionVerticalPadding extends StatelessWidget { ); } } + +class _SdkSelector extends StatelessWidget { + const _SdkSelector(); + + @override + Widget build(BuildContext context) { + final appNotifier = GetIt.instance.get(); + return AnimatedBuilder( + animation: appNotifier, + builder: (context, child) { + final sdkId = appNotifier.sdkId; + return sdkId == null + ? Container() + : SdkDropdown( + sdkId: sdkId, + onChanged: (value) { + appNotifier.sdkId = value; + }, + ); + }, + ); + } +} diff --git a/learning/tour-of-beam/frontend/lib/components/sdk_dropdown.dart b/learning/tour-of-beam/frontend/lib/components/sdk_dropdown.dart index 689860b8466c..9e84e3698e37 100644 --- a/learning/tour-of-beam/frontend/lib/components/sdk_dropdown.dart +++ b/learning/tour-of-beam/frontend/lib/components/sdk_dropdown.dart @@ -22,7 +22,13 @@ import 'package:playground_components/playground_components.dart'; import 'builders/sdks.dart'; class SdkDropdown extends StatelessWidget { - const SdkDropdown(); + final String sdkId; + final ValueChanged onChanged; + + const SdkDropdown({ + required this.sdkId, + required this.onChanged, + }); @override Widget build(BuildContext context) { @@ -34,9 +40,11 @@ class SdkDropdown extends StatelessWidget { return _DropdownWrapper( child: DropdownButton( - value: sdks.first.id, + value: sdkId, onChanged: (sdk) { - // TODO(nausharipov): change SDK + if (sdk != null) { + onChanged(sdk); + } }, items: sdks .map( @@ -46,7 +54,6 @@ class SdkDropdown extends StatelessWidget { ), ) .toList(growable: false), - isDense: true, alignment: Alignment.center, focusColor: BeamColors.transparent, borderRadius: BorderRadius.circular(BeamSizes.size6), @@ -63,9 +70,10 @@ class _DropdownWrapper extends StatelessWidget { @override Widget build(BuildContext context) { - return DecoratedBox( + return Container( + padding: const EdgeInsets.only(left: BeamSizes.size10), decoration: BoxDecoration( - color: Theme.of(context).hoverColor, + color: Theme.of(context).selectedRowColor, borderRadius: BorderRadius.circular(BeamSizes.size6), ), child: DropdownButtonHideUnderline(child: child), diff --git a/learning/tour-of-beam/frontend/lib/constants/sizes.dart b/learning/tour-of-beam/frontend/lib/constants/sizes.dart index bb9a665c8a30..53ad1c7c2d03 100644 --- a/learning/tour-of-beam/frontend/lib/constants/sizes.dart +++ b/learning/tour-of-beam/frontend/lib/constants/sizes.dart @@ -22,7 +22,6 @@ class TobSizes { } class ScreenSizes { - // TODO(nausharipov): name better static const medium = 1024; } diff --git a/learning/tour-of-beam/frontend/lib/constants/storage_keys.dart b/learning/tour-of-beam/frontend/lib/constants/storage_keys.dart new file mode 100644 index 000000000000..84b289e115e8 --- /dev/null +++ b/learning/tour-of-beam/frontend/lib/constants/storage_keys.dart @@ -0,0 +1,21 @@ +/* + * 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. + */ + +class StorageKeys { + static const sdkId = 'sdkId'; +} diff --git a/learning/tour-of-beam/frontend/lib/enums/unit_completion.dart b/learning/tour-of-beam/frontend/lib/enums/unit_completion.dart new file mode 100644 index 000000000000..746cfd4d38e5 --- /dev/null +++ b/learning/tour-of-beam/frontend/lib/enums/unit_completion.dart @@ -0,0 +1,26 @@ +/* + * 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. + */ + +enum UnitCompletion { + completed, + uncompleted, + + /// Sent the request to complete or to undo completion. + updating, + unauthenticated, +} diff --git a/learning/tour-of-beam/frontend/lib/firebase_options.dart b/learning/tour-of-beam/frontend/lib/firebase_options.dart new file mode 100644 index 000000000000..e2a871d637b3 --- /dev/null +++ b/learning/tour-of-beam/frontend/lib/firebase_options.dart @@ -0,0 +1,63 @@ +// File generated by FlutterFire CLI. +// ignore_for_file: lines_longer_than_80_chars, avoid_classes_with_only_static_members +import 'package:firebase_core/firebase_core.dart' show FirebaseOptions; +import 'package:flutter/foundation.dart' + show defaultTargetPlatform, kIsWeb, TargetPlatform; + +/// Default [FirebaseOptions] for use with your Firebase apps. +/// +/// Example: +/// ```dart +/// import 'firebase_options.dart'; +/// // ... +/// await Firebase.initializeApp( +/// options: DefaultFirebaseOptions.currentPlatform, +/// ); +/// ``` +class DefaultFirebaseOptions { + static FirebaseOptions get currentPlatform { + if (kIsWeb) { + return web; + } + switch (defaultTargetPlatform) { + case TargetPlatform.android: + throw UnsupportedError( + 'DefaultFirebaseOptions have not been configured for android - ' + 'you can reconfigure this by running the FlutterFire CLI again.', + ); + case TargetPlatform.iOS: + throw UnsupportedError( + 'DefaultFirebaseOptions have not been configured for ios - ' + 'you can reconfigure this by running the FlutterFire CLI again.', + ); + case TargetPlatform.macOS: + throw UnsupportedError( + 'DefaultFirebaseOptions have not been configured for macos - ' + 'you can reconfigure this by running the FlutterFire CLI again.', + ); + case TargetPlatform.windows: + throw UnsupportedError( + 'DefaultFirebaseOptions have not been configured for windows - ' + 'you can reconfigure this by running the FlutterFire CLI again.', + ); + case TargetPlatform.linux: + throw UnsupportedError( + 'DefaultFirebaseOptions have not been configured for linux - ' + 'you can reconfigure this by running the FlutterFire CLI again.', + ); + default: + throw UnsupportedError( + 'DefaultFirebaseOptions are not supported for this platform.', + ); + } + } + + static const FirebaseOptions web = FirebaseOptions( + apiKey: 'AIzaSyBtAreurqJ5D4IK6cNisZh5dnDRKljbJAw', + authDomain: 'astest-369409.firebaseapp.com', + projectId: 'astest-369409', + storageBucket: 'astest-369409.appspot.com', + messagingSenderId: '534850967604', + appId: '1:534850967604:web:55c6af8da7940df1ddd261', + ); +} diff --git a/learning/tour-of-beam/frontend/lib/locator.dart b/learning/tour-of-beam/frontend/lib/locator.dart index f8146a212e24..7bdb0406edd0 100644 --- a/learning/tour-of-beam/frontend/lib/locator.dart +++ b/learning/tour-of-beam/frontend/lib/locator.dart @@ -19,28 +19,40 @@ import 'package:app_state/app_state.dart'; import 'package:get_it/get_it.dart'; +import 'auth/notifier.dart'; import 'cache/content_tree.dart'; import 'cache/sdk.dart'; import 'cache/unit_content.dart'; +import 'cache/unit_progress.dart'; import 'pages/welcome/page.dart'; +import 'repositories/client/client.dart'; import 'repositories/client/cloud_functions_client.dart'; import 'router/page_factory.dart'; import 'router/route_information_parser.dart'; +import 'state.dart'; Future initializeServiceLocator() async { - _initializeCaches(); + _initializeAuth(); _initializeState(); + _initializeCaches(); +} + +void _initializeAuth() { + GetIt.instance.registerSingleton(AuthNotifier()); } void _initializeCaches() { final client = CloudFunctionsTobClient(); + GetIt.instance.registerSingleton(client); GetIt.instance.registerSingleton(ContentTreeCache(client: client)); GetIt.instance.registerSingleton(SdkCache(client: client)); GetIt.instance.registerSingleton(UnitContentCache(client: client)); + GetIt.instance.registerSingleton(UnitProgressCache(client: client)); } void _initializeState() { + GetIt.instance.registerSingleton(AppNotifier()); GetIt.instance.registerSingleton( PageStack( bottomPage: WelcomePage(), diff --git a/learning/tour-of-beam/frontend/lib/main.dart b/learning/tour-of-beam/frontend/lib/main.dart index 602a187a97f7..b5cc5d64a9c4 100644 --- a/learning/tour-of-beam/frontend/lib/main.dart +++ b/learning/tour-of-beam/frontend/lib/main.dart @@ -20,16 +20,21 @@ import 'package:app_state/app_state.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization_ext/easy_localization_ext.dart'; import 'package:easy_localization_loader/easy_localization_loader.dart'; +import 'package:firebase_core/firebase_core.dart'; import 'package:flutter/material.dart'; import 'package:get_it/get_it.dart'; import 'package:playground_components/playground_components.dart'; import 'package:provider/provider.dart'; import 'package:url_strategy/url_strategy.dart'; +import 'firebase_options.dart'; import 'locator.dart'; import 'router/route_information_parser.dart'; void main() async { + await Firebase.initializeApp( + options: DefaultFirebaseOptions.currentPlatform, + ); setPathUrlStrategy(); await EasyLocalization.ensureInitialized(); await PlaygroundComponents.ensureInitialized(); diff --git a/learning/tour-of-beam/frontend/lib/models/unit_progress.dart b/learning/tour-of-beam/frontend/lib/models/unit_progress.dart new file mode 100644 index 000000000000..473c8ae0d4e6 --- /dev/null +++ b/learning/tour-of-beam/frontend/lib/models/unit_progress.dart @@ -0,0 +1,35 @@ +/* + * 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. + */ + +import 'package:json_annotation/json_annotation.dart'; + +part 'unit_progress.g.dart'; + +@JsonSerializable(createToJson: false) +class UnitProgressModel { + final String id; + final bool isCompleted; + + const UnitProgressModel({ + required this.id, + required this.isCompleted, + }); + + factory UnitProgressModel.fromJson(Map json) => + _$UnitProgressModelFromJson(json); +} diff --git a/learning/tour-of-beam/frontend/lib/models/unit_progress.g.dart b/learning/tour-of-beam/frontend/lib/models/unit_progress.g.dart new file mode 100644 index 000000000000..c1a773cd66a9 --- /dev/null +++ b/learning/tour-of-beam/frontend/lib/models/unit_progress.g.dart @@ -0,0 +1,13 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'unit_progress.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +UnitProgressModel _$UnitProgressModelFromJson(Map json) => + UnitProgressModel( + id: json['id'] as String, + isCompleted: json['isCompleted'] as bool, + ); diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/controllers/content_tree.dart b/learning/tour-of-beam/frontend/lib/pages/tour/controllers/content_tree.dart index bfa63c94df4f..bcdb686a10b7 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/controllers/content_tree.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/controllers/content_tree.dart @@ -28,6 +28,7 @@ import '../../../models/unit.dart'; class ContentTreeController extends ChangeNotifier { String _sdkId; List _treeIds; + // TODO(nausharipov): non-nullable currentNode? NodeModel? _currentNode; final _contentTreeCache = GetIt.instance.get(); final _expandedIds = {}; @@ -47,6 +48,11 @@ class ContentTreeController extends ChangeNotifier { Sdk get sdk => Sdk.parseOrCreate(_sdkId); String get sdkId => _sdkId; + set sdkId(String newValue) { + _sdkId = newValue; + notifyListeners(); + } + List get treeIds => _treeIds; NodeModel? get currentNode => _currentNode; diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/controllers/unit.dart b/learning/tour-of-beam/frontend/lib/pages/tour/controllers/unit.dart new file mode 100644 index 000000000000..5331e454ff45 --- /dev/null +++ b/learning/tour-of-beam/frontend/lib/pages/tour/controllers/unit.dart @@ -0,0 +1,45 @@ +/* + * 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. + */ + +import 'package:flutter/widgets.dart'; +import 'package:get_it/get_it.dart'; + +import '../../../cache/unit_progress.dart'; +import '../../../repositories/client/client.dart'; + +class UnitController extends ChangeNotifier { + final String unitId; + final String sdkId; + + UnitController({ + required this.unitId, + required this.sdkId, + }); + + Future completeUnit() async { + final client = GetIt.instance.get(); + final unitProgressCache = GetIt.instance.get(); + try { + unitProgressCache.addUpdatingUnitId(unitId); + await client.postUnitComplete(sdkId, unitId); + } finally { + await unitProgressCache.updateCompletedUnits(); + unitProgressCache.clearUpdatingUnitId(unitId); + } + } +} diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/screen.dart b/learning/tour-of-beam/frontend/lib/pages/tour/screen.dart index 3557111c0f76..a73d68efc4b2 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/screen.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/screen.dart @@ -27,37 +27,37 @@ import 'widgets/content_tree.dart'; import 'widgets/playground_demo.dart'; class TourScreen extends StatelessWidget { - final TourNotifier notifier; + final TourNotifier tourNotifier; - const TourScreen(this.notifier); + const TourScreen(this.tourNotifier); @override Widget build(BuildContext context) { return TobScaffold( child: MediaQuery.of(context).size.width > ScreenBreakpoints.twoColumns - ? _WideTour(notifier) - : _NarrowTour(notifier), + ? _WideTour(tourNotifier) + : _NarrowTour(tourNotifier), ); } } class _WideTour extends StatelessWidget { - final TourNotifier notifier; + final TourNotifier tourNotifier; - const _WideTour(this.notifier); + const _WideTour(this.tourNotifier); @override Widget build(BuildContext context) { return Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ - ContentTreeWidget(controller: notifier.contentTreeController), + ContentTreeWidget(controller: tourNotifier.contentTreeController), Expanded( child: SplitView( direction: Axis.horizontal, - first: ContentWidget(notifier), + first: ContentWidget(tourNotifier), second: PlaygroundDemoWidget( - playgroundController: notifier.playgroundController, + playgroundController: tourNotifier.playgroundController, ), ), ), @@ -67,9 +67,9 @@ class _WideTour extends StatelessWidget { } class _NarrowTour extends StatelessWidget { - final TourNotifier notifier; + final TourNotifier tourNotifier; - const _NarrowTour(this.notifier); + const _NarrowTour(this.tourNotifier); @override Widget build(BuildContext context) { @@ -79,8 +79,8 @@ class _NarrowTour extends StatelessWidget { Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ - ContentTreeWidget(controller: notifier.contentTreeController), - Expanded(child: ContentWidget(notifier)), + ContentTreeWidget(controller: tourNotifier.contentTreeController), + Expanded(child: ContentWidget(tourNotifier)), ], ), DecoratedBox( diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/state.dart b/learning/tour-of-beam/frontend/lib/pages/tour/state.dart index 242aa860adc9..48a6dfc3215a 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/state.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/state.dart @@ -16,22 +16,32 @@ * limitations under the License. */ +import 'dart:async'; + import 'package:app_state/app_state.dart'; import 'package:flutter/widgets.dart'; import 'package:get_it/get_it.dart'; import 'package:playground_components/playground_components.dart'; +import '../../auth/notifier.dart'; import '../../cache/unit_content.dart'; +import '../../cache/unit_progress.dart'; import '../../config.dart'; import '../../models/unit.dart'; import '../../models/unit_content.dart'; +import '../../state.dart'; import 'controllers/content_tree.dart'; +import 'controllers/unit.dart'; import 'path.dart'; class TourNotifier extends ChangeNotifier with PageStateMixin { final ContentTreeController contentTreeController; final PlaygroundController playgroundController; + UnitController? currentUnitController; + final _appNotifier = GetIt.instance.get(); + final _authNotifier = GetIt.instance.get(); final _unitContentCache = GetIt.instance.get(); + final _unitProgressCache = GetIt.instance.get(); UnitContentModel? _currentUnitContent; TourNotifier({ @@ -42,9 +52,11 @@ class TourNotifier extends ChangeNotifier with PageStateMixin { initialTreeIds: initialTreeIds, ), playgroundController = _createPlaygroundController(initialSdkId) { - contentTreeController.addListener(_onChanged); - _unitContentCache.addListener(_onChanged); - _onChanged(); + contentTreeController.addListener(_onUnitChanged); + _unitContentCache.addListener(_onUnitChanged); + _appNotifier.addListener(_onAppNotifierChanged); + _authNotifier.addListener(_onUnitProgressChanged); + _onUnitChanged(); } @override @@ -53,7 +65,30 @@ class TourNotifier extends ChangeNotifier with PageStateMixin { treeIds: contentTreeController.treeIds, ); - void _onChanged() { + String? get currentUnitId => currentUnitController?.unitId; + UnitContentModel? get currentUnitContent => _currentUnitContent; + + void _createCurrentUnitController(String sdkId, String unitId) { + currentUnitController = UnitController( + unitId: unitId, + sdkId: sdkId, + ); + } + + Future _onUnitProgressChanged() async { + await _unitProgressCache.updateCompletedUnits(); + } + + void _onAppNotifierChanged() { + final sdkId = _appNotifier.sdkId; + if (sdkId != null) { + playgroundController.setSdk(Sdk.parseOrCreate(sdkId)); + contentTreeController.sdkId = sdkId; + _onUnitProgressChanged(); + } + } + + void _onUnitChanged() { emitPathChanged(); final currentNode = contentTreeController.currentNode; if (currentNode is UnitModel) { @@ -62,8 +97,8 @@ class TourNotifier extends ChangeNotifier with PageStateMixin { sdk.id, currentNode.id, ); - - _setCurrentUnitContent(content, sdk: sdk); + _createCurrentUnitController(contentTreeController.sdkId, currentNode.id); + _setCurrentUnitContent(content); } else { _emptyPlayground(); } @@ -71,12 +106,7 @@ class TourNotifier extends ChangeNotifier with PageStateMixin { notifyListeners(); } - UnitContentModel? get currentUnitContent => _currentUnitContent; - - void _setCurrentUnitContent( - UnitContentModel? content, { - required Sdk sdk, - }) { + Future _setCurrentUnitContent(UnitContentModel? content) async { if (content == _currentUnitContent) { return; } @@ -89,25 +119,28 @@ class TourNotifier extends ChangeNotifier with PageStateMixin { final taskSnippetId = content.taskSnippetId; if (taskSnippetId == null) { - _emptyPlayground(); + await _emptyPlayground(); return; } - playgroundController.examplesLoader.load( - ExamplesLoadingDescriptor( - descriptors: [ - UserSharedExampleLoadingDescriptor( - sdk: sdk, - snippetId: taskSnippetId, - ), - ], - ), - ); + final selectedSdk = _appNotifier.sdk; + if (selectedSdk != null) { + await playgroundController.examplesLoader.load( + ExamplesLoadingDescriptor( + descriptors: [ + UserSharedExampleLoadingDescriptor( + sdk: selectedSdk, + snippetId: taskSnippetId, + ), + ], + ), + ); + } } // TODO(alexeyinkin): Hide the entire right pane instead. - void _emptyPlayground() { - playgroundController.examplesLoader.load( + Future _emptyPlayground() async { + await playgroundController.examplesLoader.load( ExamplesLoadingDescriptor( descriptors: [ EmptyExampleLoadingDescriptor(sdk: contentTreeController.sdk), @@ -143,11 +176,13 @@ class TourNotifier extends ChangeNotifier with PageStateMixin { examplesLoader: ExamplesLoader(), ); - playgroundController.examplesLoader.load( - ExamplesLoadingDescriptor( - descriptors: [ - EmptyExampleLoadingDescriptor(sdk: Sdk.parseOrCreate(initialSdkId)), - ], + unawaited( + playgroundController.examplesLoader.load( + ExamplesLoadingDescriptor( + descriptors: [ + EmptyExampleLoadingDescriptor(sdk: Sdk.parseOrCreate(initialSdkId)), + ], + ), ), ); @@ -156,8 +191,10 @@ class TourNotifier extends ChangeNotifier with PageStateMixin { @override void dispose() { - _unitContentCache.removeListener(_onChanged); - contentTreeController.removeListener(_onChanged); + _unitContentCache.removeListener(_onUnitChanged); + contentTreeController.removeListener(_onUnitChanged); + _appNotifier.removeListener(_onAppNotifierChanged); + _authNotifier.removeListener(_onUnitProgressChanged); super.dispose(); } } diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/complete_unit_button.dart b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/complete_unit_button.dart new file mode 100644 index 000000000000..f29c04a56c5a --- /dev/null +++ b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/complete_unit_button.dart @@ -0,0 +1,68 @@ +/* + * 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. + */ + +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:get_it/get_it.dart'; +import 'package:playground_components/playground_components.dart'; + +import '../../../cache/unit_progress.dart'; +import '../state.dart'; + +class CompleteUnitButton extends StatelessWidget { + final TourNotifier tourNotifier; + const CompleteUnitButton(this.tourNotifier); + + @override + Widget build(BuildContext context) { + final themeData = Theme.of(context); + final unitProgressCache = GetIt.instance.get(); + + return AnimatedBuilder( + animation: unitProgressCache, + builder: (context, child) { + final canComplete = + unitProgressCache.canCompleteUnit(tourNotifier.currentUnitId); + final borderColor = + canComplete ? themeData.primaryColor : themeData.disabledColor; + final onPressed = canComplete + ? tourNotifier.currentUnitController?.completeUnit + : null; + + return Flexible( + child: OutlinedButton( + style: OutlinedButton.styleFrom( + foregroundColor: themeData.primaryColor, + side: BorderSide(color: borderColor), + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.all( + Radius.circular(BeamSizes.size4), + ), + ), + ), + onPressed: onPressed, + child: const Text( + 'pages.tour.completeUnit', + overflow: TextOverflow.visible, + ).tr(), + ), + ); + }, + ); + } +} diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/tour_progress_indicator.dart b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/completeness_indicator.dart similarity index 72% rename from learning/tour-of-beam/frontend/lib/pages/tour/widgets/tour_progress_indicator.dart rename to learning/tour-of-beam/frontend/lib/pages/tour/widgets/completeness_indicator.dart index 6f3d6ba56087..c75eeaf1bb39 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/tour_progress_indicator.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/completeness_indicator.dart @@ -20,19 +20,28 @@ import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; import 'package:playground_components/playground_components.dart'; -class TourProgressIndicator extends StatelessWidget { - // TODO(nausharipov): replace assetPath with progress enum - final String assetPath; +import '../../../assets/assets.gen.dart'; + +class CompletenessIndicator extends StatelessWidget { + final bool isCompleted; final bool isSelected; - const TourProgressIndicator({ - required this.assetPath, + const CompletenessIndicator({ + required this.isCompleted, required this.isSelected, }); @override Widget build(BuildContext context) { final ext = Theme.of(context).extension()!; + final Color color; + if (isCompleted) { + color = BeamColors.green; + } else if (isSelected) { + color = ext.selectedProgressColor; + } else { + color = ext.unselectedProgressColor; + } return Padding( padding: const EdgeInsets.only( @@ -40,10 +49,8 @@ class TourProgressIndicator extends StatelessWidget { right: BeamSizes.size8, ), child: SvgPicture.asset( - assetPath, - color: isSelected - ? ext.selectedProgressColor - : ext.unselectedProgressColor, + isCompleted ? Assets.svg.unitProgress100 : Assets.svg.unitProgress0, + color: color, ), ); } diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/content.dart b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/content.dart index a45b87f8a2a3..8677d4362d9d 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/content.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/content.dart @@ -16,18 +16,18 @@ * limitations under the License. */ -import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:playground_components/playground_components.dart'; import '../../../constants/sizes.dart'; import '../state.dart'; +import 'complete_unit_button.dart'; import 'unit_content.dart'; class ContentWidget extends StatelessWidget { - final TourNotifier notifier; + final TourNotifier tourNotifier; - const ContentWidget(this.notifier); + const ContentWidget(this.tourNotifier); @override Widget build(BuildContext context) { @@ -44,9 +44,9 @@ class ContentWidget extends StatelessWidget { ), ), child: AnimatedBuilder( - animation: notifier, + animation: tourNotifier, builder: (context, child) { - final currentUnitContent = notifier.currentUnitContent; + final currentUnitContent = tourNotifier.currentUnitContent; return Column( mainAxisAlignment: MainAxisAlignment.spaceBetween, @@ -56,7 +56,7 @@ class ContentWidget extends StatelessWidget { ? Container() : UnitContentWidget(unitContent: currentUnitContent), ), - const _ContentFooter(), + _ContentFooter(tourNotifier), ], ); }, @@ -66,7 +66,8 @@ class ContentWidget extends StatelessWidget { } class _ContentFooter extends StatelessWidget { - const _ContentFooter(); + final TourNotifier tourNotifier; + const _ContentFooter(this.tourNotifier); @override Widget build(BuildContext context) { @@ -85,26 +86,7 @@ class _ContentFooter extends StatelessWidget { child: Row( mainAxisAlignment: MainAxisAlignment.end, children: [ - Flexible( - child: OutlinedButton( - style: OutlinedButton.styleFrom( - foregroundColor: themeData.primaryColor, - side: BorderSide(color: themeData.primaryColor), - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.all( - Radius.circular(BeamSizes.size4), - ), - ), - ), - child: const Text( - 'pages.tour.completeUnit', - overflow: TextOverflow.ellipsis, - ).tr(), - onPressed: () { - // TODO(nausharipov): complete unit - }, - ), - ), + CompleteUnitButton(tourNotifier), ], ), ); diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/content_tree.dart b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/content_tree.dart index d6cf5fc14032..a40f14d35c60 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/content_tree.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/content_tree.dart @@ -24,6 +24,7 @@ import '../controllers/content_tree.dart'; import 'content_tree_title.dart'; import 'module.dart'; +// TODO(nausharipov): make it collapsible class ContentTreeWidget extends StatelessWidget { final ContentTreeController controller; diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/group_title.dart b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/group_title.dart index 132a1326238d..df8f014867d8 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/group_title.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/group_title.dart @@ -17,11 +17,13 @@ */ import 'package:flutter/material.dart'; +import 'package:get_it/get_it.dart'; import 'package:playground_components/playground_components.dart'; -import '../../../assets/assets.gen.dart'; +import '../../../cache/unit_progress.dart'; import '../../../models/group.dart'; -import 'tour_progress_indicator.dart'; +import '../../../models/node.dart'; +import 'completeness_indicator.dart'; class GroupTitleWidget extends StatelessWidget { final GroupModel group; @@ -38,10 +40,7 @@ class GroupTitleWidget extends StatelessWidget { onTap: onTap, child: Row( children: [ - TourProgressIndicator( - assetPath: Assets.svg.unitProgress0, - isSelected: false, - ), + _GroupProgressIndicator(group: group), Text( group.title, style: Theme.of(context).textTheme.headlineMedium, @@ -51,3 +50,68 @@ class GroupTitleWidget extends StatelessWidget { ); } } + +class _GroupProgressIndicator extends StatelessWidget { + final GroupModel group; + const _GroupProgressIndicator({required this.group}); + + @override + Widget build(BuildContext context) { + final unitProgressCache = GetIt.instance.get(); + + return AnimatedBuilder( + animation: unitProgressCache, + builder: (context, child) { + final progress = _getGroupProgress( + group.nodes, + unitProgressCache.getCompletedUnits(), + ); + + if (progress == 1) { + return const CompletenessIndicator( + isCompleted: true, + isSelected: false, + ); + } + + return Container( + margin: const EdgeInsets.symmetric(horizontal: BeamSizes.size6), + height: BeamSizes.size8, + width: BeamSizes.size8, + child: CircularProgressIndicator( + strokeWidth: BeamSizes.size3, + color: BeamColors.green, + backgroundColor: Theme.of(context) + .extension()! + .unselectedProgressColor, + value: progress, + ), + ); + }, + ); + } + + double _getGroupProgress( + List groupNodes, + Set completedUnits, + ) { + int completed = 0; + int total = 0; + + void countNodes(List nodes) { + for (final node in nodes) { + if (node is GroupModel) { + countNodes(node.nodes); + } else { + total += 1; + if (completedUnits.contains(node.id)) { + completed += 1; + } + } + } + } + + countNodes(groupNodes); + return completed / total; + } +} diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/playground_demo.dart b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/playground_demo.dart index 4b5347a24810..c8016a120caf 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/playground_demo.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/playground_demo.dart @@ -48,7 +48,6 @@ class PlaygroundDemoWidget extends StatelessWidget { first: SnippetEditor( controller: snippetController, isEditable: true, - goToContextLine: false, ), second: OutputWidget( playgroundController: playgroundController, diff --git a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/unit.dart b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/unit.dart index 3675fec64ab2..9952b7f84c28 100644 --- a/learning/tour-of-beam/frontend/lib/pages/tour/widgets/unit.dart +++ b/learning/tour-of-beam/frontend/lib/pages/tour/widgets/unit.dart @@ -17,12 +17,13 @@ */ import 'package:flutter/material.dart'; +import 'package:get_it/get_it.dart'; import 'package:playground_components/playground_components.dart'; -import '../../../assets/assets.gen.dart'; +import '../../../cache/unit_progress.dart'; import '../../../models/unit.dart'; import '../controllers/content_tree.dart'; -import 'tour_progress_indicator.dart'; +import 'completeness_indicator.dart'; class UnitWidget extends StatelessWidget { final UnitModel unit; @@ -35,6 +36,8 @@ class UnitWidget extends StatelessWidget { @override Widget build(BuildContext context) { + final unitProgressCache = GetIt.instance.get(); + return AnimatedBuilder( animation: contentTreeController, builder: (context, child) { @@ -50,9 +53,12 @@ class UnitWidget extends StatelessWidget { padding: const EdgeInsets.symmetric(vertical: BeamSizes.size10), child: Row( children: [ - TourProgressIndicator( - assetPath: Assets.svg.unitProgress0, - isSelected: isSelected, + AnimatedBuilder( + animation: unitProgressCache, + builder: (context, child) => CompletenessIndicator( + isCompleted: unitProgressCache.isUnitCompleted(unit.id), + isSelected: isSelected, + ), ), Expanded( child: Text(unit.title), diff --git a/learning/tour-of-beam/frontend/lib/pages/welcome/screen.dart b/learning/tour-of-beam/frontend/lib/pages/welcome/screen.dart index 30d07ed9b574..b848a9a582d8 100644 --- a/learning/tour-of-beam/frontend/lib/pages/welcome/screen.dart +++ b/learning/tour-of-beam/frontend/lib/pages/welcome/screen.dart @@ -16,53 +16,59 @@ * limitations under the License. */ +import 'package:app_state/app_state.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; +import 'package:get_it/get_it.dart'; import 'package:playground_components/playground_components.dart'; import '../../assets/assets.gen.dart'; +import '../../auth/notifier.dart'; import '../../components/builders/content_tree.dart'; import '../../components/builders/sdks.dart'; +import '../../components/login/content.dart'; import '../../components/scaffold.dart'; import '../../constants/sizes.dart'; import '../../models/module.dart'; +import '../../state.dart'; +import '../tour/page.dart'; import 'state.dart'; class WelcomeScreen extends StatelessWidget { - final WelcomeNotifier notifier; + final WelcomeNotifier welcomeNotifier; - const WelcomeScreen(this.notifier); + const WelcomeScreen(this.welcomeNotifier); @override Widget build(BuildContext context) { return TobScaffold( child: SingleChildScrollView( child: MediaQuery.of(context).size.width > ScreenBreakpoints.twoColumns - ? _WideWelcome(notifier) - : _NarrowWelcome(notifier), + ? _WideWelcome(welcomeNotifier) + : _NarrowWelcome(welcomeNotifier), ), ); } } class _WideWelcome extends StatelessWidget { - final WelcomeNotifier notifier; + final WelcomeNotifier welcomeNotifier; - const _WideWelcome(this.notifier); + const _WideWelcome(this.welcomeNotifier); @override Widget build(BuildContext context) { return IntrinsicHeight( child: Row( crossAxisAlignment: CrossAxisAlignment.start, - children: [ + children: const [ Expanded( - child: _SdkSelection(notifier), + child: _SdkSelection(), ), Expanded( - child: _TourSummary(notifier), + child: _TourSummary(), ), ], ), @@ -71,30 +77,29 @@ class _WideWelcome extends StatelessWidget { } class _NarrowWelcome extends StatelessWidget { - final WelcomeNotifier notifier; + final WelcomeNotifier welcomeNotifier; - const _NarrowWelcome(this.notifier); + const _NarrowWelcome(this.welcomeNotifier); @override Widget build(BuildContext context) { return Column( - children: [ - _SdkSelection(notifier), - _TourSummary(notifier), + children: const [ + _SdkSelection(), + _TourSummary(), ], ); } } class _SdkSelection extends StatelessWidget { - final WelcomeNotifier notifier; - - const _SdkSelection(this.notifier); + const _SdkSelection(); static const double _minimalHeight = 900; @override Widget build(BuildContext context) { + final appNotifier = GetIt.instance.get(); return Container( constraints: BoxConstraints( minHeight: MediaQuery.of(context).size.height - @@ -127,12 +132,14 @@ class _SdkSelection extends StatelessWidget { } return AnimatedBuilder( - animation: notifier, - builder: (context, child) => _Buttons( + animation: appNotifier, + builder: (context, child) => _SdkButtons( sdks: sdks, - sdkId: notifier.sdkId, - setSdkId: (v) => notifier.sdkId = v, - onStartPressed: notifier.startTour, + sdkId: appNotifier.sdkId, + setSdkId: (v) => appNotifier.sdkId = v, + onStartPressed: () { + _startTour(appNotifier.sdkId); + }, ), ); }, @@ -144,19 +151,25 @@ class _SdkSelection extends StatelessWidget { ), ); } + + void _startTour(String? sdkId) { + if (sdkId == null) { + return; + } + GetIt.instance.get().push(TourPage(sdkId: sdkId)); + } } class _TourSummary extends StatelessWidget { - final WelcomeNotifier notifier; - - const _TourSummary(this.notifier); + const _TourSummary(); @override Widget build(BuildContext context) { + final appNotifier = GetIt.instance.get(); return AnimatedBuilder( - animation: notifier, + animation: appNotifier, builder: (context, child) { - final sdkId = notifier.sdkId; + final sdkId = appNotifier.sdkId; if (sdkId == null) { return Container(); } @@ -211,13 +224,32 @@ class _IntroText extends StatelessWidget { color: BeamColors.grey2, constraints: const BoxConstraints(maxWidth: _dividerMaxWidth), ), - RichText( - text: TextSpan( - style: Theme.of(context).textTheme.bodyLarge, - children: [ + const _IntroTextBody(), + ], + ); + } +} + +class _IntroTextBody extends StatelessWidget { + const _IntroTextBody(); + + @override + Widget build(BuildContext context) { + final authNotifier = GetIt.instance.get(); + return AnimatedBuilder( + animation: authNotifier, + builder: (context, child) => RichText( + text: TextSpan( + style: Theme.of(context).textTheme.bodyLarge, + children: [ + TextSpan( + text: 'pages.welcome.ifSaveProgress'.tr(), + ), + if (authNotifier.isAuthenticated) TextSpan( - text: 'pages.welcome.ifSaveProgress'.tr(), - ), + text: 'pages.welcome.signIn'.tr(), + ) + else TextSpan( text: 'pages.welcome.signIn'.tr(), style: Theme.of(context) @@ -226,25 +258,37 @@ class _IntroText extends StatelessWidget { .copyWith(color: Theme.of(context).primaryColor), recognizer: TapGestureRecognizer() ..onTap = () { - // TODO(nausharipov): sign in + _openLoginDialog(context); }, ), - TextSpan(text: '\n\n${'pages.welcome.selectLanguage'.tr()}'), - ], - ), + TextSpan(text: '\n\n${'pages.welcome.selectLanguage'.tr()}'), + ], ), - ], + ), + ); + } + + void _openLoginDialog(BuildContext context) { + showDialog( + context: context, + builder: (context) => Dialog( + child: LoginContent( + onLoggedIn: () { + Navigator.pop(context); + }, + ), + ), ); } } -class _Buttons extends StatelessWidget { +class _SdkButtons extends StatelessWidget { final List sdks; final String? sdkId; final ValueChanged setSdkId; final VoidCallback onStartPressed; - const _Buttons({ + const _SdkButtons({ required this.sdks, required this.sdkId, required this.setSdkId, diff --git a/learning/tour-of-beam/frontend/lib/pages/welcome/state.dart b/learning/tour-of-beam/frontend/lib/pages/welcome/state.dart index d95b288a61be..0b381a995743 100644 --- a/learning/tour-of-beam/frontend/lib/pages/welcome/state.dart +++ b/learning/tour-of-beam/frontend/lib/pages/welcome/state.dart @@ -18,32 +18,10 @@ import 'package:app_state/app_state.dart'; import 'package:flutter/widgets.dart'; -import 'package:get_it/get_it.dart'; - -import '../tour/page.dart'; import 'path.dart'; class WelcomeNotifier extends ChangeNotifier with PageStateMixin { - String? _sdkId; - + // TODO(nausharipov): remove state from Welcome? @override PagePath get path => const WelcomePath(); - - String? get sdkId => _sdkId; - - set sdkId(String? newValue) { - _sdkId = newValue; - notifyListeners(); - } - - void startTour() { - final sdkId = _sdkId; - if (sdkId == null) { - return; - } - - GetIt.instance.get().push( - TourPage(sdkId: sdkId), - ); - } } diff --git a/learning/tour-of-beam/frontend/lib/repositories/client/client.dart b/learning/tour-of-beam/frontend/lib/repositories/client/client.dart index bdeb3214316c..66fd4a996316 100644 --- a/learning/tour-of-beam/frontend/lib/repositories/client/client.dart +++ b/learning/tour-of-beam/frontend/lib/repositories/client/client.dart @@ -19,6 +19,7 @@ import '../../models/content_tree.dart'; import '../../models/unit_content.dart'; import '../models/get_sdks_response.dart'; +import '../models/get_user_progress_response.dart'; abstract class TobClient { Future getContentTree(String sdkId); @@ -26,4 +27,8 @@ abstract class TobClient { Future getSdks(); Future getUnitContent(String sdkId, String unitId); + + Future getUserProgress(String sdkId); + + Future postUnitComplete(String sdkId, String id); } diff --git a/learning/tour-of-beam/frontend/lib/repositories/client/cloud_functions_client.dart b/learning/tour-of-beam/frontend/lib/repositories/client/cloud_functions_client.dart index e7029fcd829d..8986de435290 100644 --- a/learning/tour-of-beam/frontend/lib/repositories/client/cloud_functions_client.dart +++ b/learning/tour-of-beam/frontend/lib/repositories/client/cloud_functions_client.dart @@ -17,16 +17,21 @@ */ import 'dart:convert'; +import 'dart:io'; +import 'package:get_it/get_it.dart'; import 'package:http/http.dart' as http; +import '../../auth/notifier.dart'; import '../../config.dart'; import '../../models/content_tree.dart'; import '../../models/unit_content.dart'; import '../models/get_content_tree_response.dart'; import '../models/get_sdks_response.dart'; +import '../models/get_user_progress_response.dart'; import 'client.dart'; +// TODO(nausharipov): add repository and handle exceptions class CloudFunctionsTobClient extends TobClient { @override Future getSdks() async { @@ -64,4 +69,36 @@ class CloudFunctionsTobClient extends TobClient { final map = jsonDecode(utf8.decode(json.bodyBytes)) as Map; return UnitContentModel.fromJson(map); } + + @override + Future getUserProgress(String sdkId) async { + final token = await GetIt.instance.get().getToken(); + if (token == null) { + return null; + } + final json = await http.get( + Uri.parse( + '$cloudFunctionsBaseUrl/getUserProgress?sdk=$sdkId', + ), + headers: { + HttpHeaders.authorizationHeader: 'Bearer $token', + }, + ); + final map = jsonDecode(utf8.decode(json.bodyBytes)) as Map; + final response = GetUserProgressResponse.fromJson(map); + return response; + } + + @override + Future postUnitComplete(String sdkId, String id) async { + final token = await GetIt.instance.get().getToken(); + await http.post( + Uri.parse( + '$cloudFunctionsBaseUrl/postUnitComplete?sdk=$sdkId&id=$id', + ), + headers: { + HttpHeaders.authorizationHeader: 'Bearer $token', + }, + ); + } } diff --git a/learning/tour-of-beam/frontend/lib/repositories/models/get_user_progress_response.dart b/learning/tour-of-beam/frontend/lib/repositories/models/get_user_progress_response.dart new file mode 100644 index 000000000000..b9ef766c99dd --- /dev/null +++ b/learning/tour-of-beam/frontend/lib/repositories/models/get_user_progress_response.dart @@ -0,0 +1,33 @@ +/* + * 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. + */ + +import 'package:json_annotation/json_annotation.dart'; + +import '../../models/unit_progress.dart'; + +part 'get_user_progress_response.g.dart'; + +@JsonSerializable(createToJson: false) +class GetUserProgressResponse { + final List units; + + const GetUserProgressResponse({required this.units}); + + factory GetUserProgressResponse.fromJson(Map json) => + _$GetUserProgressResponseFromJson(json); +} diff --git a/learning/tour-of-beam/frontend/lib/repositories/models/get_user_progress_response.g.dart b/learning/tour-of-beam/frontend/lib/repositories/models/get_user_progress_response.g.dart new file mode 100644 index 000000000000..3f4bfae2e294 --- /dev/null +++ b/learning/tour-of-beam/frontend/lib/repositories/models/get_user_progress_response.g.dart @@ -0,0 +1,15 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'get_user_progress_response.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +GetUserProgressResponse _$GetUserProgressResponseFromJson( + Map json) => + GetUserProgressResponse( + units: (json['units'] as List) + .map((e) => UnitProgressModel.fromJson(e as Map)) + .toList(), + ); diff --git a/learning/tour-of-beam/frontend/lib/state.dart b/learning/tour-of-beam/frontend/lib/state.dart new file mode 100644 index 000000000000..c67b037d8d92 --- /dev/null +++ b/learning/tour-of-beam/frontend/lib/state.dart @@ -0,0 +1,58 @@ +/* + * 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. + */ + +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:playground_components/playground_components.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +import 'constants/storage_keys.dart'; + +class AppNotifier extends ChangeNotifier { + String? _sdkId; + + AppNotifier() { + unawaited(_readSdkId()); + } + + // TODO(nausharipov): remove sdkId getter and setter + String? get sdkId => _sdkId; + Sdk? get sdk => Sdk.tryParse(_sdkId); + + set sdkId(String? newValue) { + _sdkId = newValue; + unawaited(_writeSdkId(newValue)); + notifyListeners(); + } + + Future _writeSdkId(String? value) async { + final preferences = await SharedPreferences.getInstance(); + if (value != null) { + await preferences.setString(StorageKeys.sdkId, value); + } else { + await preferences.remove(StorageKeys.sdkId); + } + } + + Future _readSdkId() async { + final preferences = await SharedPreferences.getInstance(); + _sdkId = preferences.getString(StorageKeys.sdkId); + notifyListeners(); + } +} diff --git a/learning/tour-of-beam/frontend/pubspec.lock b/learning/tour-of-beam/frontend/pubspec.lock index 71590abb4eff..0f19f8a44aab 100644 --- a/learning/tour-of-beam/frontend/pubspec.lock +++ b/learning/tour-of-beam/frontend/pubspec.lock @@ -8,6 +8,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "46.0.0" + _flutterfire_internals: + dependency: transitive + description: + name: _flutterfire_internals + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.12" aligned_dialog: dependency: transitive description: @@ -28,7 +35,7 @@ packages: name: app_state url: "https://pub.dartlang.org" source: hosted - version: "0.8.1" + version: "0.8.4" archive: dependency: transitive description: @@ -267,6 +274,48 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "6.1.2" + firebase_auth: + dependency: "direct main" + description: + name: firebase_auth + url: "https://pub.dartlang.org" + source: hosted + version: "4.1.4" + firebase_auth_platform_interface: + dependency: "direct main" + description: + name: firebase_auth_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "6.11.7" + firebase_auth_web: + dependency: transitive + description: + name: firebase_auth_web + url: "https://pub.dartlang.org" + source: hosted + version: "5.1.3" + firebase_core: + dependency: "direct main" + description: + name: firebase_core + url: "https://pub.dartlang.org" + source: hosted + version: "2.4.1" + firebase_core_platform_interface: + dependency: transitive + description: + name: firebase_core_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "4.5.2" + firebase_core_web: + dependency: transitive + description: + name: firebase_core_web + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" fixnum: dependency: transitive description: @@ -285,7 +334,7 @@ packages: name: flutter_code_editor url: "https://pub.dartlang.org" source: hosted - version: "0.2.1" + version: "0.2.5" flutter_driver: dependency: transitive description: flutter @@ -388,6 +437,41 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "3.0.1" + google_sign_in: + dependency: "direct main" + description: + name: google_sign_in + url: "https://pub.dartlang.org" + source: hosted + version: "5.4.2" + google_sign_in_android: + dependency: transitive + description: + name: google_sign_in_android + url: "https://pub.dartlang.org" + source: hosted + version: "6.1.4" + google_sign_in_ios: + dependency: transitive + description: + name: google_sign_in_ios + url: "https://pub.dartlang.org" + source: hosted + version: "5.5.1" + google_sign_in_platform_interface: + dependency: transitive + description: + name: google_sign_in_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "2.3.0" + google_sign_in_web: + dependency: transitive + description: + name: google_sign_in_web + url: "https://pub.dartlang.org" + source: hosted + version: "0.10.2" googleapis_auth: dependency: transitive description: @@ -651,7 +735,7 @@ packages: name: plugin_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "2.1.2" + version: "2.1.3" pool: dependency: transitive description: @@ -694,6 +778,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.2.1" + quiver: + dependency: transitive + description: + name: quiver + url: "https://pub.dartlang.org" + source: hosted + version: "3.1.0" rxdart: dependency: transitive description: diff --git a/learning/tour-of-beam/frontend/pubspec.yaml b/learning/tour-of-beam/frontend/pubspec.yaml index fa059b5153b8..0d6a7329edf2 100644 --- a/learning/tour-of-beam/frontend/pubspec.yaml +++ b/learning/tour-of-beam/frontend/pubspec.yaml @@ -32,11 +32,15 @@ dependencies: easy_localization: ^3.0.1 easy_localization_ext: ^0.1.0 easy_localization_loader: ^1.0.0 + firebase_auth: ^4.1.1 + firebase_auth_platform_interface: ^6.11.7 + firebase_core: ^2.1.1 flutter: { sdk: flutter } flutter_markdown: ^0.6.12 flutter_svg: ^1.0.3 get_it: ^7.2.0 google_fonts: ^3.0.1 + google_sign_in: ^5.4.2 http: ^0.13.5 json_annotation: ^4.7.0 markdown: ^6.0.1 diff --git a/learning/tour-of-beam/frontend/test/main_test.dart b/learning/tour-of-beam/frontend/test/main_test.dart new file mode 100644 index 000000000000..dc0b1dd00b03 --- /dev/null +++ b/learning/tour-of-beam/frontend/test/main_test.dart @@ -0,0 +1,21 @@ +/* + * 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. + */ + +void main() { + // TODO(nausharipov): add unit and integration tests: // https://github.com/apache/beam/issues/24982 +} diff --git a/playground/frontend/playground_components/lib/playground_components.dart b/playground/frontend/playground_components/lib/playground_components.dart index 8d37335e9cca..37d6c6e0848e 100644 --- a/playground/frontend/playground_components/lib/playground_components.dart +++ b/playground/frontend/playground_components/lib/playground_components.dart @@ -17,16 +17,13 @@ */ export 'src/cache/example_cache.dart'; - export 'src/constants/colors.dart'; export 'src/constants/links.dart'; export 'src/constants/sizes.dart'; - export 'src/controllers/example_loaders/examples_loader.dart'; export 'src/controllers/playground_controller.dart'; - +export 'src/controllers/public_notifier.dart'; export 'src/enums/complexity.dart'; - export 'src/models/category_with_examples.dart'; export 'src/models/example.dart'; export 'src/models/example_base.dart'; @@ -47,27 +44,19 @@ export 'src/models/shortcut.dart'; export 'src/models/snippet_file.dart'; export 'src/models/toast.dart'; export 'src/models/toast_type.dart'; - export 'src/playground_components.dart'; - export 'src/repositories/code_client/grpc_code_client.dart'; export 'src/repositories/code_repository.dart'; export 'src/repositories/example_client/grpc_example_client.dart'; export 'src/repositories/example_repository.dart'; - export 'src/router/router_delegate.dart'; - export 'src/services/symbols/loaders/yaml.dart'; - export 'src/theme/switch_notifier.dart'; export 'src/theme/theme.dart'; - export 'src/util/pipeline_options.dart'; - export 'src/widgets/bubble.dart'; export 'src/widgets/clickable.dart'; export 'src/widgets/complexity.dart'; -export 'src/widgets/dismissible_overlay.dart'; export 'src/widgets/divider.dart'; export 'src/widgets/header_icon_button.dart'; export 'src/widgets/loading_error.dart'; @@ -77,6 +66,9 @@ export 'src/widgets/output/output.dart'; export 'src/widgets/output/output_area.dart'; export 'src/widgets/output/output_tab.dart'; export 'src/widgets/output/output_tabs.dart'; +export 'src/widgets/overlay/body.dart'; +export 'src/widgets/overlay/dismissible.dart'; +export 'src/widgets/overlay/opener.dart'; export 'src/widgets/reset_button.dart'; export 'src/widgets/run_or_cancel_button.dart'; export 'src/widgets/shortcut_tooltip.dart'; diff --git a/playground/frontend/playground_components/lib/src/controllers/public_notifier.dart b/playground/frontend/playground_components/lib/src/controllers/public_notifier.dart new file mode 100644 index 000000000000..cbc30fe84b9d --- /dev/null +++ b/playground/frontend/playground_components/lib/src/controllers/public_notifier.dart @@ -0,0 +1,27 @@ +/* + * 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. + */ + +import 'package:flutter/material.dart'; + +/// Exposes notifyListeners that was protected in the superclass. +/// +/// Use this object when you need to fire callbacks that for some +/// reason cannot listen to the object you write your code in. +class PublicNotifier extends ChangeNotifier { + void notifyPublic() => notifyListeners(); +} diff --git a/learning/tour-of-beam/frontend/test/common/test_screen_wrapper.dart b/playground/frontend/playground_components/lib/src/widgets/overlay/body.dart similarity index 66% rename from learning/tour-of-beam/frontend/test/common/test_screen_wrapper.dart rename to playground/frontend/playground_components/lib/src/widgets/overlay/body.dart index 8146e336c3df..5a45c0bcd304 100644 --- a/learning/tour-of-beam/frontend/test/common/test_screen_wrapper.dart +++ b/playground/frontend/playground_components/lib/src/widgets/overlay/body.dart @@ -17,24 +17,20 @@ */ import 'package:flutter/material.dart'; -import 'package:playground_components/playground_components.dart'; -import 'package:provider/provider.dart'; -class TestScreenWrapper extends StatelessWidget { +import '../../constants/sizes.dart'; + +class OverlayBody extends StatelessWidget { final Widget child; - const TestScreenWrapper({required this.child}); + + const OverlayBody({required this.child}); @override Widget build(BuildContext context) { - return ThemeSwitchNotifierProvider( - child: Consumer( - builder: (context, themeSwitchNotifier, _) { - return MaterialApp( - theme: kLightTheme, - home: child, - ); - }, - ), + return Material( + elevation: BeamSizes.size10, + borderRadius: BorderRadius.circular(BeamSizes.size10), + child: child, ); } } diff --git a/playground/frontend/playground_components/lib/src/widgets/dismissible_overlay.dart b/playground/frontend/playground_components/lib/src/widgets/overlay/dismissible.dart similarity index 97% rename from playground/frontend/playground_components/lib/src/widgets/dismissible_overlay.dart rename to playground/frontend/playground_components/lib/src/widgets/overlay/dismissible.dart index 2119c5314c7e..e32e55c56a71 100644 --- a/playground/frontend/playground_components/lib/src/widgets/dismissible_overlay.dart +++ b/playground/frontend/playground_components/lib/src/widgets/overlay/dismissible.dart @@ -19,7 +19,7 @@ import 'package:flutter/material.dart'; class DismissibleOverlay extends StatelessWidget { - final void Function() close; + final VoidCallback close; final Positioned child; const DismissibleOverlay({ diff --git a/playground/frontend/playground_components/lib/src/widgets/overlay/opener.dart b/playground/frontend/playground_components/lib/src/widgets/overlay/opener.dart new file mode 100644 index 000000000000..cb4e107f5f02 --- /dev/null +++ b/playground/frontend/playground_components/lib/src/widgets/overlay/opener.dart @@ -0,0 +1,39 @@ +/* + * 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. + */ + +import 'package:flutter/material.dart'; + +import '../../controllers/public_notifier.dart'; +import 'dismissible.dart'; + +void openOverlay({ + required BuildContext context, + required PublicNotifier closeNotifier, + required Positioned positioned, +}) { + final overlay = OverlayEntry( + builder: (context) { + return DismissibleOverlay( + close: closeNotifier.notifyPublic, + child: positioned, + ); + }, + ); + closeNotifier.addListener(overlay.remove); + Overlay.of(context)?.insert(overlay); +}