diff --git a/.bazelignore b/.bazelignore new file mode 100644 index 00000000000..a1fd437354a --- /dev/null +++ b/.bazelignore @@ -0,0 +1,2 @@ +.bazel-user-root +.bazelisk-home diff --git a/.bazelrc b/.bazelrc index 393e2a552e3..c059370e1f3 100644 --- a/.bazelrc +++ b/.bazelrc @@ -1,5 +1,33 @@ +common --noenable_bzlmod +# Let the OS-specific sections below (`common:linux`, `common:macos`, etc.) +# take effect so one `.bazelrc` can carry the required per-platform C++ flags. +common --enable_platform_specific_config common --experimental_repo_remote_exec # from TensorFlow +# Bazel-generated Python package init files can shadow TensorBoard's real +# compat package init at test runtime; keep this test-only so pip packaging +# still copies the intended package tree. +test --incompatible_default_to_explicit_init_py # Use C++ backing implementations for Python proto parsing and deserialization, # which is much faster (~10x). build --define=use_fast_cpp_protos=true + +# Protobuf 6.31.1 requires C++17 in this build. Keep the host and target +# language level aligned across supported platforms. +common:linux --cxxopt=-std=c++17 +common:linux --host_cxxopt=-std=c++17 +common:macos --cxxopt=-std=c++17 +common:macos --host_cxxopt=-std=c++17 +common:windows --cxxopt=/std:c++17 +common:windows --host_cxxopt=/std:c++17 + +# Local shells and virtualenvs can leak Python import state into Bazel tests, +# which then import from the wrong environment instead of the test runfiles. +test --test_env=PYTHONPATH= +test --test_env=PYTHONHOME= +test --test_env=PYTHONSTARTUP= +test --test_env=PYTHONSAFEPATH= +test --test_env=PYTHONNOUSERSITE=1 +test --test_env=PYTHONUSERBASE= +test --test_env=BUILD_WORKSPACE_DIRECTORY= +test --test_env=BUILD_WORKING_DIRECTORY= diff --git a/.bazelversion b/.bazelversion index f22d756da39..1985849fb58 100644 --- a/.bazelversion +++ b/.bazelversion @@ -1 +1 @@ -6.5.0 +7.7.0 diff --git a/.gitattributes b/.gitattributes index 752a9642c09..75e06739b02 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1,10 @@ +* text=auto +*.bzl text eol=lf +*.sh text eol=lf +.bazel* text eol=lf +BUILD text eol=lf +BUILD.bazel text eol=lf +WORKSPACE text eol=lf +MODULE.bazel text eol=lf + third_party/rust/** -diff -merge linguist-generated=true diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e09c955a8d5..634d9675f17 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,8 +25,8 @@ permissions: env: # Keep this Bazel version in sync with the `versions.check` directive # in our WORKSPACE file. - BAZEL_VERSION: '6.5.0' - BAZEL_SHA256SUM: 'a40ac69263440761199fcb8da47ad4e3f328cbe79ffbf4ecc14e5ba252857307' + BAZEL_VERSION: '7.7.0' + BAZEL_SHA256SUM: 'fe7e799cbc9140f986b063e06800a3d4c790525075c877d00a7112669824acbf' BUILDTOOLS_VERSION: '3.0.0' BUILDIFIER_SHA256SUM: 'e92a6793c7134c5431c58fbc34700664f101e5c9b1c1fcd93b97978e8b7f88db' BUILDOZER_SHA256SUM: '3d58a0b6972e4535718cdd6c12778170ea7382de7c75bc3728f5719437ffb84d' @@ -48,13 +48,40 @@ jobs: fail-fast: false matrix: tf_version_id: ['tf', 'notf'] - python_version: ['3.9'] + python_version: ['3.10'] steps: - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0 - - uses: actions/setup-python@13ae5bb136fac2878aff31522b9efb785519f984 # v4.3.0 - with: - python-version: ${{ matrix.python_version }} - architecture: 'x64' + # Use the container's system Python installation path instead of + # actions/setup-python so Bazel's @system_python repo sees a standard + # interpreter/header layout. + - name: 'Set up Python and system dependencies' + run: | + py_abi="python${{ matrix.python_version }}" + sudo apt-get update + sudo apt-get install -y \ + "${py_abi}" \ + "${py_abi}-dev" \ + "${py_abi}-venv" \ + libgbm-dev \ + libxss1 \ + libasound2 + "/usr/bin/${py_abi}" -m venv /tmp/tb-build-venv + echo "/tmp/tb-build-venv/bin" >> "${GITHUB_PATH}" + echo "VIRTUAL_ENV=/tmp/tb-build-venv" >> "${GITHUB_ENV}" + /tmp/tb-build-venv/bin/python -m pip install -U pip setuptools wheel virtualenv + - name: 'Check Python toolchain' + run: | + python --version + python - <<'PY' + import pathlib + import sys + import sysconfig + + print("sys.executable =", sys.executable) + include_dir = pathlib.Path(sysconfig.get_config_var("INCLUDEPY")) + print("INCLUDEPY =", include_dir) + print("Python.h exists =", (include_dir / "Python.h").exists()) + PY - name: 'Set up Bazel' run: | ci/download_bazel.sh "${BAZEL_VERSION}" "${BAZEL_SHA256SUM}" ~/bazel @@ -65,6 +92,11 @@ jobs: run: | python -m pip install -U pip pip install "${TENSORFLOW_VERSION}" + # tf-nightly currently pulls in tb-nightly as a dependency. Bazel's + # source-tree tests must import TensorBoard from runfiles rather than + # from site-packages, otherwise tests that rely on local-only modules + # like `tensorboard.test` resolve against the installed wheel and fail. + pip uninstall -y tensorboard tb-nightly || true if: matrix.tf_version_id != 'notf' - name: 'Install Python dependencies' run: | @@ -73,10 +105,6 @@ jobs: -r ./tensorboard/pip_package/requirements.txt \ -r ./tensorboard/pip_package/requirements_dev.txt \ ; - - name: 'Install Chrome dependencies' - run: | - sudo apt-get update - sudo apt-get install -y libgbm-dev libxss1 libasound2 - name: 'Check Pip state' run: pip freeze --all - name: 'Bazel: fetch' @@ -98,13 +126,21 @@ jobs: if: matrix.tf_version_id == 'notf' - name: 'Bazel: run Pip package test (with TensorFlow support)' run: | - bazel run //tensorboard/pip_package:test_pip_package -- \ + # `bazel run` has been flaky under this self-hosted container runner + # even when the smoke test itself completes successfully. Build the + # launcher target, invoke the generated binary directly, then shut + # down the Bazel server so the step exits cleanly. + bazel build //tensorboard/pip_package:test_pip_package + ./bazel-bin/tensorboard/pip_package/test_pip_package \ --tf-version "${TENSORFLOW_VERSION}" + bazel shutdown if: matrix.tf_version_id != 'notf' - name: 'Bazel: run Pip package test (non-TensorFlow only)' run: | - bazel run //tensorboard/pip_package:test_pip_package -- \ + bazel build //tensorboard/pip_package:test_pip_package + ./bazel-bin/tensorboard/pip_package/test_pip_package \ --tf-version notf + bazel shutdown if: matrix.tf_version_id == 'notf' - name: 'Bazel: run manual tests' run: | @@ -310,7 +346,8 @@ jobs: - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0 - uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3.6.0 with: - node-version: 16 + # Angular v17 supports node.js versions: v18.13.0 and newer + node-version: 18 - run: yarn install --ignore-engines # You can run `yarn fix-lint` to fix all Prettier complaints, although at this point this will try to fix too many things. # To fix only the files changed in this PR, see the command below. @@ -321,7 +358,7 @@ jobs: # Make sure no one depends on Angular material and CDK directly. Please # import the indirection in //tensorboard/webapp/angular. - run: | - ! git grep -E '"@npm//@angular/material"|"@npm//@angular/cdk"' 'tensorboard/*/BUILD' ':!tensorboard/webapp/BUILD' ':!tensorboard/webapp/angular/BUILD' + ! git grep -E '"@npm//@angular/material"|"@npm//@angular/cdk"' 'tensorboard/*/BUILD' ':!tensorboard/webapp/angular/BUILD' ':!tensorboard/webapp/angular_components/BUILD' # Cannot directly depend on d3 in webapp. Must depend on # `//tensorboard/webapp/third_party:d3` instead. - run: | diff --git a/WORKSPACE b/WORKSPACE index 67e90a09156..be04cfe68ae 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -1,6 +1,9 @@ workspace(name = "org_tensorflow_tensorboard") load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") +load("@bazel_tools//tools/build_defs/repo:java.bzl", "java_import_external") +load("@bazel_tools//tools/build_defs/repo:local.bzl", "local_repository") +load("//third_party:repo.bzl", "tb_http_archive", "tb_mirror_urls") http_archive( name = "bazel_skylib", @@ -18,10 +21,10 @@ versions.check( # Preemptively assume the next Bazel major version will break us, since historically they do, # and provide a clean error message in that case. Since the maximum version is inclusive rather # than exclusive, we set it to the 999th patch release of the current major version. - maximum_bazel_version = "6.999.0", + maximum_bazel_version = "7.999.0", # Keep this version in sync with: # * The BAZEL environment variable defined in .github/workflows/ci.yml, which is used for CI and nightly builds. - minimum_bazel_version = "6.5.0", + minimum_bazel_version = "7.7.0", ) http_archive( @@ -35,6 +38,34 @@ load("@io_bazel_rules_webtesting//web:repositories.bzl", "web_test_repositories" web_test_repositories(omit_bazel_skylib = True) +http_archive( + name = "io_bazel_rules_go", + sha256 = "278b7ff5a826f3dc10f04feaf0b70d48b68748ccd512d7f98bf442077f043fe3", + urls = [ + "http://mirror.tensorflow.org/github.com/bazelbuild/rules_go/releases/download/v0.41.0/rules_go-v0.41.0.zip", + "https://github.com/bazelbuild/rules_go/releases/download/v0.41.0/rules_go-v0.41.0.zip", + ], +) + +load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies") + +go_rules_dependencies() + +go_register_toolchains(version = "1.20.5") + +http_archive( + name = "bazel_gazelle", + sha256 = "29218f8e0cebe583643cbf93cae6f971be8a2484cdcfa1e45057658df8d54002", + urls = [ + "http://mirror.tensorflow.org/github.com/bazelbuild/bazel-gazelle/releases/download/v0.32.0/bazel-gazelle-v0.32.0.tar.gz", + "https://github.com/bazelbuild/bazel-gazelle/releases/download/v0.32.0/bazel-gazelle-v0.32.0.tar.gz", + ], +) + +load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies") + +gazelle_dependencies() + # rules_python has to be placed before load("@io_bazel_rules_closure//closure:repositories.bzl") # in the dependencies list, otherwise we get "cannot load '@rules_python//python:py_xxx.bzl': no such file" http_archive( @@ -53,6 +84,8 @@ py_repositories() http_archive( name = "io_bazel_rules_closure", + patch_args = ["-p1"], + patches = ["//patches:rules_closure_soy_cli.patch"], sha256 = "ae060075a7c468eee42e6a08ddbb83f5a6663bdfdbd461261a465f4a3ae8598c", strip_prefix = "rules_closure-7f3d3351a8cc31fbaa403de7d35578683c17b447", urls = [ @@ -60,20 +93,112 @@ http_archive( ], ) +# rules_closure's Soy toolchain still expects safe-html-types classes that are +# compatible with protobuf-java 6.x. We use a local repository here because +# TensorBoard needs a protobuf-6-compatible adjusted copy of those classes, +# not just any upstream safe-html-types release. +local_repository( + name = "com_google_common_html_types", + path = "third_party/safe_html_types", +) + +java_import_external( + name = "com_google_flogger_flogger", + jar_sha256 = "b5ecd1483e041197012786f749968a62063c1964d3ecfbf96ba92a95797bb8f5", + jar_urls = [ + "http://mirror.tensorflow.org/repo1.maven.org/maven2/com/google/flogger/flogger/0.5.1/flogger-0.5.1.jar", + "https://repo1.maven.org/maven2/com/google/flogger/flogger/0.5.1/flogger-0.5.1.jar", + ], + licenses = ["notice"], +) + +java_import_external( + name = "com_google_flogger_google_extensions", + jar_sha256 = "8b0862cad85b9549f355fe383c6c63816d2f19529634e033ae06d0107ab110b9", + jar_urls = [ + "http://mirror.tensorflow.org/repo1.maven.org/maven2/com/google/flogger/google-extensions/0.5.1/google-extensions-0.5.1.jar", + "https://repo1.maven.org/maven2/com/google/flogger/google-extensions/0.5.1/google-extensions-0.5.1.jar", + ], + licenses = ["notice"], + deps = ["@com_google_flogger_flogger"], +) + +java_import_external( + name = "com_google_flogger_flogger_system_backend", + jar_sha256 = "685de33b53eb313049bbeee7f4b7a80dd09e8e754e96b048a3edab2cebb36442", + jar_urls = [ + "http://mirror.tensorflow.org/repo1.maven.org/maven2/com/google/flogger/flogger-system-backend/0.5.1/flogger-system-backend-0.5.1.jar", + "https://repo1.maven.org/maven2/com/google/flogger/flogger-system-backend/0.5.1/flogger-system-backend-0.5.1.jar", + ], + licenses = ["notice"], + deps = ["@com_google_flogger_flogger"], +) + +# rules_closure's Java/Soy path still needs an explicit Soy compiler jar and +# its runtime deps. We wire those here so Closure/Soy keeps working while using +# our protobuf-6-compatible safe-html-types and protobuf-java dependencies. +java_import_external( + name = "com_google_template_soy", + extra_build_file_content = "\n".join([ + ("java_binary(\n" + + " name = \"%s\",\n" + + " main_class = \"com.google.template.soy.%s\",\n" + + " output_licenses = [\"unencumbered\"],\n" + + " runtime_deps = [\":com_google_template_soy\"],\n" + + ")\n") % (name, name) + for name in ( + "SoyParseInfoGenerator", + "SoyToJbcSrcCompiler", + "SoyToJsSrcCompiler", + "SoyToPySrcCompiler", + ) + ]), + jar_sha256 = "643440022e247ef8ad25bacb83ba099ccd2ae4b1fd078d9e9e3d3dd4af00411f", + jar_urls = [ + "https://repo1.maven.org/maven2/com/google/template/soy/2022-03-07/soy-2022-03-07.jar", + ], + licenses = ["notice"], + deps = [ + "@args4j", + "@com_google_code_findbugs_jsr305", + "@com_google_code_gson", + "@com_google_common_html_types", + "@com_google_flogger_flogger", + "@com_google_flogger_flogger_system_backend", + "@com_google_flogger_google_extensions", + "@com_google_guava", + "@com_google_inject_extensions_guice_assistedinject", + "@com_google_inject_extensions_guice_multibindings", + "@com_google_inject_guice", + "@com_google_protobuf//:protobuf_java", + "@com_ibm_icu_icu4j", + "@javax_inject", + "@org_json", + "@org_ow2_asm", + "@org_ow2_asm_analysis", + "@org_ow2_asm_commons", + "@org_ow2_asm_util", + ], +) + load("@io_bazel_rules_closure//closure:repositories.bzl", "rules_closure_dependencies") +# Omit the Closure-provided copies of these repositories so that rules_closure +# uses the adjusted/local versions declared above instead of re-introducing +# older transitive Java deps that conflict with protobuf 6.x in this setup. rules_closure_dependencies( omit_bazel_skylib = True, + omit_com_google_common_html_types = True, omit_com_google_protobuf = True, omit_com_google_protobuf_js = True, + omit_com_google_template_soy = True, ) http_archive( name = "build_bazel_rules_nodejs", - sha256 = "c29944ba9b0b430aadcaf3bf2570fece6fc5ebfb76df145c6cdad40d65c20811", + sha256 = "f02557f31d4110595ca6e93660018bcd7fdfdbe7d0086089308f1b3af3a7a7ee", urls = [ - "http://mirror.tensorflow.org/github.com/bazelbuild/rules_nodejs/releases/download/5.7.0/rules_nodejs-5.7.0.tar.gz", - "https://github.com/bazelbuild/rules_nodejs/releases/download/5.7.0/rules_nodejs-5.7.0.tar.gz", + "https://github.com/bazelbuild/rules_nodejs/releases/download/5.8.1/rules_nodejs-5.8.1.tar.gz", ], ) @@ -81,20 +206,40 @@ load("@build_bazel_rules_nodejs//:repositories.bzl", "build_bazel_rules_nodejs_d build_bazel_rules_nodejs_dependencies() -load("@build_bazel_rules_nodejs//:index.bzl", "yarn_install") +load("@build_bazel_rules_nodejs//:index.bzl", "node_repositories", "yarn_install") + +# Angular 17 needs Node.js 18.17 or higher. rules_nodejs 5.8.1 does not +# include Node 18, so we add it here manually. +# @TODO(@cdavalos7): We plan to upgrade to a newer version of rules_nodejs that includes Node 18 and remove this manual addition in next version upgrade. +node_repositories( + node_repositories = { + "18.20.8-darwin_arm64": ("node-v18.20.8-darwin-arm64.tar.gz", "node-v18.20.8-darwin-arm64", "bae4965d29d29bd32f96364eefbe3bca576a03e917ddbb70b9330d75f2cacd76"), + "18.20.8-darwin_amd64": ("node-v18.20.8-darwin-x64.tar.gz", "node-v18.20.8-darwin-x64", "ed2554677188f4afc0d050ecd8bd56effb2572d6518f8da6d40321ede6698509"), + "18.20.8-linux_arm64": ("node-v18.20.8-linux-arm64.tar.xz", "node-v18.20.8-linux-arm64", "224e569dbe7b0ea4628ce383d9d482494b57ee040566583f1c54072c86d1116b"), + "18.20.8-linux_amd64": ("node-v18.20.8-linux-x64.tar.xz", "node-v18.20.8-linux-x64", "5467ee62d6af1411d46b6a10e3fb5cacc92734dbcef465fea14e7b90993001c9"), + "18.20.8-windows_amd64": ("node-v18.20.8-win-x64.zip", "node-v18.20.8-win-x64", "1a1e40260a6facba83636e4cd0ba01eb5bd1386896824b36645afba44857384a"), + }, + node_version = "18.20.8", +) yarn_install( name = "npm", - data = [ - "//patches:@angular+build-tooling+0.0.0-7d103b83a07f132629592fc9918ce17d42a5e382.patch", - "//patches:@bazel+concatjs+5.7.0.patch", - ], # "Some rules only work by referencing labels nested inside npm packages # and therefore require turning off exports_directories_only." # This includes "ts_library". # See: https://github.com/bazelbuild/rules_nodejs/wiki/Migrating-to-5.0#exports_directories_only exports_directories_only = False, package_json = "//:package.json", + package_json_remove = ["scripts.postinstall"], + patch_args = ["-p1"], + # We still author these npm patches with patch-package, but applying them + # by invoking patch-package inside the repository rule proved unreliable in + # this Bazel/CI setup. Apply the generated patch artifacts directly during + # yarn_install instead. + post_install_patches = [ + "//patches:@angular+build-tooling+0.0.0-2113cd7f66a089ac0208ea84eee672b2529f4f6c.patch", + "//patches:@bazel+concatjs+5.8.1.patch", + ], yarn_lock = "//:yarn.lock", ) @@ -107,15 +252,15 @@ esbuild_repositories(npm_repository = "npm") # rules_sass release information is difficult to find but it does seem to # regularly release with same cadence and version as core sass. # We typically upgrade this library whenever we upgrade rules_nodejs. +# This rules_sass version is the compatible with rules_nodejs 5.8.1 # -# rules_sass 1.55.0: https://github.com/bazelbuild/rules_sass/tree/1.55.0 +# rules_sass: https://github.com/bazelbuild/rules_sass/releases/tag/1.69.5 http_archive( name = "io_bazel_rules_sass", - sha256 = "1ea0103fa6adcb7d43ff26373b5082efe1d4b2e09c4f34f8a8f8b351e9a8a9b0", - strip_prefix = "rules_sass-1.55.0", + sha256 = "4285781b24dfd07cb01fcc2324faec87818d0f2174b02e0ed9038f6f809de80a", + strip_prefix = "rules_sass-1.69.5", urls = [ - "http://mirror.tensorflow.org/github.com/bazelbuild/rules_sass/archive/1.55.0.zip", - "https://github.com/bazelbuild/rules_sass/archive/1.55.0.zip", + "https://github.com/bazelbuild/rules_sass/archive/refs/tags/1.69.5.tar.gz", ], ) @@ -133,65 +278,117 @@ sass_repositories() # high as the version of protobuf we depend on below, and we cannot increase the # version below without bumping the requirements.txt version. # -# TODO(#6185): Remove the TODO below once the TF constraint no longer applies. -# -# NOTE: This dependency currently cannot be advanced past 3.19.x. This is because -# TF is currently unable to use a runtime any greater than 3.19.x, see details here: -# https://github.com/tensorflow/tensorflow/blob/9d22f4a0a9499c8e10a4312503e63e0da35ccd94/tensorflow/tools/pip_package/setup.py#L100-L107 -# -# As a result of TF's constraint and the above <= requirement, 3.19.x is the most recent -# possible protoc we can use while remaining cross-compatible with TF. At the same time, -# 3.19.x is the minimum possible protoc that will generate compiled proto code that *is* -# compatible with protobuf runtimes >= 4, as discussed here: -# https://developers.google.com/protocol-buffers/docs/news/2022-05-06 +# TensorFlow 2.21 uses protobuf 6.31.1 in its own build and pip package +# constraints. Keep this Bazel-side protoc version aligned with that runtime +# floor so generated Python code and the ambient `protobuf` package remain +# compatible. +tb_http_archive( + name = "tb_rules_cc", + patch_file = ["//patches:rules_cc_protobuf.patch"], + repo_mapping = { + "@rules_cc": "@tb_rules_cc", + }, + sha256 = "4b12149a041ddfb8306a8fd0e904e39d673552ce82e4296e96fac9cbf0780e59", + strip_prefix = "rules_cc-0.1.0", + urls = tb_mirror_urls("https://github.com/bazelbuild/rules_cc/archive/refs/tags/0.1.0.tar.gz"), +) + http_archive( + name = "tb_rules_java", + sha256 = "b2519fabcd360529071ade8732f208b3755489ed7668b118f8f90985c0e51324", + strip_prefix = "rules_java-8.6.1", + urls = tb_mirror_urls("https://github.com/bazelbuild/rules_java/archive/refs/tags/8.6.1.tar.gz"), +) + +local_repository( + name = "compatibility_proxy", + path = "third_party/compatibility_proxy", +) + +# Protobuf 6.31.1 still expects a pip-style requirements helper repo from its +# WORKSPACE macros. TensorBoard only needs the narrow `install_deps()` / +# `requirement()` surface that protobuf actually loads in this configuration. +local_repository( + name = "protobuf_pip_deps", + path = "third_party/protobuf_pip_deps", +) + +# Protobuf's python/dist BUILD also references +# `external/protobuf_pip_deps_setuptools/site-packages`, so keep this separate +# repo shape even though it only vendors an empty placeholder tree here. +local_repository( + name = "protobuf_pip_deps_setuptools", + path = "third_party/protobuf_pip_deps_setuptools", +) + +load("@tb_rules_java//java:rules_java_deps.bzl", "rules_java_dependencies") + +tb_http_archive( + name = "com_google_absl", + repo_mapping = { + "@rules_cc": "@tb_rules_cc", + }, + sha256 = "d8ae9aa794a571ee39c77085ee69f1d4ac276212a7d99734974d95df7baa8d13", + strip_prefix = "abseil-cpp-9ac7062b1860d895fb5a8cbf58c3e9ef8f674b5f", + urls = tb_mirror_urls("https://github.com/abseil/abseil-cpp/archive/9ac7062b1860d895fb5a8cbf58c3e9ef8f674b5f.zip"), +) + +tb_http_archive( name = "com_google_protobuf", - sha256 = "9a301cf94a8ddcb380b901e7aac852780b826595075577bb967004050c835056", - strip_prefix = "protobuf-3.19.6", - urls = [ - "http://mirror.tensorflow.org/github.com/protocolbuffers/protobuf/archive/v3.19.6.tar.gz", - "https://github.com/protocolbuffers/protobuf/archive/v3.19.6.tar.gz", # 2022-09-29 - ], + patch_file = ["//patches:protobuf_6_31_1_java_export.patch"], + repo_mapping = { + "@abseil-cpp": "@com_google_absl", + "@rules_cc": "@tb_rules_cc", + "@rules_java": "@tb_rules_java", + }, + sha256 = "6e09bbc950ba60c3a7b30280210cd285af8d7d8ed5e0a6ed101c72aff22e8d88", + strip_prefix = "protobuf-6.31.1", + urls = tb_mirror_urls("https://github.com/protocolbuffers/protobuf/archive/refs/tags/v6.31.1.zip"), ) +rules_java_dependencies() + +load("@com_google_protobuf//:protobuf_deps.bzl", "protobuf_deps") + +protobuf_deps() + # gRPC. # -# NOTE: The version used here must be cross-compatible with our protobuf version. -# As 2023-01-13, 1.48.2 is the most recent gRPC release that was still using a 3.19.x -# version of protobuf in its own builds (more recent releases move to 3.21.x). +# Keep this aligned with TensorFlow 2.21's Bazel-side gRPC dependency so the +# grpc plugin and protobuf repository stay on a known-compatible combination. http_archive( name = "com_github_grpc_grpc", - sha256 = "bdb8e98145469d58c69ab9f2c9e0bd838c2836a99b5760bc0ebf658623768f52", - strip_prefix = "grpc-1.48.2", - urls = [ - "http://mirror.tensorflow.org/github.com/grpc/grpc/archive/v1.48.2.tar.gz", - "https://github.com/grpc/grpc/archive/v1.48.2.tar.gz", # 2022-09-21 - ], + sha256 = "dd6a2fa311ba8441bbefd2764c55b99136ff10f7ea42954be96006a2723d33fc", + strip_prefix = "grpc-1.74.0", + urls = tb_mirror_urls("https://github.com/grpc/grpc/archive/refs/tags/v1.74.0.tar.gz"), +) + +http_archive( + name = "build_bazel_rules_swift", + sha256 = "9919ed1d8dae509645bfd380537ae6501528d8de971caebed6d5185b9970dc4d", + urls = tb_mirror_urls("https://github.com/bazelbuild/rules_swift/releases/download/2.1.1/rules_swift.2.1.1.tar.gz"), ) load("@com_github_grpc_grpc//bazel:grpc_deps.bzl", "grpc_deps") grpc_deps() -load("@com_github_grpc_grpc//bazel:grpc_extra_deps.bzl", "grpc_extra_deps") - -grpc_extra_deps() - http_archive( name = "rules_rust", sha256 = "08109dccfa5bbf674ff4dba82b15d40d85b07436b02e62ab27e0b894f45bb4a3", strip_prefix = "rules_rust-d5ab4143245af8b33d1947813d411a6cae838409", urls = [ - # Master branch as of 2022-01-31 + # Pinned to this upstream commit as of 2022-01-31 "http://mirror.tensorflow.org/github.com/bazelbuild/rules_rust/archive/d5ab4143245af8b33d1947813d411a6cae838409.tar.gz", "https://github.com/bazelbuild/rules_rust/archive/d5ab4143245af8b33d1947813d411a6cae838409.tar.gz", ], ) -# WORKAROUND for rules_webtesting not declaring used com_github_gorilla_mux repo: -load("@io_bazel_rules_webtesting//web:go_repositories.bzl", "com_github_gorilla_mux") +load("@io_bazel_rules_webtesting//web:go_repositories.bzl", "go_internal_repositories", "go_repositories") + +go_repositories() -com_github_gorilla_mux() +go_internal_repositories() # Please add all new dependencies in workspace.bzl. load("//third_party:workspace.bzl", "tensorboard_workspace") diff --git a/ci/bazelrc b/ci/bazelrc index 4bda9653d6f..3cf4037d3dd 100644 --- a/ci/bazelrc +++ b/ci/bazelrc @@ -6,6 +6,12 @@ build --worker_max_instances=2 # Ensure sandboxing is on to increase hermeticity. build --spawn_strategy=sandboxed build --worker_sandboxing +# Bazel 7 may materialize frontend/npm assets with CopyFile/CopyDirectory +# actions that are not executable under processwrapper-sandbox alone. +# Keep sandboxing for normal actions, but allow these copy helpers to run +# locally so Angular/sass/esbuild repository actions remain buildable in CI. +build --strategy=CopyFile=local +build --strategy=CopyDirectory=local # Ensure the PATH env var from our virtualenv propagates into tests, which is # no longer on by default in Bazel 0.21.0 and possibly again in the future. diff --git a/package.json b/package.json index 5e44f963635..4ba5142a4a6 100644 --- a/package.json +++ b/package.json @@ -28,18 +28,18 @@ }, "homepage": "https://github.com/tensorflow/tensorboard#readme", "devDependencies": { - "@angular-devkit/build-angular": "^15.2.9", - "@angular/build-tooling": "https://github.com/angular/dev-infra-private-build-tooling-builds.git#fb42478534df7d48ec23a6834fea94a776cb89a0", - "@angular/cli": "^16.2.0", - "@angular/compiler": "16.2.12", - "@angular/compiler-cli": "^16.2.12", + "@angular-devkit/build-angular": "^17.0.0", + "@angular/build-tooling": "https://github.com/angular/dev-infra-private-build-tooling-builds.git#3069be882e3e41cdb3dad58788d878e31d7d82e8", + "@angular/cli": "^17.0.0", + "@angular/compiler": "17.3.12", + "@angular/compiler-cli": "^17.0.0", "@babel/core": "^7.16.12", - "@bazel/concatjs": "5.7.0", - "@bazel/esbuild": "5.7.0", + "@bazel/concatjs": "5.8.1", + "@bazel/esbuild": "5.8.1", "@bazel/ibazel": "^0.15.9", - "@bazel/jasmine": "5.7.0", - "@bazel/terser": "5.7.0", - "@bazel/typescript": "5.7.0", + "@bazel/jasmine": "5.8.1", + "@bazel/terser": "5.8.1", + "@bazel/typescript": "5.8.1", "@types/d3": "5.7.2", "@types/jasmine": "^3.8.2", "@types/lodash": "^4.14.172", @@ -61,22 +61,22 @@ "prettier-plugin-organize-imports": "2.3.4", "requirejs": "^2.3.7", "tslib": "^2.3.0", - "typescript": "4.9.5", + "typescript": "5.2.2", "yarn-deduplicate": "^5.0.0" }, "dependencies": { - "@angular/animations": "^16.2.12", - "@angular/cdk": "^16.2.14", - "@angular/common": "16.2.12", - "@angular/core": "^16.2.12", - "@angular/forms": "^16.2.12", - "@angular/localize": "^16.2.12", - "@angular/material": "^16.2.14", - "@angular/platform-browser": "^16.2.12", - "@angular/platform-browser-dynamic": "^16.2.12", - "@angular/router": "^16.2.12", - "@ngrx/effects": "^15.4.0", - "@ngrx/store": "^15.4.0", + "@angular/animations": "^17.0.0", + "@angular/cdk": "^17.0.0", + "@angular/common": "17.3.12", + "@angular/core": "^17.0.0", + "@angular/forms": "^17.0.0", + "@angular/localize": "^17.0.0", + "@angular/material": "^17.0.0", + "@angular/platform-browser": "^17.0.0", + "@angular/platform-browser-dynamic": "^17.0.0", + "@angular/router": "^17.0.0", + "@ngrx/effects": "^17.0.0", + "@ngrx/store": "^17.0.0", "@polymer/decorators": "^3.0.0", "@polymer/iron-behaviors": "^3.0.1", "@polymer/iron-collapse": "^3.0.1", @@ -131,7 +131,7 @@ "three": "~0.137.0", "umap-js": "^1.3.2", "web-animations-js": "^2.3.2", - "zone.js": "^0.13.3" + "zone.js": "^0.14.0" }, "resolutions": { "@types/d3-brush": "1.1.8", diff --git a/patches/@angular+build-tooling+0.0.0-2113cd7f66a089ac0208ea84eee672b2529f4f6c.patch b/patches/@angular+build-tooling+0.0.0-2113cd7f66a089ac0208ea84eee672b2529f4f6c.patch new file mode 100644 index 00000000000..3c546418efb --- /dev/null +++ b/patches/@angular+build-tooling+0.0.0-2113cd7f66a089ac0208ea84eee672b2529f4f6c.patch @@ -0,0 +1,33 @@ +diff --git a/node_modules/@angular/build-tooling/shared-scripts/angular-optimization/BUILD.bazel b/node_modules/@angular/build-tooling/shared-scripts/angular-optimization/BUILD.bazel +index 870da1b..3f1e5c5 100755 +--- a/node_modules/@angular/build-tooling/shared-scripts/angular-optimization/BUILD.bazel ++++ b/node_modules/@angular/build-tooling/shared-scripts/angular-optimization/BUILD.bazel +@@ -23,6 +23,7 @@ js_library( + deps = [ + "@npm//@babel/core", + "@npm//@babel/helper-annotate-as-pure", ++ "@npm//@babel/helper-split-export-declaration", + ], + ) + +diff --git a/node_modules/@angular/build-tooling/shared-scripts/angular-optimization/esbuild-plugin.mjs b/node_modules/@angular/build-tooling/shared-scripts/angular-optimization/esbuild-plugin.mjs +index 6d5ec3f..ad4217f 100755 +--- a/node_modules/@angular/build-tooling/shared-scripts/angular-optimization/esbuild-plugin.mjs ++++ b/node_modules/@angular/build-tooling/shared-scripts/angular-optimization/esbuild-plugin.mjs +@@ -86,11 +86,11 @@ export async function createEsbuildAngularOptimizePlugin(opts, additionalBabelPl + devkitOptimizePlugins.adjustTypeScriptEnumsPlugin, + ); + +- // If the current file is denoted as explicit side effect free, add the pure +- // top-level functions optimization plugin for this file. +- if (opts.optimize.isSideEffectFree && opts.optimize.isSideEffectFree(args.path)) { +- plugins.push(devkitOptimizePlugins.pureToplevelFunctionsPlugin); +- } ++ // For TensorBoard: This plugin aggressively culls symbols in a way that ++ // is incompatible with TensorBoard source. Disable it. As result the binary is bigger. ++ //if (opts.optimize.isSideEffectFree && opts.optimize.isSideEffectFree(args.path)) { ++ // plugins.push(devkitOptimizePlugins.pureToplevelFunctionsPlugin); ++ //} + } + + const shouldRunLinker = diff --git a/patches/@angular+build-tooling+0.0.0-7d103b83a07f132629592fc9918ce17d42a5e382.patch b/patches/@angular+build-tooling+0.0.0-7d103b83a07f132629592fc9918ce17d42a5e382.patch deleted file mode 100644 index db8c439cd38..00000000000 --- a/patches/@angular+build-tooling+0.0.0-7d103b83a07f132629592fc9918ce17d42a5e382.patch +++ /dev/null @@ -1,32 +0,0 @@ -diff --git a/node_modules/@angular/build-tooling/shared-scripts/angular-optimization/BUILD.bazel b/node_modules/@angular/build-tooling/shared-scripts/angular-optimization/BUILD.bazel -index d5a8645..4b57378 100755 ---- a/node_modules/@angular/build-tooling/shared-scripts/angular-optimization/BUILD.bazel -+++ b/node_modules/@angular/build-tooling/shared-scripts/angular-optimization/BUILD.bazel -@@ -23,6 +23,7 @@ js_library( - deps = [ - "@npm//@babel/core", - "@npm//@babel/helper-annotate-as-pure", -+ "@npm//@babel/helper-split-export-declaration", - ], - ) - -diff --git a/node_modules/@angular/build-tooling/shared-scripts/angular-optimization/esbuild-plugin.mjs b/node_modules/@angular/build-tooling/shared-scripts/angular-optimization/esbuild-plugin.mjs -index 57cd2b9..2e5eaf1 100755 ---- a/node_modules/@angular/build-tooling/shared-scripts/angular-optimization/esbuild-plugin.mjs -+++ b/node_modules/@angular/build-tooling/shared-scripts/angular-optimization/esbuild-plugin.mjs -@@ -43,9 +43,12 @@ export function createEsbuildAngularOptimizePlugin( - - // If the current file is denoted as explicit side effect free, add the pure - // top-level functions optimization plugin for this file. -- if (isSideEffectFreeFn !== null && isSideEffectFreeFn(args.path)) { -- plugins.push(pureToplevelFunctionsPlugin); -- } -+ // For TensorBoard: This plugin aggressively culls symbols in a way that -+ // is incompatible with TensorBoard source. Remove it. The binary is -+ // bigger than it otherwise could be but the bundle also happens faster. -+ //if (isSideEffectFreeFn !== null && isSideEffectFreeFn(args.path)) { -+ // plugins.push(pureToplevelFunctionsPlugin); -+ //} - - const {code} = await babel.transformAsync(content, { - filename: filePath, diff --git a/patches/@bazel+concatjs+5.7.0.patch b/patches/@bazel+concatjs+5.8.1.patch similarity index 62% rename from patches/@bazel+concatjs+5.7.0.patch rename to patches/@bazel+concatjs+5.8.1.patch index c3228308583..f2fea97ab11 100644 --- a/patches/@bazel+concatjs+5.7.0.patch +++ b/patches/@bazel+concatjs+5.8.1.patch @@ -28,24 +28,17 @@ index fed787a..377915a 100755 return struct( closure_js = closure_js_files, devmode_js = devmode_js_files, -diff --git a/node_modules/@bazel/concatjs/web_test/karma.conf.js b/node_modules/@bazel/concatjs/web_test/karma.conf.js -index 90a03ef..28778c9 100755 ---- a/node_modules/@bazel/concatjs/web_test/karma.conf.js -+++ b/node_modules/@bazel/concatjs/web_test/karma.conf.js -@@ -384,7 +384,15 @@ try { - conf.browsers.push(launcher); - } else { - const launcher = 'CustomChrome'; -- conf.customLaunchers = {[launcher]: {base: browser, flags: additionalArgs}}; -+ // For TensorBoard: Patch the CustomChrome launcher so that even it -+ // specifies the --no-sandbox flag. This is to workaround -+ // incompatibilities with some environments. -+ // -+ // Specifically we were seeing errors like: -+ // [WARNING:gpu_process_host.cc(1228)] The GPU process has crashed 6 time(s) -+ // [FATAL:gpu_data_manager_impl_private.cc(439)] GPU process isn't usable. Goodbye. -+ conf.customLaunchers = -+ {[launcher]: {base: browser, flags: ['--no-sandbox', ...additionalArgs]}}; - conf.browsers.push(launcher); - } - } +diff --git a/node_modules/@bazel/concatjs/package.json b/node_modules/@bazel/concatjs/package.json +index 1234567..abcdefg 100755 +--- a/node_modules/@bazel/concatjs/package.json ++++ b/node_modules/@bazel/concatjs/package.json +@@ -24,7 +24,8 @@ + "dependencies": { + "protobufjs": "6.8.8", + "source-map-support": "0.5.9", +- "tsutils": "3.21.0" ++ "tsutils": "3.21.0", ++ "typescript": "5.2.2" + }, + "peerDependencies": { + "karma": ">=4.0.0", diff --git a/patches/README.md b/patches/README.md index d95fc2391e2..4224fe93fe2 100644 --- a/patches/README.md +++ b/patches/README.md @@ -1,21 +1,88 @@ # TensorBoard patches using patch-package. -We use [patch-package](https://www.npmjs.com/package/patch-package) to apply +We use [patch-package](https://www.npmjs.com/package/patch-package) to author TensorBoard-specific patches to some of our npm/yarn dependencies. +At build time, `WORKSPACE` applies the generated patch artifacts via +`yarn_install(post_install_patches = ...)` instead of invoking +`patch-package` inside the repository rule. In the current Bazel/CI setup, that +install-time invocation was less reliable than applying the generated patch +files directly. + After creating or updating a patch, ensure there is no trailing whitespace on any line (CI runs `./tensorboard/tools/whitespace_hygiene_test.py`). You can strip it with `sed -i '' 's/[[:space:]]*$//' patches/.patch`. -To regenerate @bazel/concatjs patch: -* `vi node_modules/@bazel/concatjs/web_test/karma.conf.js` +## `@bazel+concatjs+5.8.1.patch` + +**Modified files:** +- `node_modules/@bazel/concatjs/internal/common/compilation.bzl` +- `node_modules/@bazel/concatjs/package.json` + +**What it does:** +Updated patch from 5.7.0 to 5.8.1. This version already includes the TypeScript 5.x fix and Chrome sandbox fix that we had to patch manually in 5.7.0. +Added typescript as a direct dependency because the Bazel sandbox can't find it otherwise. + +Why 5.8.1 and not 6.x: rules_nodejs 6.x removed most of the build rules we depend on (concatjs, esbuild, typescript, etc.) and moved them to a separate project (rules_js). This effort will be done in future upgrades. + + +To regenerate: +* `vi node_modules/@bazel/concatjs/internal/common/compilation.bzl` +* `vi node_modules/@bazel/concatjs/package.json` * make edits * `yarn patch-package "@bazel/concatjs"` * update the WORKSPACE file with the name of the new patch file -To regenerate @angular/build-tooling patch: +## `@angular+build-tooling+0.0.0-2113cd7f66a089ac0208ea84eee672b2529f4f6c.patch` + +**Modified files:** +- `node_modules/@angular/build-tooling/shared-scripts/angular-optimization/BUILD.bazel` +- `node_modules/@angular/build-tooling/shared-scripts/angular-optimization/esbuild-plugin.mjs` + +**What it does:** +Updated for the Angular 17 version of build-tooling, adding the missing Babel dependency and +Disables an optimization plugin that incorrectly removes function calls that Tensorboard depends on runtime. + +To regenerate: +* `vi node_modules/@angular/build-tooling/shared-scripts/angular-optimization/BUILD.bazel` * `vi node_modules/@angular/build-tooling/shared-scripts/angular-optimization/esbuild-plugin.mjs` * make edits * `yarn patch-package "@angular/build-tooling"` * update the WORKSPACE file with the name of the new patch file + + +## `protobuf_6_31_1_java_export.patch` + +**Modified files:** +- `build_defs/java_opts.bzl` +- `bazel/private/proto_library_rule.bzl` + +**What it does:** +- Drops the older javadocopts workaround from protobuf's Java export helper on + the current rules_java/protobuf stack. +- Relaxes the import-prefix normalization check so empty-but-normalized values + continue to work under the newer path handling used here. + + +## `rules_cc_protobuf.patch` + +**Modified files:** +- `cc/defs.bzl` + +**What it does:** +- Re-exports `cc_proto_library` from protobuf's Bazel definitions so callers on + this repository can keep loading the symbol through `rules_cc` while using the + protobuf 6.31.1 repository layout. + + +## `rules_closure_soy_cli.patch` + +**Modified files:** +- `closure/templates/closure_java_template_library.bzl` + +**What it does:** +- Updates rules_closure's Soy invocation for the compiler/jar combination used + here. +- Switches to the `--depHeaders` flag expected by this compiler and drops the + older `--allowExternalCalls` flag that is not accepted here. diff --git a/patches/protobuf_6_31_1_java_export.patch b/patches/protobuf_6_31_1_java_export.patch new file mode 100644 index 00000000000..bf0291c5247 --- /dev/null +++ b/patches/protobuf_6_31_1_java_export.patch @@ -0,0 +1,49 @@ +diff --git a/build_defs/java_opts.bzl b/build_defs/java_opts.bzl +--- a/build_defs/java_opts.bzl ++++ b/build_defs/java_opts.bzl +@@ -17,14 +17,5 @@ def protobuf_java_export(**kwargs): + def protobuf_java_export(**kwargs): + java_export( + javacopts = JAVA_RELEASE_OPTS, +- # https://github.com/bazelbuild/rules_jvm_external/issues/1245 +- javadocopts = [ +- "-notimestamp", +- "-use", +- "-quiet", +- "-Xdoclint:-missing", +- "-encoding", +- "UTF8", +- ], + **kwargs + ) +diff --git a/bazel/private/proto_library_rule.bzl b/bazel/private/proto_library_rule.bzl +--- a/bazel/private/proto_library_rule.bzl ++++ b/bazel/private/proto_library_rule.bzl +@@ -29,6 +29,9 @@ def _check_srcs_package(target_package, srcs): + for src in srcs: + if target_package != src.label.package: + fail("Proto source with label '%s' must be in same package as consuming rule." % src.label) ++ ++def _is_normalized(path): ++ return path == "" or paths.normalize(path) == path + + def _get_import_prefix(ctx): + """Gets and verifies import_prefix attribute if it is declared.""" +@@ -36,7 +39,7 @@ def _get_import_prefix(ctx): + + import_prefix = ctx.attr.import_prefix + +- if not paths.is_normalized(import_prefix): ++ if not _is_normalized(import_prefix): + fail("should be normalized (without uplevel references or '.' path segments)", attr = "import_prefix") + if paths.is_absolute(import_prefix): + fail("should be a relative path", attr = "import_prefix") +@@ -48,7 +51,7 @@ def _get_strip_import_prefix(ctx): + + strip_import_prefix = ctx.attr.strip_import_prefix + +- if not paths.is_normalized(strip_import_prefix): ++ if not _is_normalized(strip_import_prefix): + fail("should be normalized (without uplevel references or '.' path segments)", attr = "strip_import_prefix") + + if paths.is_absolute(strip_import_prefix): diff --git a/patches/rules_cc_protobuf.patch b/patches/rules_cc_protobuf.patch new file mode 100644 index 00000000000..944962033d0 --- /dev/null +++ b/patches/rules_cc_protobuf.patch @@ -0,0 +1,16 @@ +diff --git a/cc/defs.bzl b/cc/defs.bzl +index 3448e77..9c298ab 100644 +--- a/cc/defs.bzl ++++ b/cc/defs.bzl +@@ -30,9 +30,11 @@ load("//cc/toolchains:cc_toolchain_suite.bzl", _cc_toolchain_suite = "cc_toolcha + load("//cc/toolchains:compiler_flag.bzl", _compiler_flag = "compiler_flag") + load("//cc/toolchains:fdo_prefetch_hints.bzl", _fdo_prefetch_hints = "fdo_prefetch_hints") + load("//cc/toolchains:fdo_profile.bzl", _fdo_profile = "fdo_profile") ++load("@com_google_protobuf//bazel:cc_proto_library.bzl", _protobuf_cc_proto_library = "cc_proto_library") + + # Rules + ++cc_proto_library = _protobuf_cc_proto_library + cc_library = _cc_library + cc_binary = _cc_binary + cc_test = _cc_test diff --git a/patches/rules_closure_soy_cli.patch b/patches/rules_closure_soy_cli.patch new file mode 100644 index 00000000000..1559d81ef68 --- /dev/null +++ b/patches/rules_closure_soy_cli.patch @@ -0,0 +1,19 @@ +diff --git a/closure/templates/closure_java_template_library.bzl b/closure/templates/closure_java_template_library.bzl +--- a/closure/templates/closure_java_template_library.bzl ++++ b/closure/templates/closure_java_template_library.bzl +@@ -133,7 +133,7 @@ def _soy_java_template_genrule_impl( + out_name = deps_flag_file_name, + targets = deps, +- flag = "--deps", ++ flag = "--depHeaders", + compatible_with = compatible_with, + ) + native.genrule( +@@ -145,7 +145,6 @@ def _soy_java_template_genrule_impl( + cmd = "$(location %s)" % soycompilerbin + + " --outputDirectory=$(@D)" + + " --javaPackage=" + java_package + + " --javaClassNameSource=filename" + +- " --allowExternalCalls=" + str(allow_external_calls) + + additional_flags + + # Include the sources and deps files as command line flags. diff --git a/tensorboard/BUILD b/tensorboard/BUILD index 181314b31a0..a61cc8ed441 100644 --- a/tensorboard/BUILD +++ b/tensorboard/BUILD @@ -45,6 +45,7 @@ py_library( srcs_version = "PY3", deps = [ "//tensorboard:expect_absl_logging_installed", + "//tensorboard/compat", "//tensorboard/compat:tensorflow", ], ) diff --git a/tensorboard/backend/event_processing/BUILD b/tensorboard/backend/event_processing/BUILD index 5444b20c56a..9ff453ffe65 100644 --- a/tensorboard/backend/event_processing/BUILD +++ b/tensorboard/backend/event_processing/BUILD @@ -13,6 +13,7 @@ py_library( srcs_version = "PY3", visibility = ["//visibility:public"], deps = [ + "//tensorboard/compat", "//tensorboard/compat:tensorflow", "//tensorboard/util:io_util", "//tensorboard/util:tb_logging", @@ -38,6 +39,7 @@ py_library( ":data_provider", ":event_multiplexer", ":tag_types", + "//tensorboard/compat", "//tensorboard/compat:tensorflow", "//tensorboard/data:ingester", "//tensorboard/plugins/audio:metadata", @@ -104,6 +106,7 @@ py_library( deps = [ ":directory_watcher", ":io_wrapper", + "//tensorboard/compat", "//tensorboard/compat:tensorflow", "//tensorboard/util:tb_logging", ], @@ -130,6 +133,7 @@ py_library( visibility = ["//visibility:public"], deps = [ ":io_wrapper", + "//tensorboard/compat", "//tensorboard/compat:tensorflow", "//tensorboard/util:io_util", "//tensorboard/util:tb_logging", @@ -172,6 +176,7 @@ py_library( deps = [ "//tensorboard:data_compat", "//tensorboard:dataclass_compat", + "//tensorboard/compat", "//tensorboard/compat:tensorflow", "//tensorboard/compat/proto:protos_all_py_pb2", "//tensorboard/util:platform_util", @@ -354,6 +359,7 @@ py_library( srcs_version = "PY3", visibility = ["//visibility:public"], deps = [ + "//tensorboard/compat", "//tensorboard/compat:tensorflow", ], ) @@ -366,6 +372,7 @@ py_library( deps = [ ":event_accumulator", ":io_wrapper", + "//tensorboard/compat", "//tensorboard/compat:tensorflow", "//tensorboard/compat/proto:protos_all_py_pb2", ], diff --git a/tensorboard/compat/BUILD b/tensorboard/compat/BUILD index e04bc3eb312..38ae4a7d0f8 100644 --- a/tensorboard/compat/BUILD +++ b/tensorboard/compat/BUILD @@ -22,8 +22,16 @@ py_library( srcs = ["__init__.py"], srcs_version = "PY3", visibility = ["//visibility:public"], + deps = ["//tensorboard:lazy"], +) + +py_test( + name = "compat_test", + srcs = ["compat_test.py"], + srcs_version = "PY3", deps = [ - "//tensorboard:lazy", + ":compat", + "//tensorboard:expect_tensorflow_installed", ], ) @@ -38,9 +46,13 @@ py_library( # as written but can be swapped out for a real dependency. py_library( name = "tensorflow", + srcs = ["__init__.py"], srcs_version = "PY3", + # Keep the package's real __init__.py on this target instead of depending + # on :compat so Bazel test/binary runfiles expose the lazy tf/tf2 exports from + # the actual package init rather than a synthesized empty package. deps = [ - ":compat", + "//tensorboard:lazy", "//tensorboard/compat/tensorflow_stub", ], ) @@ -50,10 +62,16 @@ py_library( # Depend on this rule if your code should only use the TF stub. py_library( name = "no_tensorflow", - srcs = ["notf.py"], + srcs = [ + "__init__.py", + "notf.py", + ], srcs_version = "PY3", + # Mirror :tensorflow's package layout so the no-TF variant still exposes + # the compat package exports while forcing the sentinel import. deps = [ - ":tensorflow", + "//tensorboard:lazy", + "//tensorboard/compat/tensorflow_stub", ], ) diff --git a/tensorboard/compat/__init__.py b/tensorboard/compat/__init__.py index 6786669fe2d..aedef948dd3 100644 --- a/tensorboard/compat/__init__.py +++ b/tensorboard/compat/__init__.py @@ -19,6 +19,7 @@ and defer the search and loading of the module until necessary. """ +import importlib import tensorboard.lazy as _lazy @@ -39,7 +40,7 @@ def tf(): ImportError: if a TF-like API is not available. """ try: - from tensorboard.compat import notf # noqa: F401 + importlib.import_module("tensorboard.compat.notf") except ImportError: try: import tensorflow @@ -47,9 +48,7 @@ def tf(): return tensorflow except ImportError: pass - from tensorboard.compat import tensorflow_stub - - return tensorflow_stub + return importlib.import_module("tensorboard.compat.tensorflow_stub") @_lazy.lazy_load("tensorboard.compat.tf2") diff --git a/tensorboard/compat/compat_test.py b/tensorboard/compat/compat_test.py new file mode 100644 index 00000000000..d24bf315096 --- /dev/null +++ b/tensorboard/compat/compat_test.py @@ -0,0 +1,33 @@ +# Copyright 2026 The TensorFlow Authors. All Rights Reserved. +# +# Licensed 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. + +"""Tests for tensorboard.compat lazy exports.""" + +import unittest + + +class CompatTest(unittest.TestCase): + def test_tf_export(self): + from tensorboard.compat import tf + + self.assertTrue(hasattr(tf, "compat")) + + def test_tf2_export(self): + from tensorboard.compat import tf2 + + self.assertTrue(hasattr(tf2, "summary")) + + +if __name__ == "__main__": + unittest.main() diff --git a/tensorboard/data/server/DEVELOPMENT.md b/tensorboard/data/server/DEVELOPMENT.md index 025249abdf8..b28c883aa2e 100644 --- a/tensorboard/data/server/DEVELOPMENT.md +++ b/tensorboard/data/server/DEVELOPMENT.md @@ -150,7 +150,7 @@ When done, commit the changes to `Cargo.toml`, `Cargo.lock`, and the Test datasets are stored on Google Cloud Storage in the world-readable `gs://tensorboard-bench-logs` bucket, whose [bucket README] is online. To run -against this data, use `gsutil` to copy it to your local machine. +against this data, use `gcloud storage` to copy it to your local machine. [bucket README]: https://storage.googleapis.com/tensorboard-bench-logs/README diff --git a/tensorboard/data/server/descriptor.bin b/tensorboard/data/server/descriptor.bin index bd230a39479..a0475fb3e92 100644 Binary files a/tensorboard/data/server/descriptor.bin and b/tensorboard/data/server/descriptor.bin differ diff --git a/tensorboard/data/server/gcs/gsutil.rs b/tensorboard/data/server/gcs/gsutil.rs index 09d609b9fc2..5b741d10f3c 100644 --- a/tensorboard/data/server/gcs/gsutil.rs +++ b/tensorboard/data/server/gcs/gsutil.rs @@ -21,7 +21,7 @@ use std::io::Write; use rustboard_core::gcs; #[derive(Clap, Debug)] -#[clap(name = "gsutil")] +#[clap(name = "gcloud storage")] struct Opts { #[clap(long, default_value = "info")] log_level: String, diff --git a/tensorboard/defs/defs.bzl b/tensorboard/defs/defs.bzl index 3f3ac904f29..745aab34dc5 100644 --- a/tensorboard/defs/defs.bzl +++ b/tensorboard/defs/defs.bzl @@ -14,10 +14,9 @@ """External-only delegates for various BUILD rules.""" load("@bazel_skylib//rules:copy_file.bzl", "copy_file") -load("@io_bazel_rules_sass//:defs.bzl", "npm_sass_library", "sass_binary", "sass_library") +load("@npm//@angular/build-tooling/bazel:extract_js_module_output.bzl", "extract_js_module_output") load("@npm//@angular/build-tooling/bazel/app-bundling:index.bzl", "app_bundle") load("@npm//@angular/build-tooling/bazel/spec-bundling:index.bzl", "spec_bundle") -load("@npm//@angular/build-tooling/bazel:extract_js_module_output.bzl", "extract_js_module_output") load("@npm//@bazel/concatjs:index.bzl", "karma_web_test_suite", "ts_library") load("@npm//@bazel/esbuild:index.bzl", "esbuild") load("@npm//@bazel/typescript:index.bzl", "ts_config") @@ -179,7 +178,8 @@ def tf_ts_library(srcs = [], strict_checks = True, **kwargs): **kwargs ) -def tf_ng_web_test_suite(name, deps = [], **kwargs): +# The external list is used to exclude node-fetch from the browser bundle since it is not compatible with browsers. This allows us to use tfjs in our web application without running into issues caused by node-fetch. @tensorflow/tfjs-core is used by vz_projector plugin. +def tf_ng_web_test_suite(name, deps = [], external = [], **kwargs): """TensorBoard wrapper for the rule for a Karma web test suite. This uses the Angular team's internal toolchain for bundling @@ -218,6 +218,7 @@ def tf_ng_web_test_suite(name, deps = [], **kwargs): workspace_name = "org_tensorflow_tensorboard", run_angular_linker = False, platform = "browser", + external = external, ) karma_web_test_suite( @@ -234,6 +235,10 @@ def tf_ng_web_test_suite(name, deps = [], **kwargs): deps = [ "%s_bundle" % name, ], + # rules_nodejs passes this through to rules_webtesting. An empty dict + # avoids forwarding a stray None-valued attribute to web_test under + # Bazel 7.7.0 with the currently pinned rules_webtesting stack. + browser_overrides = {}, ) def tf_svg_bundle(name, srcs, out): @@ -247,45 +252,6 @@ def tf_svg_bundle(name, srcs, out): ], ) -def tf_sass_binary(deps = [], include_paths = [], strict_deps = True, **kwargs): - """TensorBoard wrap for declaring SASS binary. - - It adds dependency on theme by default then add include Angular material - theme library paths for better node_modules library resolution. - - strict_deps is included here and intentionally ignored so it can be used - internally. - """ - sass_binary( - deps = deps, - include_paths = include_paths + [ - "external/npm/node_modules", - ], - sourcemap = False, - **kwargs - ) - -def tf_sass_library(**kwargs): - """TensorBoard wrap for declaring SASS library. - - It re-exports the sass_libray symbol so users do not have to depend on - "@io_bazel_rules_sass//:defs.bzl". - """ - sass_library( - **kwargs - ) - -def tf_external_sass_libray(**kwargs): - """TensorBoard wrapper for declaring external SASS dependency. - - When an external (NPM) package have SASS files that has `import` statements, - TensorBoard has to depdend on them very specifically. This rule allows SASS - modules in NPM packages to be built properly. - """ - npm_sass_library( - **kwargs - ) - def tf_ng_module(assets = [], **kwargs): """TensorBoard wrapper for Angular modules.""" tf_ts_library( diff --git a/tensorboard/defs/protos.bzl b/tensorboard/defs/protos.bzl index e1dbe485d32..5fd5df99a36 100644 --- a/tensorboard/defs/protos.bzl +++ b/tensorboard/defs/protos.bzl @@ -12,10 +12,10 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("@com_google_protobuf//:protobuf.bzl", "proto_gen") -load("@rules_python//python:py_library.bzl", "py_library") +load("@com_google_protobuf//bazel:py_proto_library.bzl", "py_proto_library") +load("@com_github_grpc_grpc//bazel:protobuf.bzl", "well_known_proto_libs") +load("@com_github_grpc_grpc//bazel:python_rules.bzl", "py_grpc_library") -# TODO(#6185): try to reduce the complexity in this rule. def tb_proto_library( name, srcs = None, @@ -25,66 +25,29 @@ def tb_proto_library( has_services = False, # The `exports` arg is unused here, but required internally for compatibility. exports = []): - outs_proto = _PyOuts(srcs, grpc = False) - outs_grpc = _PyOuts(srcs, grpc = True) if has_services else [] - outs_all = outs_proto + outs_grpc + proto_deps = [s + "_proto" for s in deps] + well_known_proto_libs() - # Dependencies we need to operate protoc (the protobuf compiler), including - # protoc itself, the intermediate generated proto output from the runtime - # bundled with protoc (to provide proto types used during the protoc code - # generation process itself), and the grpc plugin to protoc used for gRPC - # service generation. - protoc = "@com_google_protobuf//:protoc" - protoc_runtime_genproto = "@com_google_protobuf//:protobuf_python_genproto" - grpc_python_plugin = "//external:grpc_python_plugin" - - # Python generated code relies on a Python protobuf runtime to be present. - # The runtime version must be compatible (typically, >=) with the protoc - # that was used to generate the code. There is a runtime provided along - # with protoc as part of our build-time dependency on protobuf (the target - # is "@com_google_protobuf//:protobuf_python"), but we deliberately don't - # use it, because our tests may need to use a protobuf runtime that is - # higher than our protoc version in order to be compatible with generated - # protobuf code used by our dependencies (namely, TensorFlow). Instead, we - # rely on picking up protobuf ambiently from the virtual environment, the - # same way that it will behave when released in our pip package. - runtime = "//tensorboard:expect_protobuf_installed" - - proto_gen( - name = name + "_genproto", + native.proto_library( + name = name + "_proto", srcs = srcs, - deps = [s + "_genproto" for s in deps] + [protoc_runtime_genproto], - includes = [], - protoc = protoc, - gen_py = True, - outs = outs_all, + deps = proto_deps, + testonly = testonly, visibility = ["//visibility:public"], - plugin = grpc_python_plugin if has_services else None, - plugin_language = "grpc", ) - py_deps = [s + "_py_pb2" for s in deps] + [runtime] - py_library( + py_proto_library( name = name + "_py_pb2", - srcs = outs_proto, - imports = [], - srcs_version = "PY3", - deps = py_deps, + deps = [name + "_proto"], testonly = testonly, visibility = visibility, ) + if has_services: - py_library( + py_grpc_library( name = name + "_py_pb2_grpc", - srcs = outs_grpc, - imports = [], - srcs_version = "PY3", - deps = [name + "_py_pb2"] + py_deps, + srcs = [name + "_proto"], + deps = [name + "_py_pb2"], + grpc_library = "//tensorboard:expect_grpc_installed", testonly = testonly, visibility = visibility, ) - -def _PyOuts(srcs, grpc): - # Adapted from @com_google_protobuf//:protobuf.bzl. - ext = "_pb2.py" if not grpc else "_pb2_grpc.py" - return [s[:-len(".proto")] + ext for s in srcs] diff --git a/tensorboard/manager.py b/tensorboard/manager.py index 823735bd477..4d6ec770d0f 100644 --- a/tensorboard/manager.py +++ b/tensorboard/manager.py @@ -32,6 +32,29 @@ from tensorboard.util import tb_logging +_SUBPROCESS_ENV_DENYLIST = frozenset( + ( + "BUILD_WORKING_DIRECTORY", + "BUILD_WORKSPACE_DIRECTORY", + "JAVA_RUNFILES", + "PYTHONHOME", + "PYTHONPATH", + "PYTHONSAFEPATH", + "PYTHONSTARTUP", + "PYTHONUSERBASE", + "PYTHON_RUNFILES", + "RUNFILES", + "RUNFILES_DIR", + "RUNFILES_MANIFEST_FILE", + "RUNFILES_MANIFEST_ONLY", + "RUNFILES_REPO_MAPPING", + "TEST_BINARY", + "TEST_SRCDIR", + "TEST_WORKSPACE", + ) +) + + @dataclasses.dataclass(frozen=True) class TensorBoardInfo: """Holds the information about a running TensorBoard instance. @@ -385,6 +408,20 @@ class StartTimedOut: pid: int +def _subprocess_environ(): + """Create an environment for a managed TensorBoard subprocess. + + TensorBoard processes launched from Bazel tests should resolve their own + runfiles and Python import paths. Inheriting Bazel's test-only Python and + runfiles variables can make the child binary execute against the parent's + runfiles tree instead of its own. + """ + environ = os.environ.copy() + for key in _SUBPROCESS_ENV_DENYLIST: + environ.pop(key, None) + return environ + + def start(arguments, timeout=datetime.timedelta(seconds=60)): """Start a new TensorBoard instance, or reuse a compatible one. @@ -427,6 +464,7 @@ def start(arguments, timeout=datetime.timedelta(seconds=60)): try: p = subprocess.Popen( ["tensorboard" if explicit_tb is None else explicit_tb] + arguments, + env=_subprocess_environ(), stdout=stdout_fd, stderr=stderr_fd, ) diff --git a/tensorboard/manager_test.py b/tensorboard/manager_test.py index 6911398c515..e5659d1cf64 100644 --- a/tensorboard/manager_test.py +++ b/tensorboard/manager_test.py @@ -233,6 +233,30 @@ def test_arguments_list_vs_tuple_irrelevant(self): self.assertEqual(with_list, with_tuple) +class SubprocessEnvironTest(tb_test.TestCase): + def test_strips_bazel_and_python_path_state(self): + with mock.patch.dict( + os.environ, + { + "PATH": "/bin:/usr/bin", + "TMPDIR": "/tmp/tb", + "PYTHONPATH": "/tmp/runfiles", + "RUNFILES_DIR": "/tmp/runfiles", + "TEST_BINARY": "/tmp/test_binary", + "BUILD_WORKSPACE_DIRECTORY": "/tmp/workspace", + }, + clear=True, + ): + actual = manager._subprocess_environ() + + self.assertEqual(actual["PATH"], "/bin:/usr/bin") + self.assertEqual(actual["TMPDIR"], "/tmp/tb") + self.assertNotIn("PYTHONPATH", actual) + self.assertNotIn("RUNFILES_DIR", actual) + self.assertNotIn("TEST_BINARY", actual) + self.assertNotIn("BUILD_WORKSPACE_DIRECTORY", actual) + + class TensorBoardInfoIoTest(tb_test.TestCase): """Tests for `write_info_file`, `remove_info_file`, and `get_all`.""" diff --git a/tensorboard/pip_package/requirements.txt b/tensorboard/pip_package/requirements.txt index ac31021fbb8..7ee4b97b1af 100644 --- a/tensorboard/pip_package/requirements.txt +++ b/tensorboard/pip_package/requirements.txt @@ -17,22 +17,15 @@ absl-py >= 0.4 # NOTE: this version should be >= the grpc version in our WORKSPACE file. -grpcio >= 1.48.2 +grpcio >= 1.74.0, < 2.0 markdown >= 2.6.8 numpy >= 1.12.0 -# NOTE: The packaging dependency was introduced in order to compare installed -# package versions and conditionally use different supported kwargs -# (specifically the protobuf dependency). If we restrict protobuf >= 5.0.0 we -# can get rid of the packaging dependency. packaging pillow # NOTE: this version must be >= the protoc version in our WORKSPACE file. -# At the same time, any constraints we specify here must allow at least some -# version to be installed that is also compatible with TensorFlow's constraints: -# https://github.com/tensorflow/tensorflow/blob/25adc4fccb4b0bb5a933eba1d246380e7b87d7f7/tensorflow/tools/pip_package/setup.py#L101 -# 4.24.0 had an issue that broke our tests, so we should avoid that release: -# https://github.com/protocolbuffers/protobuf/issues/13485 -protobuf >= 3.19.6, != 4.24.0 +# TensorFlow 2.21 requires protobuf >= 6.31.1, < 8.0.0, so keep our open-source +# runtime floor aligned with that range. +protobuf >= 6.31.1, < 8.0.0 setuptools >= 41.0.0 # Note: provides pkg_resources as well as setuptools tensorboard-data-server >= 0.7.0, < 0.8.0 werkzeug >= 1.0.1 diff --git a/tensorboard/pip_package/requirements_dev.txt b/tensorboard/pip_package/requirements_dev.txt index f9a7a3ae702..5b2ea9c4540 100644 --- a/tensorboard/pip_package/requirements_dev.txt +++ b/tensorboard/pip_package/requirements_dev.txt @@ -16,11 +16,11 @@ # Dependencies of TensorBoard used only for testing or development. # For tests -grpcio-testing==1.24.3 +grpcio-testing==1.74.0 pandas~=2.0 # For gfile S3 test -boto3==1.9.86 -moto==1.3.7 +boto3==1.34.162 +moto==4.2.14 # For gfile fsspec test fsspec>=2021.06.0 diff --git a/tensorboard/pip_package/test_pip_package.sh b/tensorboard/pip_package/test_pip_package.sh index 1595bcd8601..a4b1cb097f6 100755 --- a/tensorboard/pip_package/test_pip_package.sh +++ b/tensorboard/pip_package/test_pip_package.sh @@ -194,4 +194,6 @@ test_tf_summary() { printf '%s\n' "${import_from}" "${import_as}" "${import_attr}" | python - } +printf >&2 'All smoke tests passed.' + main "$@" diff --git a/tensorboard/plugins/audio/BUILD b/tensorboard/plugins/audio/BUILD index 8e0d8965ba1..4075740989b 100644 --- a/tensorboard/plugins/audio/BUILD +++ b/tensorboard/plugins/audio/BUILD @@ -92,6 +92,7 @@ py_library( deps = [ ":metadata", "//tensorboard/compat", + "//tensorboard/compat:tensorflow", "//tensorboard/util:lazy_tensor_creator", ], ) diff --git a/tensorboard/plugins/custom_scalar/BUILD b/tensorboard/plugins/custom_scalar/BUILD index 83b59203ff7..795d5c5fc18 100644 --- a/tensorboard/plugins/custom_scalar/BUILD +++ b/tensorboard/plugins/custom_scalar/BUILD @@ -20,6 +20,7 @@ py_library( "//tensorboard:expect_protobuf_installed", "//tensorboard:plugin_util", "//tensorboard/backend:http_util", + "//tensorboard/compat", "//tensorboard/compat:tensorflow", "//tensorboard/plugins:base_plugin", "//tensorboard/plugins/scalar:metadata", diff --git a/tensorboard/plugins/debugger_v2/debugger_v2_plugin_test.py b/tensorboard/plugins/debugger_v2/debugger_v2_plugin_test.py index ae300001384..115abfec4bc 100644 --- a/tensorboard/plugins/debugger_v2/debugger_v2_plugin_test.py +++ b/tensorboard/plugins/debugger_v2/debugger_v2_plugin_test.py @@ -1494,7 +1494,7 @@ def testServeSourceFileContentOfThisTestFile(self): data = json.loads(response.get_data()) self.assertEqual(data["host_name"], _HOST_NAME) self.assertEqual(data["file_path"], _CURRENT_FILE_FULL_PATH) - with open(__file__, "r") as f: + with open(__file__, "r", newline="") as f: lines = f.read().split("\n") self.assertEqual(data["lines"], lines) diff --git a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/BUILD b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/BUILD index b849cc35c73..7f21c22cec5 100644 --- a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/BUILD +++ b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/BUILD @@ -1,13 +1,15 @@ -load("//tensorboard/defs:defs.bzl", "tf_ng_module", "tf_ng_web_test_suite", "tf_sass_binary", "tf_ts_library") +load("@io_bazel_rules_sass//:defs.bzl", "sass_binary") load("@rules_python//python:py_binary.bzl", "py_binary") +load("//tensorboard/defs:defs.bzl", "tf_ng_module", "tf_ng_web_test_suite", "tf_ts_library") package(default_visibility = ["//tensorboard:internal"]) licenses(["notice"]) -tf_sass_binary( +sass_binary( name = "debugger_component_style", src = "debugger_component.scss", + include_paths = ["external/npm/node_modules"], deps = ["//tensorboard/webapp/theme"], ) diff --git a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/debugger_container.ts b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/debugger_container.ts index 6519ca9bc28..ee11d252cd1 100644 --- a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/debugger_container.ts +++ b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/debugger_container.ts @@ -12,13 +12,19 @@ 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 {Component, OnDestroy, OnInit} from '@angular/core'; +import { + ChangeDetectionStrategy, + Component, + OnDestroy, + OnInit, +} from '@angular/core'; import {createSelector, select, Store} from '@ngrx/store'; import {debuggerLoaded, debuggerUnloaded} from './actions'; import {getActiveRunId, getDebuggerRunListing} from './store'; import {State} from './store/debugger_types'; @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'tf-debugger-v2', template: ` diff --git a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/effects/debugger_effects_test.ts b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/effects/debugger_effects_test.ts index 41d84d4e234..a91fc05b0e4 100644 --- a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/effects/debugger_effects_test.ts +++ b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/effects/debugger_effects_test.ts @@ -401,9 +401,12 @@ describe('Debugger effects', () => { }).compileComponents(); store = TestBed.inject>(Store) as MockStore; - dispatchSpy = spyOn(store, 'dispatch').and.callFake((action: Action) => { - dispatchedActions.push(action); - }); + // Cast to jasmine.Spy for compatibility between NgRx dispatch signature overloads. + dispatchSpy = (spyOn(store, 'dispatch') as jasmine.Spy).and.callFake( + (action: Action) => { + dispatchedActions.push(action); + } + ); store.overrideSelector(getActivePlugin, ''); }); @@ -436,6 +439,7 @@ describe('Debugger effects', () => { begin: number, end: number, alertsResponse: AlertsResponse, + // tslint:disable-next-line:enforce-name-casing alert_type?: string ) { if (alert_type === undefined) { @@ -1403,6 +1407,7 @@ describe('Debugger effects', () => { }, begin: 0, end: 2, + // tslint:disable-next-line:enforce-name-casing alert_type: AlertType.INF_NAN_ALERT, per_type_alert_limit: 1000, alerts: [alert0, alert1], @@ -1657,7 +1662,9 @@ describe('Debugger effects', () => { .withArgs(runId, fileIndex) .and.returnValue( of({ + // tslint:disable-next-line:enforce-name-casing host_name: hostName, + // tslint:disable-next-line:enforce-name-casing file_path: filePath, lines, }) diff --git a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/testing/index.ts b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/testing/index.ts index 700a92c286e..9455e8ab5fc 100644 --- a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/testing/index.ts +++ b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/testing/index.ts @@ -13,7 +13,7 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -import {Component, NgModule} from '@angular/core'; +import {ChangeDetectionStrategy, Component, NgModule} from '@angular/core'; import {Store} from '@ngrx/store'; import { createInitialExecutionsState, @@ -354,6 +354,7 @@ export function createState( // that use it. @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'tf-debugger-v2', template: ``, diff --git a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/alerts/alerts_component.ts b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/alerts/alerts_component.ts index a2054c410fa..c4af4398b59 100644 --- a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/alerts/alerts_component.ts +++ b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/alerts/alerts_component.ts @@ -12,7 +12,13 @@ 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 {Component, EventEmitter, Input, Output} from '@angular/core'; +import { + ChangeDetectionStrategy, + Component, + EventEmitter, + Input, + Output, +} from '@angular/core'; import {AlertType} from '../../store/debugger_types'; export interface AlertTypeDisplay { @@ -23,6 +29,7 @@ export interface AlertTypeDisplay { } @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'alerts-component', templateUrl: './alerts_component.ng.html', diff --git a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/common/BUILD b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/common/BUILD index 9cdf2085484..912022e2f91 100644 --- a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/common/BUILD +++ b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/common/BUILD @@ -1,11 +1,11 @@ -load("//tensorboard/defs:defs.bzl", "tf_sass_library") +load("@io_bazel_rules_sass//:defs.bzl", "sass_library") package(default_visibility = ["//tensorboard:internal"]) licenses(["notice"]) -tf_sass_library( +sass_library( name = "style_lib", srcs = ["_lib.scss"], - deps = ["//tensorboard/webapp:angular_material_sass_deps"], + deps = ["//tensorboard/webapp/angular_components:material_sass"], ) diff --git a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/debug_tensor_value/debug_tensor_value_component.ts b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/debug_tensor_value/debug_tensor_value_component.ts index 21455d1196d..b0e86b71c8e 100644 --- a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/debug_tensor_value/debug_tensor_value_component.ts +++ b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/debug_tensor_value/debug_tensor_value_component.ts @@ -12,7 +12,7 @@ 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 {Component, Input} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input} from '@angular/core'; import {DebugTensorValue} from '../../store/debugger_types'; const basicDebugInfoStyle = ` @@ -30,6 +30,7 @@ const basicDebugInfoStyle = ` `; @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'debug-tensor-dtype', template: ` {{ dtype }} `, @@ -41,6 +42,7 @@ export class DebugTensorDTypeComponent { } @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'debug-tensor-rank', template: ` {{ rank }}D `, @@ -52,6 +54,7 @@ export class DebugTensorRankComponent { } @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'debug-tensor-shape', template: ` shape:{{ shapeString }} `, @@ -75,6 +78,7 @@ export class DebugTensorShapeComponent { } @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'debug-tensor-numeric-breakdown', template: ` @@ -209,6 +213,7 @@ export class DebugTensorNumericBreakdownComponent { } @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'debug-tensor-has-inf-or-nan', template: ` @@ -247,6 +252,7 @@ export class DebugTensorHasInfOrNaNComponent { } @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'debug-tensor-value', template: ` diff --git a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/execution_data/BUILD b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/execution_data/BUILD index 1eceb24a18c..900375c08b0 100644 --- a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/execution_data/BUILD +++ b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/execution_data/BUILD @@ -1,14 +1,16 @@ -load("//tensorboard/defs:defs.bzl", "tf_ng_module", "tf_sass_binary", "tf_ts_library") +load("@io_bazel_rules_sass//:defs.bzl", "sass_binary") +load("//tensorboard/defs:defs.bzl", "tf_ng_module", "tf_ts_library") package(default_visibility = ["//tensorboard:internal"]) licenses(["notice"]) -tf_sass_binary( +sass_binary( name = "execution_data_styles", src = "execution_data_component.scss", + include_paths = ["external/npm/node_modules"], deps = [ - "//tensorboard/webapp:angular_material_sass_deps", + "//tensorboard/webapp/angular_components:material_sass", "//tensorboard/webapp/theme", ], ) diff --git a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/execution_data/execution_data_component.ts b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/execution_data/execution_data_component.ts index 5ac2f424096..a9cfa2b9202 100644 --- a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/execution_data/execution_data_component.ts +++ b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/execution_data/execution_data_component.ts @@ -12,11 +12,12 @@ 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 {Component, Input} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input} from '@angular/core'; import {Execution, TensorDebugMode} from '../../store/debugger_types'; import {parseDebugTensorValue} from '../../store/debug_tensor_value'; @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'execution-data-component', templateUrl: './execution_data_component.ng.html', diff --git a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/execution_data/execution_data_container.ts b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/execution_data/execution_data_container.ts index c53c8586ffa..c8db0d280be 100644 --- a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/execution_data/execution_data_container.ts +++ b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/execution_data/execution_data_container.ts @@ -12,7 +12,7 @@ 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 {Component, Input} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input} from '@angular/core'; import {createSelector, select, Store} from '@ngrx/store'; import {getFocusedExecutionData} from '../../store'; import {Execution, State, TensorDebugMode} from '../../store/debugger_types'; @@ -21,6 +21,7 @@ import {DTYPE_ENUM_TO_NAME} from '../../tf_dtypes'; const UNKNOWN_DTYPE_NAME = 'Unknown dtype'; @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'tf-debugger-v2-execution-data', template: ` diff --git a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/graph/BUILD b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/graph/BUILD index 5305d0a0334..6a5b5004db6 100644 --- a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/graph/BUILD +++ b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/graph/BUILD @@ -1,24 +1,27 @@ -load("//tensorboard/defs:defs.bzl", "tf_ng_module", "tf_sass_binary", "tf_ts_library") +load("@io_bazel_rules_sass//:defs.bzl", "sass_binary") +load("//tensorboard/defs:defs.bzl", "tf_ng_module", "tf_ts_library") package(default_visibility = ["//tensorboard:internal"]) licenses(["notice"]) -tf_sass_binary( +sass_binary( name = "graph_styles", src = "graph_component.scss", + include_paths = ["external/npm/node_modules"], deps = [ "//tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/common:style_lib", "//tensorboard/webapp/theme", ], ) -tf_sass_binary( +sass_binary( name = "graph_op_styles", src = "graph_op_component.scss", + include_paths = ["external/npm/node_modules"], deps = [ "//tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/common:style_lib", - "//tensorboard/webapp:angular_material_sass_deps", + "//tensorboard/webapp/angular_components:material_sass", "//tensorboard/webapp/theme", ], ) diff --git a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/graph/graph_container.ts b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/graph/graph_container.ts index 82e929758e3..e080c8e28b8 100644 --- a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/graph/graph_container.ts +++ b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/graph/graph_container.ts @@ -12,7 +12,7 @@ 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 {Component} from '@angular/core'; +import {ChangeDetectionStrategy, Component} from '@angular/core'; import {select, Store} from '@ngrx/store'; import {graphOpFocused} from '../../actions'; import { @@ -23,6 +23,7 @@ import { import {State} from '../../store/debugger_types'; @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'tf-debugger-v2-graph', template: ` diff --git a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/graph/graph_op_component.ts b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/graph/graph_op_component.ts index b7e5c0a9f12..beafbe22d97 100644 --- a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/graph/graph_op_component.ts +++ b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/graph/graph_op_component.ts @@ -13,10 +13,17 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -import {Component, EventEmitter, Input, Output} from '@angular/core'; +import { + ChangeDetectionStrategy, + Component, + EventEmitter, + Input, + Output, +} from '@angular/core'; import {GraphOpInfo} from '../../store/debugger_types'; @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'graph-op', templateUrl: 'graph_op_component.ng.html', diff --git a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/graph_executions/BUILD b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/graph_executions/BUILD index f4b85ab1653..47e77627a85 100644 --- a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/graph_executions/BUILD +++ b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/graph_executions/BUILD @@ -1,12 +1,14 @@ -load("//tensorboard/defs:defs.bzl", "tf_ng_module", "tf_sass_binary", "tf_ts_library") +load("@io_bazel_rules_sass//:defs.bzl", "sass_binary") +load("//tensorboard/defs:defs.bzl", "tf_ng_module", "tf_ts_library") package(default_visibility = ["//tensorboard:internal"]) licenses(["notice"]) -tf_sass_binary( +sass_binary( name = "graph_executions_styles", src = "graph_executions_component.scss", + include_paths = ["external/npm/node_modules"], deps = [ "//tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/common:style_lib", "//tensorboard/webapp/theme", diff --git a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/graph_executions/graph_executions_container.ts b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/graph_executions/graph_executions_container.ts index b2d1e0c3490..eaaeae3704c 100644 --- a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/graph_executions/graph_executions_container.ts +++ b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/graph_executions/graph_executions_container.ts @@ -12,7 +12,7 @@ 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 {Component} from '@angular/core'; +import {ChangeDetectionStrategy, Component} from '@angular/core'; import {createSelector, select, Store} from '@ngrx/store'; import { graphExecutionFocused, @@ -27,6 +27,7 @@ import { import {State} from '../../store/debugger_types'; @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'tf-debugger-v2-graph-executions', template: ` diff --git a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/inactive/inactive_component.ts b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/inactive/inactive_component.ts index a45c209ec57..e69eb6ccf47 100644 --- a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/inactive/inactive_component.ts +++ b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/inactive/inactive_component.ts @@ -12,9 +12,10 @@ 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 {Component} from '@angular/core'; +import {ChangeDetectionStrategy, Component} from '@angular/core'; @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'inactive-component', templateUrl: './inactive_component.ng.html', diff --git a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/inactive/inactive_container.ts b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/inactive/inactive_container.ts index 455190f0c61..f55dfe4e7a3 100644 --- a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/inactive/inactive_container.ts +++ b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/inactive/inactive_container.ts @@ -12,13 +12,14 @@ 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 {Component} from '@angular/core'; +import {ChangeDetectionStrategy, Component} from '@angular/core'; import {Store} from '@ngrx/store'; // TODO(cais): Move to a separate file. export interface InactiveState {} @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'tf-debugger-v2-inactive', template: ` `, diff --git a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/source_files/BUILD b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/source_files/BUILD index 8c0ce03dd94..521eaf1028f 100644 --- a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/source_files/BUILD +++ b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/source_files/BUILD @@ -1,12 +1,14 @@ -load("//tensorboard/defs:defs.bzl", "tf_ng_module", "tf_sass_binary", "tf_ts_library") +load("@io_bazel_rules_sass//:defs.bzl", "sass_binary") +load("//tensorboard/defs:defs.bzl", "tf_ng_module", "tf_ts_library") package(default_visibility = ["//tensorboard:internal"]) licenses(["notice"]) -tf_sass_binary( +sass_binary( name = "source_files_component_style", src = "source_files_component.scss", + include_paths = ["external/npm/node_modules"], deps = ["//tensorboard/webapp/theme"], ) diff --git a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/source_files/source_files_component.ts b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/source_files/source_files_component.ts index 4dda714fc28..1e7e87a518f 100644 --- a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/source_files/source_files_component.ts +++ b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/source_files/source_files_component.ts @@ -12,7 +12,7 @@ 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 {Component, Input} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input} from '@angular/core'; import {SourceFileContent, StackFrame} from '../../store/debugger_types'; /** @@ -24,6 +24,7 @@ import {SourceFileContent, StackFrame} from '../../store/debugger_types'; * displayed by this component. */ @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'source-files-component', templateUrl: './source_files_component.ng.html', diff --git a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/source_files/source_files_container.ts b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/source_files/source_files_container.ts index dd9e2089d4d..ce7b5d779c4 100644 --- a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/source_files/source_files_container.ts +++ b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/source_files/source_files_container.ts @@ -12,7 +12,7 @@ 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 {Component} from '@angular/core'; +import {ChangeDetectionStrategy, Component} from '@angular/core'; import {Store} from '@ngrx/store'; import {Observable} from 'rxjs'; import {State as OtherAppState} from '../../../../../webapp/app_state'; @@ -24,6 +24,7 @@ import { import {State as DebuggerState} from '../../store/debugger_types'; @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'tf-debugger-v2-source-files', template: ` diff --git a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/stack_trace/BUILD b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/stack_trace/BUILD index f755476ccfe..4a427994aa0 100644 --- a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/stack_trace/BUILD +++ b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/stack_trace/BUILD @@ -1,12 +1,14 @@ -load("//tensorboard/defs:defs.bzl", "tf_ng_module", "tf_sass_binary", "tf_ts_library") +load("@io_bazel_rules_sass//:defs.bzl", "sass_binary") +load("//tensorboard/defs:defs.bzl", "tf_ng_module", "tf_ts_library") package(default_visibility = ["//tensorboard:internal"]) licenses(["notice"]) -tf_sass_binary( +sass_binary( name = "stack_trace_styles", src = "stack_trace_component.scss", + include_paths = ["external/npm/node_modules"], deps = [ "//tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/common:style_lib", "//tensorboard/webapp/theme", diff --git a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/stack_trace/stack_trace_component.ts b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/stack_trace/stack_trace_component.ts index ca274d93bf2..01cf833b715 100644 --- a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/stack_trace/stack_trace_component.ts +++ b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/stack_trace/stack_trace_component.ts @@ -14,6 +14,7 @@ limitations under the License. ==============================================================================*/ import { AfterViewChecked, + ChangeDetectionStrategy, Component, ElementRef, EventEmitter, @@ -40,6 +41,7 @@ export interface StackFrameForDisplay { } @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'stack-trace-component', templateUrl: './stack_trace_component.ng.html', diff --git a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/stack_trace/stack_trace_container.ts b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/stack_trace/stack_trace_container.ts index e35802566fb..546affeb693 100644 --- a/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/stack_trace/stack_trace_container.ts +++ b/tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/views/stack_trace/stack_trace_container.ts @@ -12,7 +12,7 @@ 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 {Component} from '@angular/core'; +import {ChangeDetectionStrategy, Component} from '@angular/core'; import {createSelector, select, Store} from '@ngrx/store'; import {sourceLineFocused} from '../../actions'; import { @@ -25,6 +25,7 @@ import {CodeLocationType, State} from '../../store/debugger_types'; import {StackFrameForDisplay} from './stack_trace_component'; @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'tf-debugger-v2-stack-trace', template: ` diff --git a/tensorboard/plugins/histogram/BUILD b/tensorboard/plugins/histogram/BUILD index 77fa2d1f0f8..413d3aaf939 100644 --- a/tensorboard/plugins/histogram/BUILD +++ b/tensorboard/plugins/histogram/BUILD @@ -107,6 +107,7 @@ py_library( ":metadata", "//tensorboard:expect_numpy_installed", "//tensorboard/compat", + "//tensorboard/compat:tensorflow", "//tensorboard/compat/proto:protos_all_py_pb2", "//tensorboard/util:lazy_tensor_creator", "//tensorboard/util:tensor_util", diff --git a/tensorboard/plugins/hparams/BUILD b/tensorboard/plugins/hparams/BUILD index 74667a28195..51d5155b500 100644 --- a/tensorboard/plugins/hparams/BUILD +++ b/tensorboard/plugins/hparams/BUILD @@ -251,6 +251,7 @@ py_library( ":protos_all_py_pb2", "//tensorboard:expect_numpy_installed", "//tensorboard/compat", + "//tensorboard/compat:tensorflow", "//tensorboard/compat/proto:protos_all_py_pb2", ], ) diff --git a/tensorboard/plugins/image/BUILD b/tensorboard/plugins/image/BUILD index b32e02d2a3d..3ba85ff1d21 100644 --- a/tensorboard/plugins/image/BUILD +++ b/tensorboard/plugins/image/BUILD @@ -103,6 +103,7 @@ py_library( deps = [ ":metadata", "//tensorboard/compat", + "//tensorboard/compat:tensorflow", "//tensorboard/compat/proto:protos_all_py_pb2", "//tensorboard/util:lazy_tensor_creator", ], diff --git a/tensorboard/plugins/mesh/BUILD b/tensorboard/plugins/mesh/BUILD index 14cc2d6459a..54e7796c311 100644 --- a/tensorboard/plugins/mesh/BUILD +++ b/tensorboard/plugins/mesh/BUILD @@ -108,6 +108,7 @@ py_library( srcs_version = "PY3", deps = [ ":metadata", + "//tensorboard/compat", "//tensorboard/compat:tensorflow", "//tensorboard/compat/proto:protos_all_py_pb2", "//tensorboard/util:tensor_util", @@ -151,6 +152,7 @@ py_library( srcs_version = "PY3", deps = [ "//tensorboard:expect_numpy_installed", + "//tensorboard/compat", "//tensorboard/compat:tensorflow", ], ) diff --git a/tensorboard/plugins/projector/BUILD b/tensorboard/plugins/projector/BUILD index 628c344cfd9..5a52c36de02 100644 --- a/tensorboard/plugins/projector/BUILD +++ b/tensorboard/plugins/projector/BUILD @@ -24,6 +24,7 @@ py_library( "//tensorboard:expect_protobuf_installed", "//tensorboard/backend:http_util", "//tensorboard/backend/event_processing:plugin_asset_util", + "//tensorboard/compat", "//tensorboard/compat:tensorflow", "//tensorboard/plugins:base_plugin", "//tensorboard/util:img_mime_type_detector", @@ -41,6 +42,7 @@ py_library( ":metadata", ":protos_all_py_pb2", "//tensorboard:expect_protobuf_installed", + "//tensorboard/compat", "//tensorboard/compat:tensorflow", ], ) diff --git a/tensorboard/plugins/projector/projector_plugin.py b/tensorboard/plugins/projector/projector_plugin.py index 90bf78af1fc..d0371bd6703 100644 --- a/tensorboard/plugins/projector/projector_plugin.py +++ b/tensorboard/plugins/projector/projector_plugin.py @@ -210,10 +210,23 @@ def _parse_positive_int_param(request, param_name): def _rel_to_abs_asset_path(fpath, config_fpath): - fpath = os.path.expanduser(fpath) - if not os.path.isabs(fpath): - return os.path.join(os.path.dirname(config_fpath), fpath) - return fpath + config_dir = os.path.realpath( + os.path.dirname(os.path.expanduser(config_fpath)) + ) + candidate = os.path.expanduser(fpath) + if not os.path.isabs(candidate): + candidate = os.path.join(config_dir, candidate) + candidate = os.path.realpath(candidate) + error_message = 'Asset path "%s" resolves outside the config directory' % ( + fpath + ) + try: + common_path = os.path.commonpath([config_dir, candidate]) + except ValueError as e: + raise ValueError(error_message) from e + if common_path != config_dir: + raise ValueError(error_message) + return candidate def _using_tf(): @@ -363,9 +376,18 @@ def _augment_configs_with_checkpoint_info(self): embedding.tensor_name = embedding.tensor_name[:-2] # Find the size of embeddings associated with a tensors file. if embedding.tensor_path: - fpath = _rel_to_abs_asset_path( - embedding.tensor_path, self.config_fpaths[run] - ) + try: + fpath = _rel_to_abs_asset_path( + embedding.tensor_path, self.config_fpaths[run] + ) + except ValueError as e: + logger.warning( + 'Skipping tensor path "%s" for run "%s": %s', + embedding.tensor_path, + run, + e, + ) + continue tensor = self.tensor_cache.get((run, embedding.tensor_name)) if tensor is None: try: @@ -594,7 +616,10 @@ def _serve_metadata(self, request): "text/plain", 400, ) - fpath = _rel_to_abs_asset_path(fpath, self.config_fpaths[run]) + try: + fpath = _rel_to_abs_asset_path(fpath, self.config_fpaths[run]) + except ValueError as e: + return Respond(request, str(e), "text/plain", 400) if not tf.io.gfile.exists(fpath) or tf.io.gfile.isdir(fpath): return Respond( request, @@ -651,9 +676,12 @@ def _serve_tensor(self, request): embedding = self._get_embedding(name, config) if embedding and embedding.tensor_path: - fpath = _rel_to_abs_asset_path( - embedding.tensor_path, self.config_fpaths[run] - ) + try: + fpath = _rel_to_abs_asset_path( + embedding.tensor_path, self.config_fpaths[run] + ) + except ValueError as e: + return Respond(request, str(e), "text/plain", 400) if not tf.io.gfile.exists(fpath): return Respond( request, @@ -720,7 +748,10 @@ def _serve_bookmarks(self, request): "text/plain", 400, ) - fpath = _rel_to_abs_asset_path(fpath, self.config_fpaths[run]) + try: + fpath = _rel_to_abs_asset_path(fpath, self.config_fpaths[run]) + except ValueError as e: + return Respond(request, str(e), "text/plain", 400) if not tf.io.gfile.exists(fpath) or tf.io.gfile.isdir(fpath): return Respond( request, @@ -766,7 +797,10 @@ def _serve_sprite_image(self, request): ) fpath = os.path.expanduser(embedding_info.sprite.image_path) - fpath = _rel_to_abs_asset_path(fpath, self.config_fpaths[run]) + try: + fpath = _rel_to_abs_asset_path(fpath, self.config_fpaths[run]) + except ValueError as e: + return Respond(request, str(e), "text/plain", 400) if not tf.io.gfile.exists(fpath) or tf.io.gfile.isdir(fpath): return Respond( request, diff --git a/tensorboard/plugins/projector/projector_plugin_test.py b/tensorboard/plugins/projector/projector_plugin_test.py index 64dd5814517..e7f9df9bf3b 100644 --- a/tensorboard/plugins/projector/projector_plugin_test.py +++ b/tensorboard/plugins/projector/projector_plugin_test.py @@ -55,7 +55,11 @@ def __init__(self, *args, **kwargs): self.server = None def setUp(self): - self.log_dir = self.get_temp_dir() + self.test_dir = self.get_temp_dir() + self.log_dir = os.path.join(self.test_dir, "log_dir") + self.restricted_dir = os.path.join(self.test_dir, "restricted_dir") + tf.io.gfile.makedirs(self.log_dir) + tf.io.gfile.makedirs(self.restricted_dir) def testRunsWithValidCheckpoint(self): self._GenerateProjectorTestData() @@ -197,6 +201,93 @@ def testBookmarks(self): bookmark = self._GetJson(url) self.assertEqual(bookmark, {"a": "b"}) + def testMetadataServesRelativeFileWithinLogdir(self): + self._GenerateProjectorAssetsTestData(metadata_path="metadata.tsv") + self._WriteTextFile( + os.path.join(self.log_dir, "metadata.tsv"), "label\nvalue\n" + ) + self._SetupWSGIApp() + + response = self._Get( + "/data/plugin/projector/metadata?run=.&name=embedding" + ) + self.assertEqual(response.status_code, 200) + self.assertEqual(response.data, b"label\nvalue\n") + + def testMetadataRejectsTraversalOutsideLogdir(self): + outside_metadata_path = os.path.join( + self.restricted_dir, "outside_metadata.tsv" + ) + traversal_path = "../restricted_dir/outside_metadata.tsv" + self._WriteTextFile(outside_metadata_path, "secret\n") + self._GenerateProjectorAssetsTestData(metadata_path=traversal_path) + self._SetupWSGIApp() + + response = self._Get( + "/data/plugin/projector/metadata?run=.&name=embedding" + ) + self._AssertOutsideConfigDirResponse(response) + + def testMetadataRejectsSymlinkOutsideLogdir(self): + outside_metadata_path = os.path.join( + self.restricted_dir, "outside_metadata.tsv" + ) + symlink_path = os.path.join(self.log_dir, "metadata-link.tsv") + self._WriteTextFile(outside_metadata_path, "secret\n") + try: + os.symlink(outside_metadata_path, symlink_path) + except (AttributeError, NotImplementedError, OSError) as e: + self.skipTest("symlinks unavailable: %s" % e) + self._GenerateProjectorAssetsTestData(metadata_path="metadata-link.tsv") + self._SetupWSGIApp() + + response = self._Get( + "/data/plugin/projector/metadata?run=.&name=embedding" + ) + self._AssertOutsideConfigDirResponse(response) + + def testTensorRejectsAbsolutePathOutsideLogdir(self): + outside_tensor_path = os.path.join( + self.restricted_dir, "outside_tensor.tsv" + ) + self._WriteTextFile(outside_tensor_path, "1.0\t2.0\n") + self._GenerateProjectorAssetsTestData(tensor_path=outside_tensor_path) + self._SetupWSGIApp() + + response = self._Get( + "/data/plugin/projector/tensor?run=.&name=embedding" + ) + self._AssertOutsideConfigDirResponse(response) + + def testBookmarksRejectAbsolutePathOutsideLogdir(self): + outside_bookmarks_path = os.path.join( + self.restricted_dir, "outside_bookmarks.json" + ) + self._WriteTextFile(outside_bookmarks_path, '{"label": "secret"}') + self._GenerateProjectorAssetsTestData( + bookmarks_path=outside_bookmarks_path + ) + self._SetupWSGIApp() + + response = self._Get( + "/data/plugin/projector/bookmarks?run=.&name=embedding" + ) + self._AssertOutsideConfigDirResponse(response) + + def testSpriteImageRejectsTraversalOutsideLogdir(self): + outside_sprite_path = os.path.join( + self.restricted_dir, "outside_sprite.png" + ) + traversal_path = "../restricted_dir/outside_sprite.png" + self._WriteTextFile(outside_sprite_path, "not-an-image") + self._GenerateProjectorAssetsTestData(sprite_image_path=traversal_path) + self._SetupWSGIApp() + + response = self._Get( + "/data/plugin/projector/sprite_image?run=.&name=embedding" + ) + self._AssertOutsideConfigDirResponse(response) + def testEndpointsNoAssets(self): g = tf.Graph() @@ -213,6 +304,10 @@ def _AssertTensorResponse(self, tensor_bytes, expected_tensor): ) self.assertTrue(np.array_equal(tensor, expected_tensor)) + def _AssertOutsideConfigDirResponse(self, response): + self.assertEqual(response.status_code, 400) + self.assertIn(b"resolves outside the config directory", response.data) + # TODO(#2007): Cleanly separate out projector tests that require real TF @unittest.skipUnless(USING_REAL_TF, "Test only passes when using real TF") def testPluginIsActive(self): @@ -336,6 +431,44 @@ def _GenerateProjectorTestData(self): ) saver.save(sess, checkpoint_path) + def _GenerateProjectorAssetsTestData( + self, + tensor_path="tensor.tsv", + metadata_path=None, + bookmarks_path=None, + sprite_image_path=None, + ): + self._WriteTextFile(self._ResolveAssetPath(tensor_path), "1.0\t2.0\n") + + config = projector_config_pb2.ProjectorConfig() + embedding = config.embeddings.add() + embedding.tensor_name = "embedding" + embedding.tensor_path = tensor_path + if metadata_path is not None: + embedding.metadata_path = metadata_path + if bookmarks_path is not None: + embedding.bookmarks_path = bookmarks_path + if sprite_image_path is not None: + embedding.sprite.image_path = sprite_image_path + + with tf.io.gfile.GFile( + os.path.join(self.log_dir, "projector_config.pbtxt"), "w" + ) as f: + f.write(text_format.MessageToString(config)) + + def _ResolveAssetPath(self, path): + path = os.path.expanduser(path) + if os.path.isabs(path): + return os.path.realpath(path) + return os.path.realpath(os.path.join(self.log_dir, path)) + + def _WriteTextFile(self, path, contents): + parent = os.path.dirname(path) + if parent: + tf.io.gfile.makedirs(parent) + with tf.io.gfile.GFile(path, "w") as f: + f.write(contents) + class MetadataColumnsTest(tf.test.TestCase): def testLengthDoesNotMatch(self): diff --git a/tensorboard/plugins/projector/vz_projector/BUILD b/tensorboard/plugins/projector/vz_projector/BUILD index 7d9777cb090..befb0e27be0 100644 --- a/tensorboard/plugins/projector/vz_projector/BUILD +++ b/tensorboard/plugins/projector/vz_projector/BUILD @@ -140,6 +140,20 @@ tf_ts_library( tf_ng_web_test_suite( name = "vz_projector_test", + # This vz_projector plugin depends on @tensorflow/tfjs library. + # tfjs is designed to run in the browser and in Node.js server, so it includes node-fetch for the Node.js side. + # When esbuild bundles everything for the browser, it tries to include node-fetch and fails because it can't resolve Node.js built-ins. The external list just tells esbuild to ignore those server only packages since they'll never be used in the browser. + external = [ + "node-fetch", + "stream", + "http", + "https", + "url", + "zlib", + "buffer", + "punycode", + "string_decoder", + ], deps = [ ":vz_projector_test_lib", ], diff --git a/tensorboard/plugins/scalar/BUILD b/tensorboard/plugins/scalar/BUILD index 6a6d044f4e5..fd5c3cea12e 100644 --- a/tensorboard/plugins/scalar/BUILD +++ b/tensorboard/plugins/scalar/BUILD @@ -111,6 +111,7 @@ py_library( deps = [ ":metadata", "//tensorboard/compat", + "//tensorboard/compat:tensorflow", "//tensorboard/compat/proto:protos_all_py_pb2", "//tensorboard/util:tensor_util", ], diff --git a/tensorboard/plugins/text/BUILD b/tensorboard/plugins/text/BUILD index b7aa4bedc8f..15ecdeb24ee 100644 --- a/tensorboard/plugins/text/BUILD +++ b/tensorboard/plugins/text/BUILD @@ -101,6 +101,7 @@ py_library( deps = [ ":metadata", "//tensorboard/compat", + "//tensorboard/compat:tensorflow", "//tensorboard/compat/proto:protos_all_py_pb2", "//tensorboard/util:tensor_util", ], diff --git a/tensorboard/tools/whitespace_hygiene_test.py b/tensorboard/tools/whitespace_hygiene_test.py index c4b4a463086..cff34e33aa0 100755 --- a/tensorboard/tools/whitespace_hygiene_test.py +++ b/tensorboard/tools/whitespace_hygiene_test.py @@ -25,7 +25,15 @@ import sys -exceptions = frozenset([]) +# @TODO(@cdavalos7): Remove this exception when the patch file is no longer needed. +# Patch files use a trailing space on blank lines to mark them as context. +# This is required by patch-package and cannot be removed. +exceptions = frozenset( + [ + "patches/@angular+build-tooling+0.0.0-2113cd7f66a089ac0208ea84eee672b2529f4f6c.patch", + "patches/protobuf_6_31_1_java_export.patch", + ] +) @dataclasses.dataclass(frozen=True) diff --git a/tensorboard/util/BUILD b/tensorboard/util/BUILD index ef1b57fd27c..656c33054da 100644 --- a/tensorboard/util/BUILD +++ b/tensorboard/util/BUILD @@ -69,6 +69,7 @@ py_library( srcs_version = "PY3", deps = [ "//tensorboard/compat", + "//tensorboard/compat:tensorflow", ], ) diff --git a/tensorboard/webapp/BUILD b/tensorboard/webapp/BUILD index e701e6ad829..4bfc675fac9 100644 --- a/tensorboard/webapp/BUILD +++ b/tensorboard/webapp/BUILD @@ -1,4 +1,5 @@ -load("//tensorboard/defs:defs.bzl", "tf_external_sass_libray", "tf_ng_module", "tf_ng_prod_js_binary", "tf_ng_web_test_suite", "tf_sass_binary", "tf_svg_bundle", "tf_ts_library") +load("@io_bazel_rules_sass//:defs.bzl", "sass_binary") +load("//tensorboard/defs:defs.bzl", "tf_ng_module", "tf_ng_prod_js_binary", "tf_ng_web_test_suite", "tf_svg_bundle", "tf_ts_library") load("//tensorboard/defs:js.bzl", "tf_resource_digest_suffixer") load("//tensorboard/defs:web.bzl", "tb_combine_html", "tf_web_library") @@ -86,9 +87,10 @@ tf_ts_library( ], ) -tf_sass_binary( +sass_binary( name = "app_styles", src = "app_container.scss", + include_paths = ["external/npm/node_modules"], deps = ["//tensorboard/webapp/theme"], ) @@ -379,13 +381,9 @@ tf_svg_bundle( out = "icon_bundle.svg", ) -tf_external_sass_libray( - name = "angular_material_sass_deps", - deps = ["@npm//@angular/material"], -) - -tf_sass_binary( +sass_binary( name = "styles", src = "styles.scss", + include_paths = ["external/npm/node_modules"], deps = ["//tensorboard/webapp/theme"], ) diff --git a/tensorboard/webapp/alert/alert_action_test.ts b/tensorboard/webapp/alert/alert_action_test.ts index 45d0e0ebaad..3f2a43c0822 100644 --- a/tensorboard/webapp/alert/alert_action_test.ts +++ b/tensorboard/webapp/alert/alert_action_test.ts @@ -59,7 +59,8 @@ describe('alert_effects', () => { store = TestBed.inject>(Store) as MockStore; recordedActions = []; - spyOn(store, 'dispatch').and.callFake((action: Action) => { + // Cast to jasmine.Spy for compatibility between NgRx dispatch signature overloads. + (spyOn(store, 'dispatch') as jasmine.Spy).and.callFake((action: Action) => { recordedActions.push(action); }); }); diff --git a/tensorboard/webapp/alert/views/BUILD b/tensorboard/webapp/alert/views/BUILD index 8e846f96215..18cc93958ba 100644 --- a/tensorboard/webapp/alert/views/BUILD +++ b/tensorboard/webapp/alert/views/BUILD @@ -1,10 +1,12 @@ -load("//tensorboard/defs:defs.bzl", "tf_ng_module", "tf_sass_binary", "tf_ts_library") +load("@io_bazel_rules_sass//:defs.bzl", "sass_binary") +load("//tensorboard/defs:defs.bzl", "tf_ng_module", "tf_ts_library") package(default_visibility = ["//tensorboard:internal"]) -tf_sass_binary( +sass_binary( name = "alert_display_snackbar_styles", src = "alert_display_snackbar_container.scss", + include_paths = ["external/npm/node_modules"], ) tf_ng_module( diff --git a/tensorboard/webapp/alert/views/alert_snackbar_test.ts b/tensorboard/webapp/alert/views/alert_snackbar_test.ts index 2870ac2f3a0..9fdb69b5c0c 100644 --- a/tensorboard/webapp/alert/views/alert_snackbar_test.ts +++ b/tensorboard/webapp/alert/views/alert_snackbar_test.ts @@ -13,7 +13,7 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ import {OverlayContainer} from '@angular/cdk/overlay'; -import {TestBed} from '@angular/core/testing'; +import {fakeAsync, flush, TestBed} from '@angular/core/testing'; import {MatButtonModule} from '@angular/material/button'; import {MatSnackBar, MatSnackBarModule} from '@angular/material/snack-bar'; import {NoopAnimationsModule} from '@angular/platform-browser/animations'; @@ -56,7 +56,8 @@ describe('alert snackbar', () => { }).compileComponents(); store = TestBed.inject>(Store) as MockStore; recordedActions = []; - spyOn(store, 'dispatch').and.callFake((action: Action) => { + // Cast to jasmine.Spy for compatibility between NgRx dispatch signature overloads. + (spyOn(store, 'dispatch') as jasmine.Spy).and.callFake((action: Action) => { recordedActions.push(action); }); overlayContainer = TestBed.inject(OverlayContainer); @@ -129,7 +130,8 @@ describe('alert snackbar', () => { }); }); - it('closes the snackbar on click', async () => { + /* Replaced async/await with fakeAsync/flush(). Angular Material 17 no longer triggers immediate change detection when dismissing the snackbar. Since the snackbar lives in an overlay outside the test component, fixture.detectChanges() doesn't reach it. flush() forces all pending tasks to complete globally, including the overlay */ + it('closes the snackbar on click', fakeAsync(() => { const fixture = TestBed.createComponent(AlertSnackbarContainer); fixture.detectChanges(); store.overrideSelector(selectors.getLatestAlert, { @@ -143,14 +145,13 @@ describe('alert snackbar', () => { .querySelector(Selectors.DISMISS_BUTTON); expect(dismissEl).toBeTruthy(); (dismissEl as HTMLButtonElement).click(); - fixture.detectChanges(); - await fixture.whenStable(); + flush(); const snackbarAfterEl = overlayContainer .getContainerElement() .querySelector(Selectors.SNACKBAR); expect(snackbarAfterEl).not.toBeTruthy(); - }); + })); it('shows the followup action if needed', () => { const fixture = TestBed.createComponent(AlertSnackbarContainer); @@ -187,7 +188,7 @@ describe('alert snackbar', () => { expect(followupEl).not.toBeTruthy(); }); - it('dispatches a followup action and closes', async () => { + it('dispatches a followup action and closes', fakeAsync(() => { const fixture = TestBed.createComponent(AlertSnackbarContainer); fixture.detectChanges(); store.overrideSelector(selectors.getLatestAlert, { @@ -204,17 +205,16 @@ describe('alert snackbar', () => { .getContainerElement() .querySelector(Selectors.FOLLOWUP_BUTTON); (followupEl as HTMLButtonElement).click(); - fixture.detectChanges(); - await fixture.whenStable(); + flush(); expect(recordedActions).toEqual([testAction()]); const snackbarAfterEl = overlayContainer .getContainerElement() .querySelector(Selectors.SNACKBAR); expect(snackbarAfterEl).not.toBeTruthy(); - }); + })); - it('dispatches a followup action with payload and closes', async () => { + it('dispatches a followup action with payload and closes', fakeAsync(() => { const fixture = TestBed.createComponent(AlertSnackbarContainer); fixture.detectChanges(); store.overrideSelector(selectors.getLatestAlert, { @@ -231,13 +231,12 @@ describe('alert snackbar', () => { .getContainerElement() .querySelector(Selectors.FOLLOWUP_BUTTON); (followupEl as HTMLButtonElement).click(); - fixture.detectChanges(); - await fixture.whenStable(); + flush(); expect(recordedActions).toEqual([testActionWithProps({foo: true})]); const snackbarAfterEl = overlayContainer .getContainerElement() .querySelector(Selectors.SNACKBAR); expect(snackbarAfterEl).not.toBeTruthy(); - }); + })); }); diff --git a/tensorboard/webapp/angular_components/BUILD b/tensorboard/webapp/angular_components/BUILD new file mode 100644 index 00000000000..6dad4ea28b0 --- /dev/null +++ b/tensorboard/webapp/angular_components/BUILD @@ -0,0 +1,10 @@ +# Open-source-only file (synced as BUILD.OPENSOURCE). Internally this dependency +# is managed directly by Blaze, so npm_sass_library is not needed. +load("@io_bazel_rules_sass//:defs.bzl", "npm_sass_library") + +package(default_visibility = ["//tensorboard:internal"]) + +npm_sass_library( + name = "material_sass", + deps = ["@npm//@angular/material"], +) diff --git a/tensorboard/webapp/app_container.ts b/tensorboard/webapp/app_container.ts index 64f21f74465..6fe181ba77b 100644 --- a/tensorboard/webapp/app_container.ts +++ b/tensorboard/webapp/app_container.ts @@ -12,9 +12,14 @@ 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 {Component, ViewContainerRef} from '@angular/core'; +import { + ChangeDetectionStrategy, + Component, + ViewContainerRef, +} from '@angular/core'; @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'tb-webapp', templateUrl: './app_container.ng.html', diff --git a/tensorboard/webapp/app_routing/effects/app_routing_effects_test.ts b/tensorboard/webapp/app_routing/effects/app_routing_effects_test.ts index afa8834701d..af5aeddf7c4 100644 --- a/tensorboard/webapp/app_routing/effects/app_routing_effects_test.ts +++ b/tensorboard/webapp/app_routing/effects/app_routing_effects_test.ts @@ -13,7 +13,7 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -import {Component} from '@angular/core'; +import {ChangeDetectionStrategy, Component} from '@angular/core'; import {fakeAsync, flush, TestBed, tick} from '@angular/core/testing'; import {provideMockActions} from '@ngrx/effects/testing'; import {Action, createAction, createSelector, props, Store} from '@ngrx/store'; @@ -48,7 +48,13 @@ import { } from '../types'; import {AppRoutingEffects, TEST_ONLY} from './app_routing_effects'; -@Component({standalone: false, selector: 'test', template: '', jit: true}) +@Component({ + changeDetection: ChangeDetectionStrategy.Default, + standalone: false, + selector: 'test', + template: '', + jit: true, +}) class TestableComponent {} const testAction = createAction('[TEST] test action'); @@ -237,7 +243,8 @@ describe('app_routing_effects', () => { store.overrideSelector(getRehydratedDeepLinks, []); actualActions = []; - spyOn(store, 'dispatch').and.callFake((action: Action) => { + // Cast to jasmine.Spy for compatibility between NgRx dispatch signature overloads. + (spyOn(store, 'dispatch') as jasmine.Spy).and.callFake((action: Action) => { actualActions.push(action); }); diff --git a/tensorboard/webapp/app_routing/route_config_test.ts b/tensorboard/webapp/app_routing/route_config_test.ts index eac5e5d67dd..e51e6cc42cf 100644 --- a/tensorboard/webapp/app_routing/route_config_test.ts +++ b/tensorboard/webapp/app_routing/route_config_test.ts @@ -13,13 +13,18 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -import {Component} from '@angular/core'; +import {ChangeDetectionStrategy, Component} from '@angular/core'; import {createAction, props} from '@ngrx/store'; import {RouteConfigs, RouteMatch} from './route_config'; import {ConcreteRouteDef, RedirectionRouteDef} from './route_config_types'; import {Navigation, RouteKind} from './types'; -@Component({standalone: false, selector: 'test', template: ''}) +@Component({ + changeDetection: ChangeDetectionStrategy.Default, + standalone: false, + selector: 'test', + template: '', +}) class TestableComponent {} function buildConcreteRouteDef(override: Partial) { diff --git a/tensorboard/webapp/app_routing/route_config_types.ts b/tensorboard/webapp/app_routing/route_config_types.ts index b8c0fc08037..6d83248c40c 100644 --- a/tensorboard/webapp/app_routing/route_config_types.ts +++ b/tensorboard/webapp/app_routing/route_config_types.ts @@ -12,10 +12,10 @@ 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 {Component, Type} from '@angular/core'; +import {Type} from '@angular/core'; +import {Action} from '@ngrx/store'; import {DeepLinkProvider} from './deep_link_provider'; import {RouteKind, SerializableQueryParams} from './types'; -import {Action} from '@ngrx/store'; export interface ConcreteRouteDef { routeKind: RouteKind; @@ -26,7 +26,7 @@ export interface ConcreteRouteDef { // Parameter has to be denoted with ":" prefix and "/" has to precede it. path: string; - ngComponent: Type; + ngComponent: Type; // Redirect to this `path` if current navigation does not match any known // routes. Only one RouteConfig can have defaultRoute = true. diff --git a/tensorboard/webapp/app_routing/route_registry_module.ts b/tensorboard/webapp/app_routing/route_registry_module.ts index ddb2b12d07d..2f09c83bc77 100644 --- a/tensorboard/webapp/app_routing/route_registry_module.ts +++ b/tensorboard/webapp/app_routing/route_registry_module.ts @@ -13,7 +13,6 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ import { - Component, Inject, ModuleWithProviders, NgModule, @@ -28,10 +27,7 @@ import {RouteKind} from './types'; @NgModule({}) export class RouteRegistryModule { private readonly routeConfigs: RouteConfigs; - private readonly routeKindToNgComponent = new Map< - RouteKind, - Type - >(); + private readonly routeKindToNgComponent = new Map>(); constructor( @Optional() @Inject(ROUTE_CONFIGS_TOKEN) configsList: RouteDef[][] @@ -67,7 +63,7 @@ export class RouteRegistryModule { return this.routeConfigs; } - getNgComponentByRouteKind(routeKind: RouteKind): Type | null { + getNgComponentByRouteKind(routeKind: RouteKind): Type | null { return this.routeKindToNgComponent.get(routeKind) || null; } diff --git a/tensorboard/webapp/app_routing/route_registry_module_test.ts b/tensorboard/webapp/app_routing/route_registry_module_test.ts index 5229882f578..32370b39af9 100644 --- a/tensorboard/webapp/app_routing/route_registry_module_test.ts +++ b/tensorboard/webapp/app_routing/route_registry_module_test.ts @@ -13,12 +13,13 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -import {Component} from '@angular/core'; +import {ChangeDetectionStrategy, Component} from '@angular/core'; import {TestBed} from '@angular/core/testing'; import {RouteRegistryModule} from './route_registry_module'; import {RouteKind} from './types'; @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'experiment', template: 'I am experiment', @@ -26,6 +27,7 @@ import {RouteKind} from './types'; class Experiment {} @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'experiments', template: 'List of experiment', @@ -33,6 +35,7 @@ class Experiment {} class Experiments {} @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'not_found', template: 'Unknown route', diff --git a/tensorboard/webapp/app_routing/views/router_link_test.ts b/tensorboard/webapp/app_routing/views/router_link_test.ts index 1e01818dd18..879990682e3 100644 --- a/tensorboard/webapp/app_routing/views/router_link_test.ts +++ b/tensorboard/webapp/app_routing/views/router_link_test.ts @@ -13,7 +13,13 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -import {Component, DebugElement, Input, NO_ERRORS_SCHEMA} from '@angular/core'; +import { + ChangeDetectionStrategy, + Component, + DebugElement, + Input, + NO_ERRORS_SCHEMA, +} from '@angular/core'; import {TestBed} from '@angular/core/testing'; import {By} from '@angular/platform-browser'; import {NoopAnimationsModule} from '@angular/platform-browser/animations'; @@ -27,6 +33,7 @@ import {LocationModule} from '../location_module'; import {RouterLinkDirectiveContainer} from './router_link_directive_container'; @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'test', template: 'testable link', @@ -37,6 +44,7 @@ class TestableComponent { } @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'test-with-reset', template: @@ -73,7 +81,8 @@ describe('router_link', () => { AppRootProvider ) as TestableAppRootProvider; - spyOn(store, 'dispatch').and.callFake((action: Action) => { + // Cast to jasmine.Spy for compatibility between NgRx dispatch signature overloads. + (spyOn(store, 'dispatch') as jasmine.Spy).and.callFake((action: Action) => { actualDispatches.push(action); }); }); diff --git a/tensorboard/webapp/app_routing/views/router_outlet_component.ts b/tensorboard/webapp/app_routing/views/router_outlet_component.ts index 7729dd76b46..2b28f9f361f 100644 --- a/tensorboard/webapp/app_routing/views/router_outlet_component.ts +++ b/tensorboard/webapp/app_routing/views/router_outlet_component.ts @@ -33,14 +33,14 @@ export class RouterOutletComponent implements OnChanges { @ViewChild('routeContainer', {static: true, read: ViewContainerRef}) private readonly routeContainer!: ViewContainerRef; - @Input() activeNgComponent!: Type | null; + @Input() activeNgComponent!: Type | null; ngOnChanges(changes: SimpleChanges) { const activeComponentChange = changes['activeNgComponent']; if (activeComponentChange) { this.routeContainer.clear(); const componentType = - activeComponentChange.currentValue as Type | null; + activeComponentChange.currentValue as Type | null; if (componentType) { this.routeContainer.createComponent(componentType); } diff --git a/tensorboard/webapp/app_routing/views/router_outlet_test.ts b/tensorboard/webapp/app_routing/views/router_outlet_test.ts index bb26173e72a..d3afebc4e1b 100644 --- a/tensorboard/webapp/app_routing/views/router_outlet_test.ts +++ b/tensorboard/webapp/app_routing/views/router_outlet_test.ts @@ -13,7 +13,11 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -import {Component, NO_ERRORS_SCHEMA} from '@angular/core'; +import { + ChangeDetectionStrategy, + Component, + NO_ERRORS_SCHEMA, +} from '@angular/core'; import {TestBed} from '@angular/core/testing'; import {By} from '@angular/platform-browser'; import {BrowserDynamicTestingModule} from '@angular/platform-browser-dynamic/testing'; @@ -33,6 +37,7 @@ import {RouterOutletComponent} from './router_outlet_component'; import {RouterOutletContainer} from './router_outlet_container'; @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'first', template: 'I am a test', @@ -40,6 +45,7 @@ import {RouterOutletContainer} from './router_outlet_container'; class FirstTestableComponent {} @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'second', template: 'I am inevitable', diff --git a/tensorboard/webapp/core/effects/core_effects_test.ts b/tensorboard/webapp/core/effects/core_effects_test.ts index f969974b580..dfc2ba44ea0 100644 --- a/tensorboard/webapp/core/effects/core_effects_test.ts +++ b/tensorboard/webapp/core/effects/core_effects_test.ts @@ -111,7 +111,8 @@ describe('core_effects', () => { store = TestBed.inject>(Store) as MockStore; recordedActions = []; - spyOn(store, 'dispatch').and.callFake((action: Action) => { + // Cast to jasmine.Spy for compatibility between NgRx dispatch signature overloads. + (spyOn(store, 'dispatch') as jasmine.Spy).and.callFake((action: Action) => { recordedActions.push(action); }); diff --git a/tensorboard/webapp/core/views/BUILD b/tensorboard/webapp/core/views/BUILD index 7cd765e171f..52ef18642a3 100644 --- a/tensorboard/webapp/core/views/BUILD +++ b/tensorboard/webapp/core/views/BUILD @@ -1,10 +1,12 @@ -load("//tensorboard/defs:defs.bzl", "tf_ng_module", "tf_sass_binary", "tf_ts_library") +load("@io_bazel_rules_sass//:defs.bzl", "sass_binary") +load("//tensorboard/defs:defs.bzl", "tf_ng_module", "tf_ts_library") package(default_visibility = ["//tensorboard:internal"]) -tf_sass_binary( +sass_binary( name = "layout_styles", src = "layout_container.scss", + include_paths = ["external/npm/node_modules"], deps = ["//tensorboard/webapp/theme"], ) diff --git a/tensorboard/webapp/core/views/layout_test.ts b/tensorboard/webapp/core/views/layout_test.ts index 5f2850a4d2b..f210fd17889 100644 --- a/tensorboard/webapp/core/views/layout_test.ts +++ b/tensorboard/webapp/core/views/layout_test.ts @@ -12,7 +12,7 @@ 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 {Component} from '@angular/core'; +import {ChangeDetectionStrategy, Component} from '@angular/core'; import {ComponentFixture, TestBed} from '@angular/core/testing'; import {By} from '@angular/platform-browser'; import {NoopAnimationsModule} from '@angular/platform-browser/animations'; @@ -30,6 +30,7 @@ import { import {LayoutContainer} from './layout_container'; @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'sidebar', template: `sidebar content`, @@ -37,6 +38,7 @@ import {LayoutContainer} from './layout_container'; class Sidebar {} @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'main', template: `main content`, @@ -44,6 +46,7 @@ class Sidebar {} class Main {} @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'testable-component', template: ` @@ -85,7 +88,8 @@ describe('layout test', () => { dispatchedActions = []; store = TestBed.inject>(Store) as MockStore; - spyOn(store, 'dispatch').and.callFake((action: Action) => { + // Cast to jasmine.Spy for compatibility between NgRx dispatch signature overloads. + (spyOn(store, 'dispatch') as jasmine.Spy).and.callFake((action: Action) => { dispatchedActions.push(action); }); store.overrideSelector(getSideBarWidthInPercent, 10); diff --git a/tensorboard/webapp/core/views/page_title_test.ts b/tensorboard/webapp/core/views/page_title_test.ts index 1d208e6a7ca..08653b63ef9 100644 --- a/tensorboard/webapp/core/views/page_title_test.ts +++ b/tensorboard/webapp/core/views/page_title_test.ts @@ -12,7 +12,11 @@ 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 {Component, NO_ERRORS_SCHEMA} from '@angular/core'; +import { + ChangeDetectionStrategy, + Component, + NO_ERRORS_SCHEMA, +} from '@angular/core'; import {TestBed} from '@angular/core/testing'; import {Store} from '@ngrx/store'; import {MockStore} from '@ngrx/store/testing'; @@ -112,6 +116,7 @@ describe('page title test', () => { }); @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'my-tester', template: ` `, diff --git a/tensorboard/webapp/customization/customizable_component.ts b/tensorboard/webapp/customization/customizable_component.ts index 78a31015943..a1866d2d315 100644 --- a/tensorboard/webapp/customization/customizable_component.ts +++ b/tensorboard/webapp/customization/customizable_component.ts @@ -12,7 +12,14 @@ 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 {Component, Input, OnInit, Type, ViewContainerRef} from '@angular/core'; +import { + ChangeDetectionStrategy, + Component, + Input, + OnInit, + Type, + ViewContainerRef, +} from '@angular/core'; /** * A Component that defines a customization point. Ideal for use for small @@ -24,7 +31,7 @@ import {Component, Input, OnInit, Type, ViewContainerRef} from '@angular/core'; * * 1. Define a customizable Component, for example a button: * - * const CustomizableButton = new InjectionToken>('Customizable Button'); + * const CustomizableButton = new InjectionToken>('Customizable Button'); * * 2. Where the customization point is desired, use this Component to wrap some * default behavior. Bind to some possibly-empty variable with the @@ -39,7 +46,7 @@ import {Component, Input, OnInit, Type, ViewContainerRef} from '@angular/core'; * * constructor( * @Optional() @Inject(CustomizableButton) - * readonly customButtonIfProvided: Type) + * readonly customButtonIfProvided: Type) * * If you do not wish to customize the behavior for a certain TensorBoard * service (in this case, a button), you're done. The TensorBoard service @@ -68,6 +75,7 @@ import {Component, Input, OnInit, Type, ViewContainerRef} from '@angular/core'; * }) */ @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'tb-customization', template: ` @@ -77,7 +85,7 @@ import {Component, Input, OnInit, Type, ViewContainerRef} from '@angular/core'; `, }) export class CustomizableComponent implements OnInit { - @Input() customizableComponent!: Type | undefined; + @Input() customizableComponent!: Type | undefined; constructor(private readonly viewContainerRef: ViewContainerRef) {} diff --git a/tensorboard/webapp/customization/customization_test.ts b/tensorboard/webapp/customization/customization_test.ts index 88ebb972422..e7f6d5d593e 100644 --- a/tensorboard/webapp/customization/customization_test.ts +++ b/tensorboard/webapp/customization/customization_test.ts @@ -12,7 +12,12 @@ 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 {Component, NgModule, Optional} from '@angular/core'; +import { + ChangeDetectionStrategy, + Component, + NgModule, + Optional, +} from '@angular/core'; import {TestBed} from '@angular/core/testing'; import {CustomizationModule} from './customization_module'; @@ -26,6 +31,7 @@ export class CustomizableComponentType {} * Parent class that uses the component. */ @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'parent-component', template: ` @@ -55,6 +61,7 @@ export class ParentComponentModule {} * into the ParentComponent for some tests. */ @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'customizable-component', template: `
Showing Customized Text!
`, diff --git a/tensorboard/webapp/feature_flag/directives/feature_flag_directive_test.ts b/tensorboard/webapp/feature_flag/directives/feature_flag_directive_test.ts index 042762d1b16..6d236ad77cc 100644 --- a/tensorboard/webapp/feature_flag/directives/feature_flag_directive_test.ts +++ b/tensorboard/webapp/feature_flag/directives/feature_flag_directive_test.ts @@ -12,20 +12,25 @@ 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 {Component, DebugElement, Input} from '@angular/core'; +import { + ChangeDetectionStrategy, + Component, + DebugElement, + Input, +} from '@angular/core'; import {TestBed, fakeAsync, tick} from '@angular/core/testing'; import {By} from '@angular/platform-browser'; import {Store} from '@ngrx/store'; import {MockStore} from '@ngrx/store/testing'; import {provideMockTbStore} from '../../testing/utils'; -import {FEATURE_FLAGS_HEADER_NAME} from '../http/const'; import {getFeatureFlagsToSendToServer} from '../store/feature_flag_selectors'; import {State as FeatureFlagState} from '../store/feature_flag_types'; import {FeatureFlagDirective} from './feature_flag_directive'; @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'test-matching-selector', template: ` @@ -41,6 +46,7 @@ export class TestMatchingComponent { } @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'test-nonmatching-selector', template: ` diff --git a/tensorboard/webapp/feature_flag/views/BUILD b/tensorboard/webapp/feature_flag/views/BUILD index 75842f0abaa..220be0ca004 100644 --- a/tensorboard/webapp/feature_flag/views/BUILD +++ b/tensorboard/webapp/feature_flag/views/BUILD @@ -1,14 +1,16 @@ -load("//tensorboard/defs:defs.bzl", "tf_ng_module", "tf_sass_binary") +load("@io_bazel_rules_sass//:defs.bzl", "sass_binary") +load("//tensorboard/defs:defs.bzl", "tf_ng_module") package(default_visibility = ["//tensorboard:internal"]) licenses(["notice"]) -tf_sass_binary( +sass_binary( name = "style", src = "feature_flag_dialog_component.scss", + include_paths = ["external/npm/node_modules"], deps = [ - "//tensorboard/webapp:angular_material_sass_deps", + "//tensorboard/webapp/angular_components:material_sass", "//tensorboard/webapp/theme", ], ) diff --git a/tensorboard/webapp/feature_flag/views/feature_flag_dialog_component.ts b/tensorboard/webapp/feature_flag/views/feature_flag_dialog_component.ts index b749959e721..82cdc0e59a9 100644 --- a/tensorboard/webapp/feature_flag/views/feature_flag_dialog_component.ts +++ b/tensorboard/webapp/feature_flag/views/feature_flag_dialog_component.ts @@ -12,12 +12,19 @@ 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 {Component, EventEmitter, Input, Output} from '@angular/core'; +import { + ChangeDetectionStrategy, + Component, + EventEmitter, + Input, + Output, +} from '@angular/core'; import {FeatureFlagType} from '../store/feature_flag_metadata'; import {FeatureFlags} from '../types'; import {FeatureFlagStatus, FeatureFlagStatusEvent} from './types'; @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'feature-flag-dialog-component', styleUrls: ['feature_flag_dialog_component.css'], diff --git a/tensorboard/webapp/feature_flag/views/feature_flag_dialog_container.ts b/tensorboard/webapp/feature_flag/views/feature_flag_dialog_container.ts index 80af1f193f0..b29cb822d72 100644 --- a/tensorboard/webapp/feature_flag/views/feature_flag_dialog_container.ts +++ b/tensorboard/webapp/feature_flag/views/feature_flag_dialog_container.ts @@ -12,7 +12,7 @@ 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 {Component} from '@angular/core'; +import {ChangeDetectionStrategy, Component} from '@angular/core'; import {Store} from '@ngrx/store'; import {Observable} from 'rxjs'; import {map, withLatestFrom} from 'rxjs/operators'; @@ -40,6 +40,7 @@ import { } from './types'; @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'feature-flag-dialog', template: `Test', diff --git a/tensorboard/webapp/header/BUILD b/tensorboard/webapp/header/BUILD index c8bcd55b950..fdf57acf285 100644 --- a/tensorboard/webapp/header/BUILD +++ b/tensorboard/webapp/header/BUILD @@ -1,18 +1,21 @@ -load("//tensorboard/defs:defs.bzl", "tf_ng_module", "tf_sass_binary", "tf_ts_library") +load("@io_bazel_rules_sass//:defs.bzl", "sass_binary") +load("//tensorboard/defs:defs.bzl", "tf_ng_module", "tf_ts_library") package(default_visibility = ["//tensorboard:internal"]) licenses(["notice"]) -tf_sass_binary( +sass_binary( name = "plugin_selector_styles", src = "plugin_selector_component.scss", + include_paths = ["external/npm/node_modules"], deps = ["//tensorboard/webapp/theme"], ) -tf_sass_binary( +sass_binary( name = "header_styles", src = "header_component.scss", + include_paths = ["external/npm/node_modules"], deps = ["//tensorboard/webapp/theme"], ) diff --git a/tensorboard/webapp/header/dark_mode_toggle_component.ts b/tensorboard/webapp/header/dark_mode_toggle_component.ts index 40aae27cc2d..a3183b6e861 100644 --- a/tensorboard/webapp/header/dark_mode_toggle_component.ts +++ b/tensorboard/webapp/header/dark_mode_toggle_component.ts @@ -12,7 +12,13 @@ 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 {Component, EventEmitter, Input, Output} from '@angular/core'; +import { + ChangeDetectionStrategy, + Component, + EventEmitter, + Input, + Output, +} from '@angular/core'; export enum DarkModeOverride { DEFAULT, @@ -21,6 +27,7 @@ export enum DarkModeOverride { } @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'app-header-dark-mode-toggle-component', template: ` diff --git a/tensorboard/webapp/header/dark_mode_toggle_container.ts b/tensorboard/webapp/header/dark_mode_toggle_container.ts index 1a01cbec62a..52a1362fddc 100644 --- a/tensorboard/webapp/header/dark_mode_toggle_container.ts +++ b/tensorboard/webapp/header/dark_mode_toggle_container.ts @@ -12,7 +12,7 @@ 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 {Component} from '@angular/core'; +import {ChangeDetectionStrategy, Component} from '@angular/core'; import {Store} from '@ngrx/store'; import {Observable} from 'rxjs'; import {map} from 'rxjs/operators'; @@ -23,6 +23,7 @@ import {State as FeatureFlagState} from '../feature_flag/store/feature_flag_type import {DarkModeOverride} from './dark_mode_toggle_component'; @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'app-header-dark-mode-toggle', template: ` diff --git a/tensorboard/webapp/header/dark_mode_toggle_test.ts b/tensorboard/webapp/header/dark_mode_toggle_test.ts index 6cedfad7249..3365cb742ab 100644 --- a/tensorboard/webapp/header/dark_mode_toggle_test.ts +++ b/tensorboard/webapp/header/dark_mode_toggle_test.ts @@ -50,7 +50,8 @@ describe('dark mode toggle test', () => { store.overrideSelector(getEnableDarkModeOverride, null); dispatchedActions = []; - spyOn(store, 'dispatch').and.callFake((action: Action) => { + // Cast to jasmine.Spy for compatibility between NgRx dispatch signature overloads. + (spyOn(store, 'dispatch') as jasmine.Spy).and.callFake((action: Action) => { dispatchedActions.push(action); }); diff --git a/tensorboard/webapp/header/header_component.ts b/tensorboard/webapp/header/header_component.ts index bbf8da9bbb9..c6d95692f41 100644 --- a/tensorboard/webapp/header/header_component.ts +++ b/tensorboard/webapp/header/header_component.ts @@ -12,9 +12,10 @@ 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 {Component} from '@angular/core'; +import {ChangeDetectionStrategy, Component} from '@angular/core'; @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'app-header', template: ` diff --git a/tensorboard/webapp/header/plugin_selector_component.ts b/tensorboard/webapp/header/plugin_selector_component.ts index b143a9609cb..4680736a1e9 100644 --- a/tensorboard/webapp/header/plugin_selector_component.ts +++ b/tensorboard/webapp/header/plugin_selector_component.ts @@ -12,12 +12,19 @@ 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 {Component, EventEmitter, Input, Output} from '@angular/core'; +import { + ChangeDetectionStrategy, + Component, + EventEmitter, + Input, + Output, +} from '@angular/core'; import {MatSelectChange} from '@angular/material/select'; import {PluginId} from '../types/api'; import {UiPluginMetadata} from './types'; @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'plugin-selector-component', templateUrl: './plugin_selector_component.ng.html', diff --git a/tensorboard/webapp/header/plugin_selector_container.ts b/tensorboard/webapp/header/plugin_selector_container.ts index 0c2eb8b60d9..a678c6ec63e 100644 --- a/tensorboard/webapp/header/plugin_selector_container.ts +++ b/tensorboard/webapp/header/plugin_selector_container.ts @@ -12,7 +12,7 @@ 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 {Component} from '@angular/core'; +import {ChangeDetectionStrategy, Component} from '@angular/core'; import {createSelector, select, Store} from '@ngrx/store'; import {changePlugin} from '../core/actions'; import {getActivePlugin, getPlugins, State} from '../core/store'; @@ -29,6 +29,7 @@ const getDisabledPlugins = createSelector( ); @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'plugin-selector', template: ` diff --git a/tensorboard/webapp/header/reload_container.ts b/tensorboard/webapp/header/reload_container.ts index 742ac0e4c48..d8a6d1078f4 100644 --- a/tensorboard/webapp/header/reload_container.ts +++ b/tensorboard/webapp/header/reload_container.ts @@ -12,7 +12,7 @@ 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 {Component} from '@angular/core'; +import {ChangeDetectionStrategy, Component} from '@angular/core'; import {createSelector, Store} from '@ngrx/store'; import {Observable} from 'rxjs'; import {combineLatestWith, map} from 'rxjs/operators'; @@ -36,6 +36,7 @@ const isReloadDisabledByPlugin = createSelector( ); @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'app-header-reload', template: ` diff --git a/tensorboard/webapp/hparams/_redux/hparams_effects_test.ts b/tensorboard/webapp/hparams/_redux/hparams_effects_test.ts index e8b8e1e1d1d..0669f67f1ea 100644 --- a/tensorboard/webapp/hparams/_redux/hparams_effects_test.ts +++ b/tensorboard/webapp/hparams/_redux/hparams_effects_test.ts @@ -65,9 +65,12 @@ describe('hparams effects', () => { store = TestBed.inject>(Store) as MockStore; actualActions = []; - dispatchSpy = spyOn(store, 'dispatch').and.callFake((action: Action) => { - actualActions.push(action); - }); + // Cast to jasmine.Spy for compatibility between NgRx dispatch signature overloads. + dispatchSpy = (spyOn(store, 'dispatch') as jasmine.Spy).and.callFake( + (action: Action) => { + actualActions.push(action); + } + ); effects = TestBed.inject(HparamsEffects); dataSource = TestBed.inject( diff --git a/tensorboard/webapp/metrics/effects/metrics_effects_test.ts b/tensorboard/webapp/metrics/effects/metrics_effects_test.ts index c56c4d08ec2..1abcd90567c 100644 --- a/tensorboard/webapp/metrics/effects/metrics_effects_test.ts +++ b/tensorboard/webapp/metrics/effects/metrics_effects_test.ts @@ -85,7 +85,8 @@ describe('metrics effects', () => { }).compileComponents(); store = TestBed.inject>(Store) as MockStore; - spyOn(store, 'dispatch').and.callFake((action: Action) => { + // Cast to jasmine.Spy for compatibility between NgRx dispatch signature overloads. + (spyOn(store, 'dispatch') as jasmine.Spy).and.callFake((action: Action) => { actualActions.push(action); }); effects = TestBed.inject(MetricsEffects); diff --git a/tensorboard/webapp/metrics/views/BUILD b/tensorboard/webapp/metrics/views/BUILD index 5544836ce17..0812e35767e 100644 --- a/tensorboard/webapp/metrics/views/BUILD +++ b/tensorboard/webapp/metrics/views/BUILD @@ -1,19 +1,21 @@ -load("//tensorboard/defs:defs.bzl", "tf_ng_module", "tf_sass_binary", "tf_sass_library", "tf_ts_library") +load("@io_bazel_rules_sass//:defs.bzl", "sass_binary", "sass_library") +load("//tensorboard/defs:defs.bzl", "tf_ng_module", "tf_ts_library") package(default_visibility = ["//tensorboard:internal"]) -tf_sass_library( +sass_library( name = "metrics_common_styles", srcs = [ "_common.scss", ], ) -tf_sass_binary( +sass_binary( name = "metrics_container_styles", src = "metrics_container.scss", + include_paths = ["external/npm/node_modules"], deps = [ - "//tensorboard/webapp:angular_material_sass_deps", + "//tensorboard/webapp/angular_components:material_sass", "//tensorboard/webapp/theme", ], ) diff --git a/tensorboard/webapp/metrics/views/card_renderer/BUILD b/tensorboard/webapp/metrics/views/card_renderer/BUILD index 288f052416f..014159b6c42 100644 --- a/tensorboard/webapp/metrics/views/card_renderer/BUILD +++ b/tensorboard/webapp/metrics/views/card_renderer/BUILD @@ -1,10 +1,12 @@ -load("//tensorboard/defs:defs.bzl", "tf_ng_module", "tf_sass_binary", "tf_ts_library") +load("@io_bazel_rules_sass//:defs.bzl", "sass_binary") +load("//tensorboard/defs:defs.bzl", "tf_ng_module", "tf_ts_library") package(default_visibility = ["//tensorboard:internal"]) -tf_sass_binary( +sass_binary( name = "card_view_styles", src = "card_view_container.scss", + include_paths = ["external/npm/node_modules"], deps = ["//tensorboard/webapp/theme"], ) @@ -39,9 +41,10 @@ tf_ng_module( ], ) -tf_sass_binary( +sass_binary( name = "data_download_dialog_styles", src = "data_download_dialog_component.scss", + include_paths = ["external/npm/node_modules"], deps = ["//tensorboard/webapp/theme"], ) @@ -76,9 +79,10 @@ tf_ng_module( ], ) -tf_sass_binary( +sass_binary( name = "histogram_card_styles", src = "histogram_card_component.scss", + include_paths = ["external/npm/node_modules"], deps = [ "//tensorboard/webapp/metrics/views:metrics_common_styles", "//tensorboard/webapp/theme", @@ -124,11 +128,12 @@ tf_ng_module( ], ) -tf_sass_binary( +sass_binary( name = "image_card_styles", src = "image_card_component.scss", + include_paths = ["external/npm/node_modules"], deps = [ - "//tensorboard/webapp:angular_material_sass_deps", + "//tensorboard/webapp/angular_components:material_sass", "//tensorboard/webapp/metrics/views:metrics_common_styles", "//tensorboard/webapp/theme", ], @@ -171,9 +176,10 @@ tf_ng_module( ], ) -tf_sass_binary( +sass_binary( name = "run_name_styles", src = "run_name_component.scss", + include_paths = ["external/npm/node_modules"], deps = ["//tensorboard/webapp/theme"], ) @@ -200,11 +206,12 @@ tf_ng_module( ], ) -tf_sass_binary( +sass_binary( name = "vis_linked_time_selection_warning_styles", src = "vis_linked_time_selection_warning_component.scss", + include_paths = ["external/npm/node_modules"], deps = [ - "//tensorboard/webapp:angular_material_sass_deps", + "//tensorboard/webapp/angular_components:material_sass", "//tensorboard/webapp/theme", ], ) @@ -251,24 +258,27 @@ tf_ts_library( ], ) -tf_sass_binary( +sass_binary( name = "scalar_card_styles", src = "scalar_card_component.scss", + include_paths = ["external/npm/node_modules"], deps = [ - "//tensorboard/webapp:angular_material_sass_deps", + "//tensorboard/webapp/angular_components:material_sass", "//tensorboard/webapp/metrics/views:metrics_common_styles", "//tensorboard/webapp/theme", ], ) -tf_sass_binary( +sass_binary( name = "scalar_card_fob_controller_styles", src = "scalar_card_fob_controller.scss", + include_paths = ["external/npm/node_modules"], ) -tf_sass_binary( +sass_binary( name = "scalar_card_data_table_styles", src = "scalar_card_data_table.scss", + include_paths = ["external/npm/node_modules"], ) tf_ng_module( @@ -358,9 +368,10 @@ tf_ng_module( ], ) -tf_sass_binary( +sass_binary( name = "scalar_card_line_chart_styles", src = "scalar_card_line_chart_component.scss", + include_paths = ["external/npm/node_modules"], deps = ["//tensorboard/webapp/theme"], ) diff --git a/tensorboard/webapp/metrics/views/card_renderer/card_lazy_loader_test.ts b/tensorboard/webapp/metrics/views/card_renderer/card_lazy_loader_test.ts index 90b9f020907..d20ea095ed7 100644 --- a/tensorboard/webapp/metrics/views/card_renderer/card_lazy_loader_test.ts +++ b/tensorboard/webapp/metrics/views/card_renderer/card_lazy_loader_test.ts @@ -12,7 +12,12 @@ 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 {Component, Input, NO_ERRORS_SCHEMA} from '@angular/core'; +import { + ChangeDetectionStrategy, + Component, + Input, + NO_ERRORS_SCHEMA, +} from '@angular/core'; import {ComponentFixture, TestBed} from '@angular/core/testing'; import {By} from '@angular/platform-browser'; import {NoopAnimationsModule} from '@angular/platform-browser/animations'; @@ -25,6 +30,7 @@ import {CardId} from '../../types'; import {CardLazyLoader, CardObserver} from '../card_renderer/card_lazy_loader'; @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'card-view', template: `{{ cardId }}`, @@ -39,6 +45,7 @@ interface TestableCardConfig { } @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'testable-cards', template: ` diff --git a/tensorboard/webapp/metrics/views/card_renderer/card_view_test.ts b/tensorboard/webapp/metrics/views/card_renderer/card_view_test.ts index 323dfe57626..04de6e3c20a 100644 --- a/tensorboard/webapp/metrics/views/card_renderer/card_view_test.ts +++ b/tensorboard/webapp/metrics/views/card_renderer/card_view_test.ts @@ -13,6 +13,7 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ import { + ChangeDetectionStrategy, Component, EventEmitter, Input, @@ -35,6 +36,7 @@ import {CardViewComponent} from './card_view_component'; import {CardViewContainer} from './card_view_container'; @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'scalar-card', template: ``, diff --git a/tensorboard/webapp/metrics/views/card_renderer/histogram_card_test.ts b/tensorboard/webapp/metrics/views/card_renderer/histogram_card_test.ts index 0141459630c..3daafd045cf 100644 --- a/tensorboard/webapp/metrics/views/card_renderer/histogram_card_test.ts +++ b/tensorboard/webapp/metrics/views/card_renderer/histogram_card_test.ts @@ -12,7 +12,13 @@ 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 {Component, EventEmitter, Input, Output} from '@angular/core'; +import { + ChangeDetectionStrategy, + Component, + EventEmitter, + Input, + Output, +} from '@angular/core'; import {ComponentFixture, TestBed} from '@angular/core/testing'; import {MatProgressSpinnerModule} from '@angular/material/progress-spinner'; import {By} from '@angular/platform-browser'; @@ -58,6 +64,7 @@ import {RunNameModule} from './run_name_module'; import {VisLinkedTimeSelectionWarningModule} from './vis_linked_time_selection_warning_module'; @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'tb-histogram', template: ``, diff --git a/tensorboard/webapp/metrics/views/card_renderer/image_card_test.ts b/tensorboard/webapp/metrics/views/card_renderer/image_card_test.ts index 515330e2dfe..6b32b34bdc7 100644 --- a/tensorboard/webapp/metrics/views/card_renderer/image_card_test.ts +++ b/tensorboard/webapp/metrics/views/card_renderer/image_card_test.ts @@ -12,7 +12,7 @@ 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 {Component, Input} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input} from '@angular/core'; import {ComponentFixture, TestBed} from '@angular/core/testing'; import {MatButtonModule} from '@angular/material/button'; import {MatProgressSpinnerModule} from '@angular/material/progress-spinner'; @@ -45,6 +45,7 @@ import {RunNameModule} from './run_name_module'; import {VisLinkedTimeSelectionWarningModule} from './vis_linked_time_selection_warning_module'; @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'card-view', template: ` diff --git a/tensorboard/webapp/metrics/views/card_renderer/scalar_card_line_chart_test.ts b/tensorboard/webapp/metrics/views/card_renderer/scalar_card_line_chart_test.ts index 21334debeb1..3d65413b979 100644 --- a/tensorboard/webapp/metrics/views/card_renderer/scalar_card_line_chart_test.ts +++ b/tensorboard/webapp/metrics/views/card_renderer/scalar_card_line_chart_test.ts @@ -13,6 +13,7 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ import { + ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, @@ -35,6 +36,7 @@ import {State} from '../../../app_state'; import {ExperimentAlias} from '../../../experiments/types'; import * as selectors from '../../../selectors'; import {MatIconTestingModule} from '../../../testing/mat_icon_module'; +import {provideMockTbStore} from '../../../testing/utils'; import {CardFobComponent} from '../../../widgets/card_fob/card_fob_component'; import { CardFobControllerComponent, @@ -54,6 +56,7 @@ import { relativeTimeFormatter, siNumberFormatter, } from '../../../widgets/line_chart_v2/lib/formatter'; +import {Extent} from '../../../widgets/line_chart_v2/lib/public_types'; import { DataSeries, DataSeriesMetadataMap, @@ -69,22 +72,21 @@ import { } from '../../actions'; import {getMetricsCardRangeSelectionEnabled} from '../../store'; import {TooltipSort, XAxisType} from '../../types'; +import {ScalarCardFobController} from './scalar_card_fob_controller'; import {ScalarCardLineChartComponent} from './scalar_card_line_chart_component'; import {ScalarCardLineChartContainer} from './scalar_card_line_chart_container'; -import {ScalarCardFobController} from './scalar_card_fob_controller'; import { MinMaxStep, OriginalSeriesMetadata, + ScalarCardDataSeries, ScalarCardPoint, ScalarCardSeriesMetadata, ScalarCardSeriesMetadataMap, - ScalarCardDataSeries, SeriesType, } from './scalar_card_types'; -import {Extent} from '../../../widgets/line_chart_v2/lib/public_types'; -import {provideMockTbStore} from '../../../testing/utils'; @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'line-chart', template: ` @@ -166,6 +168,7 @@ class TestableLineChart { } @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'test-scalar-card-line-chart', template: ` diff --git a/tensorboard/webapp/metrics/views/card_renderer/scalar_card_test.ts b/tensorboard/webapp/metrics/views/card_renderer/scalar_card_test.ts index b514bc64aff..79c5b72dfd9 100644 --- a/tensorboard/webapp/metrics/views/card_renderer/scalar_card_test.ts +++ b/tensorboard/webapp/metrics/views/card_renderer/scalar_card_test.ts @@ -14,6 +14,7 @@ limitations under the License. ==============================================================================*/ import {OverlayContainer} from '@angular/cdk/overlay'; import { + ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, @@ -30,7 +31,7 @@ import { TestBed, tick, } from '@angular/core/testing'; -import {MatDialogModule, MAT_DIALOG_DATA} from '@angular/material/dialog'; +import {MAT_DIALOG_DATA, MatDialogModule} from '@angular/material/dialog'; import {MatMenuModule} from '@angular/material/menu'; import {MatProgressSpinnerModule} from '@angular/material/progress-spinner'; import {By} from '@angular/platform-browser'; @@ -40,10 +41,16 @@ import {MockStore} from '@ngrx/store/testing'; import {Observable, of, ReplaySubject} from 'rxjs'; import {State} from '../../../app_state'; import {ExperimentAlias} from '../../../experiments/types'; +import * as hparamsActions from '../../../hparams/_redux/hparams_actions'; +import * as hparamsSelectors from '../../../hparams/_redux/hparams_selectors'; +import {HparamFilter} from '../../../hparams/_redux/types'; +import * as runsSelectors from '../../../runs/store/runs_selectors'; import {Run} from '../../../runs/store/runs_types'; import {buildRun} from '../../../runs/store/testing'; import * as selectors from '../../../selectors'; +import {getIsScalarColumnContextMenusEnabled} from '../../../selectors'; import {MatIconTestingModule} from '../../../testing/mat_icon_module'; +import {provideMockTbStore} from '../../../testing/utils'; import {DataLoadState} from '../../../types/data'; import {CardFobComponent} from '../../../widgets/card_fob/card_fob_component'; import { @@ -55,8 +62,23 @@ import { TimeSelectionAffordance, TimeSelectionToggleAffordance, } from '../../../widgets/card_fob/card_fob_types'; +import {ContentCellComponent} from '../../../widgets/data_table/content_cell_component'; +import {ContentRowComponent} from '../../../widgets/data_table/content_row_component'; import {DataTableComponent} from '../../../widgets/data_table/data_table_component'; import {DataTableModule} from '../../../widgets/data_table/data_table_module'; +import {HeaderCellComponent} from '../../../widgets/data_table/header_cell_component'; +import { + AddColumnEvent, + ColumnHeader, + ColumnHeaderType, + DataTableMode, + DomainType, + FilterAddedEvent, + IntervalFilter, + ReorderColumnEvent, + Side, + SortingOrder, +} from '../../../widgets/data_table/types'; import {ExperimentAliasModule} from '../../../widgets/experiment_alias/experiment_alias_module'; import {IntersectionObserverTestingModule} from '../../../widgets/intersection_observer/intersection_observer_testing_module'; import { @@ -64,6 +86,7 @@ import { relativeTimeFormatter, siNumberFormatter, } from '../../../widgets/line_chart_v2/lib/formatter'; +import {Extent} from '../../../widgets/line_chart_v2/lib/public_types'; import { DataSeries, DataSeriesMetadataMap, @@ -76,13 +99,13 @@ import {ResizeDetectorTestingModule} from '../../../widgets/resize_detector_test import {TruncatedPathModule} from '../../../widgets/text/truncated_path_module'; import { cardViewBoxChanged, + dataTableColumnOrderChanged, + dataTableColumnToggled, metricsCardFullSizeToggled, metricsCardStateUpdated, + metricsSlideoutMenuOpened, stepSelectorToggled, timeSelectionChanged, - metricsSlideoutMenuOpened, - dataTableColumnOrderChanged, - dataTableColumnToggled, } from '../../actions'; import {PluginType} from '../../data_source'; import { @@ -104,6 +127,7 @@ import { provideMockCardRunToSeriesData, } from '../../testing'; import {TooltipSort, XAxisType} from '../../types'; +import * as commonSelectors from '../main_view/common_selectors'; import {ScalarCardComponent} from './scalar_card_component'; import {ScalarCardContainer} from './scalar_card_container'; import {ScalarCardDataTable} from './scalar_card_data_table'; @@ -113,32 +137,10 @@ import { ScalarCardSeriesMetadata, SeriesType, } from './scalar_card_types'; -import { - AddColumnEvent, - ColumnHeader, - ColumnHeaderType, - DataTableMode, - DomainType, - FilterAddedEvent, - IntervalFilter, - ReorderColumnEvent, - Side, - SortingOrder, -} from '../../../widgets/data_table/types'; import {VisLinkedTimeSelectionWarningModule} from './vis_linked_time_selection_warning_module'; -import {Extent} from '../../../widgets/line_chart_v2/lib/public_types'; -import {provideMockTbStore} from '../../../testing/utils'; -import * as commonSelectors from '../main_view/common_selectors'; -import {ContentCellComponent} from '../../../widgets/data_table/content_cell_component'; -import {ContentRowComponent} from '../../../widgets/data_table/content_row_component'; -import {HeaderCellComponent} from '../../../widgets/data_table/header_cell_component'; -import {HparamFilter} from '../../../hparams/_redux/types'; -import * as hparamsSelectors from '../../../hparams/_redux/hparams_selectors'; -import * as hparamsActions from '../../../hparams/_redux/hparams_actions'; -import * as runsSelectors from '../../../runs/store/runs_selectors'; -import {getIsScalarColumnContextMenusEnabled} from '../../../selectors'; @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'line-chart', template: ` @@ -223,6 +225,7 @@ class TestableLineChart { // DataDownloadContainer pulls in entire redux and, for this test, we don't want to // know about their data requirements. @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'testable-data-download-dialog', template: `{{ cardId }}`, diff --git a/tensorboard/webapp/metrics/views/main_view/BUILD b/tensorboard/webapp/metrics/views/main_view/BUILD index d06a7865781..8a431f5c3db 100644 --- a/tensorboard/webapp/metrics/views/main_view/BUILD +++ b/tensorboard/webapp/metrics/views/main_view/BUILD @@ -1,66 +1,74 @@ -load("//tensorboard/defs:defs.bzl", "tf_ng_module", "tf_sass_binary", "tf_ts_library") +load("@io_bazel_rules_sass//:defs.bzl", "sass_binary") +load("//tensorboard/defs:defs.bzl", "tf_ng_module", "tf_ts_library") package(default_visibility = ["//tensorboard:internal"]) -tf_sass_binary( +sass_binary( name = "main_view_styles", src = "main_view_component.scss", + include_paths = ["external/npm/node_modules"], deps = [ - "//tensorboard/webapp:angular_material_sass_deps", + "//tensorboard/webapp/angular_components:material_sass", "//tensorboard/webapp/metrics/views:metrics_common_styles", "//tensorboard/webapp/theme", ], ) -tf_sass_binary( +sass_binary( name = "filter_input_component_styles", src = "filter_input_component.scss", + include_paths = ["external/npm/node_modules"], deps = [ - "//tensorboard/webapp:angular_material_sass_deps", + "//tensorboard/webapp/angular_components:material_sass", "//tensorboard/webapp/theme", ], ) -tf_sass_binary( +sass_binary( name = "filtered_view_component_styles", src = "filtered_view_component.scss", + include_paths = ["external/npm/node_modules"], deps = [ "//tensorboard/webapp/metrics/views:metrics_common_styles", "//tensorboard/webapp/theme", ], ) -tf_sass_binary( +sass_binary( name = "pinned_view_component_styles", src = "pinned_view_component.scss", + include_paths = ["external/npm/node_modules"], deps = [ - "//tensorboard/webapp:angular_material_sass_deps", + "//tensorboard/webapp/angular_components:material_sass", "//tensorboard/webapp/metrics/views:metrics_common_styles", "//tensorboard/webapp/theme", ], ) -tf_sass_binary( +sass_binary( name = "card_grid_component_styles", src = "card_grid_component.scss", + include_paths = ["external/npm/node_modules"], deps = [ "//tensorboard/webapp/metrics/views:metrics_common_styles", "//tensorboard/webapp/theme", ], ) -tf_sass_binary( +sass_binary( name = "card_groups_component_styles", src = "card_groups_component.scss", + include_paths = ["external/npm/node_modules"], deps = [ "//tensorboard/webapp/metrics/views:metrics_common_styles", "//tensorboard/webapp/theme", ], ) -tf_sass_binary( +sass_binary( name = "card_group_toolbar_component_styles", src = "card_group_toolbar_component.scss", + include_paths = ["external/npm/node_modules"], deps = [ "//tensorboard/webapp/metrics/views:metrics_common_styles", "//tensorboard/webapp/theme", diff --git a/tensorboard/webapp/metrics/views/main_view/card_grid_test.ts b/tensorboard/webapp/metrics/views/main_view/card_grid_test.ts index 5b01ed6bd0c..23704a1e6cd 100644 --- a/tensorboard/webapp/metrics/views/main_view/card_grid_test.ts +++ b/tensorboard/webapp/metrics/views/main_view/card_grid_test.ts @@ -14,6 +14,7 @@ limitations under the License. ==============================================================================*/ import {ScrollingModule} from '@angular/cdk/scrolling'; import { + ChangeDetectionStrategy, Component, EventEmitter, Input, @@ -48,6 +49,7 @@ import {CardGridContainer} from './card_grid_container'; const scrollElementHeight = 100; @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'testable-scrolling-container', template: ` @@ -82,7 +84,11 @@ class TestableScrollingContainer { /** * Stub 'card-view' component for ease of testing. */ -@Component({standalone: false, selector: 'card-view'}) +@Component({ + changeDetection: ChangeDetectionStrategy.Default, + standalone: false, + selector: 'card-view', +}) class TestableCardView { @Output() fullHeightChanged = new EventEmitter(); @Output() fullWidthChanged = new EventEmitter(); diff --git a/tensorboard/webapp/metrics/views/main_view/main_view_component.ts b/tensorboard/webapp/metrics/views/main_view/main_view_component.ts index 1ac764b3abc..3e09ab87d1d 100644 --- a/tensorboard/webapp/metrics/views/main_view/main_view_component.ts +++ b/tensorboard/webapp/metrics/views/main_view/main_view_component.ts @@ -17,18 +17,18 @@ import { Component, ElementRef, EventEmitter, - Input, Inject, + InjectionToken, + Input, + Optional, Output, Type, - Optional, - InjectionToken, } from '@angular/core'; import {PluginType} from '../../types'; import {CardObserver} from '../card_renderer/card_lazy_loader'; -export const SHARE_BUTTON_COMPONENT = new InjectionToken>( +export const SHARE_BUTTON_COMPONENT = new InjectionToken>( 'Customizable Share Button' ); @@ -62,7 +62,7 @@ export class MainViewComponent { private readonly host: ElementRef, @Optional() @Inject(SHARE_BUTTON_COMPONENT) - readonly customShareButton: Type + readonly customShareButton: Type ) { this.cardObserver = new CardObserver( this.host.nativeElement, diff --git a/tensorboard/webapp/metrics/views/main_view/main_view_test.ts b/tensorboard/webapp/metrics/views/main_view/main_view_test.ts index a871fae7207..3229b0cec39 100644 --- a/tensorboard/webapp/metrics/views/main_view/main_view_test.ts +++ b/tensorboard/webapp/metrics/views/main_view/main_view_test.ts @@ -13,6 +13,7 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ import { + ChangeDetectionStrategy, Component, DebugElement, Input, @@ -39,6 +40,7 @@ import { } from '../../../selectors'; import {selectors as settingsSelectors} from '../../../settings'; import {KeyType, sendKey, sendKeys} from '../../../testing/dom'; +import {buildMockState} from '../../../testing/utils'; import {DataLoadState} from '../../../types/data'; import {RunColorScale} from '../../../types/ui'; import * as actions from '../../actions'; @@ -53,25 +55,25 @@ import {CardLazyLoader, CardObserver} from '../card_renderer/card_lazy_loader'; import {CardIdWithMetadata} from '../metrics_view_types'; import {CardGridComponent} from './card_grid_component'; import {CardGridContainer} from './card_grid_container'; -import {CardGroupsComponent} from './card_groups_component'; -import {CardGroupsContainer} from './card_groups_container'; import {CardGroupToolBarComponent} from './card_group_toolbar_component'; import {CardGroupToolBarContainer} from './card_group_toolbar_container'; +import {CardGroupsComponent} from './card_groups_component'; +import {CardGroupsContainer} from './card_groups_container'; import * as common_selectors from './common_selectors'; import {EmptyTagMatchMessageComponent} from './empty_tag_match_message_component'; import {EmptyTagMatchMessageContainer} from './empty_tag_match_message_container'; import {FilteredViewComponent} from './filtered_view_component'; import { - FilteredViewContainer, FILTER_VIEW_DEBOUNCE_IN_MS, + FilteredViewContainer, } from './filtered_view_container'; import {MainViewComponent, SHARE_BUTTON_COMPONENT} from './main_view_component'; import {MainViewContainer} from './main_view_container'; import {PinnedViewComponent} from './pinned_view_component'; import {PinnedViewContainer} from './pinned_view_container'; -import {buildMockState} from '../../../testing/utils'; @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'card-view', template: `{{ pluginType }}: {{ cardId }}`, @@ -83,6 +85,7 @@ class TestableCard { } @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'test-share-button', template: ``, diff --git a/tensorboard/webapp/metrics/views/right_pane/BUILD b/tensorboard/webapp/metrics/views/right_pane/BUILD index 2c6c21901e8..82fc761be11 100644 --- a/tensorboard/webapp/metrics/views/right_pane/BUILD +++ b/tensorboard/webapp/metrics/views/right_pane/BUILD @@ -1,21 +1,24 @@ -load("//tensorboard/defs:defs.bzl", "tf_ng_module", "tf_sass_binary", "tf_ts_library") +load("@io_bazel_rules_sass//:defs.bzl", "sass_binary") +load("//tensorboard/defs:defs.bzl", "tf_ng_module", "tf_ts_library") package(default_visibility = ["//tensorboard:internal"]) -tf_sass_binary( +sass_binary( name = "settings_view_styles", src = "settings_view_component.scss", + include_paths = ["external/npm/node_modules"], deps = [ - "//tensorboard/webapp:angular_material_sass_deps", + "//tensorboard/webapp/angular_components:material_sass", "//tensorboard/webapp/theme", ], ) -tf_sass_binary( +sass_binary( name = "saving_pins_checkbox_styles", src = "saving_pins_checkbox_component.scss", + include_paths = ["external/npm/node_modules"], deps = [ - "//tensorboard/webapp:angular_material_sass_deps", + "//tensorboard/webapp/angular_components:material_sass", "//tensorboard/webapp/theme", ], ) diff --git a/tensorboard/webapp/metrics/views/right_pane/saving_pins_dialog/BUILD b/tensorboard/webapp/metrics/views/right_pane/saving_pins_dialog/BUILD index 540bcff6a82..b2aa6e283a4 100644 --- a/tensorboard/webapp/metrics/views/right_pane/saving_pins_dialog/BUILD +++ b/tensorboard/webapp/metrics/views/right_pane/saving_pins_dialog/BUILD @@ -1,10 +1,12 @@ -load("//tensorboard/defs:defs.bzl", "tf_ng_module", "tf_sass_binary", "tf_ts_library") +load("@io_bazel_rules_sass//:defs.bzl", "sass_binary") +load("//tensorboard/defs:defs.bzl", "tf_ng_module", "tf_ts_library") package(default_visibility = ["//tensorboard:internal"]) -tf_sass_binary( +sass_binary( name = "saving_pins_dialog_component_styles", src = "saving_pins_dialog_component.scss", + include_paths = ["external/npm/node_modules"], ) tf_ng_module( diff --git a/tensorboard/webapp/metrics/views/right_pane/scalar_column_editor/BUILD b/tensorboard/webapp/metrics/views/right_pane/scalar_column_editor/BUILD index 66b5b13e31a..f2491619572 100644 --- a/tensorboard/webapp/metrics/views/right_pane/scalar_column_editor/BUILD +++ b/tensorboard/webapp/metrics/views/right_pane/scalar_column_editor/BUILD @@ -1,12 +1,14 @@ -load("//tensorboard/defs:defs.bzl", "tf_ng_module", "tf_sass_binary", "tf_ts_library") +load("@io_bazel_rules_sass//:defs.bzl", "sass_binary") +load("//tensorboard/defs:defs.bzl", "tf_ng_module", "tf_ts_library") package(default_visibility = ["//tensorboard:internal"]) -tf_sass_binary( +sass_binary( name = "scalar_column_editor_styles", src = "scalar_column_editor_component.scss", + include_paths = ["external/npm/node_modules"], deps = [ - "//tensorboard/webapp:angular_material_sass_deps", + "//tensorboard/webapp/angular_components:material_sass", "//tensorboard/webapp/theme", ], ) diff --git a/tensorboard/webapp/metrics/views/right_pane/scalar_column_editor/scalar_column_editor_test.ts b/tensorboard/webapp/metrics/views/right_pane/scalar_column_editor/scalar_column_editor_test.ts index d8c781b78dd..287c7466064 100644 --- a/tensorboard/webapp/metrics/views/right_pane/scalar_column_editor/scalar_column_editor_test.ts +++ b/tensorboard/webapp/metrics/views/right_pane/scalar_column_editor/scalar_column_editor_test.ts @@ -236,9 +236,12 @@ describe('scalar column editor', () => { let dispatchedActions: Action[] = []; beforeEach(() => { dispatchedActions = []; - spyOn(store, 'dispatch').and.callFake((action: Action) => { - dispatchedActions.push(action); - }); + // Cast to jasmine.Spy for compatibility between NgRx dispatch signature overloads. + (spyOn(store, 'dispatch') as jasmine.Spy).and.callFake( + (action: Action) => { + dispatchedActions.push(action); + } + ); }); it('dispatches dataTableColumnToggled action with singe selection when checkbox is clicked', fakeAsync(() => { @@ -320,9 +323,12 @@ describe('scalar column editor', () => { let dispatchedActions: Action[] = []; beforeEach(() => { dispatchedActions = []; - spyOn(store, 'dispatch').and.callFake((action: Action) => { - dispatchedActions.push(action); - }); + // Cast to jasmine.Spy for compatibility between NgRx dispatch signature overloads. + (spyOn(store, 'dispatch') as jasmine.Spy).and.callFake( + (action: Action) => { + dispatchedActions.push(action); + } + ); }); it('dispatches dataTableColumnOrderChanged action with single selection when header is dragged', fakeAsync(() => { @@ -508,9 +514,12 @@ describe('scalar column editor', () => { let dispatchedActions: Action[] = []; beforeEach(() => { dispatchedActions = []; - spyOn(store, 'dispatch').and.callFake((action: Action) => { - dispatchedActions.push(action); - }); + // Cast to jasmine.Spy for compatibility between NgRx dispatch signature overloads. + (spyOn(store, 'dispatch') as jasmine.Spy).and.callFake( + (action: Action) => { + dispatchedActions.push(action); + } + ); }); it('dispatches metricsSlideoutMenuClosed', () => { const fixture = createComponent(); @@ -527,9 +536,12 @@ describe('scalar column editor', () => { let dispatchedActions: Action[] = []; beforeEach(() => { dispatchedActions = []; - spyOn(store, 'dispatch').and.callFake((action: Action) => { - dispatchedActions.push(action); - }); + // Cast to jasmine.Spy for compatibility between NgRx dispatch signature overloads. + (spyOn(store, 'dispatch') as jasmine.Spy).and.callFake( + (action: Action) => { + dispatchedActions.push(action); + } + ); }); it('dispatches tableEditorTabChanged action when tab is clicked', fakeAsync(() => { const fixture = createComponent(); diff --git a/tensorboard/webapp/notification_center/_redux/notification_center_effects_test.ts b/tensorboard/webapp/notification_center/_redux/notification_center_effects_test.ts index 5c0c3d1b5f9..a468ca77c02 100644 --- a/tensorboard/webapp/notification_center/_redux/notification_center_effects_test.ts +++ b/tensorboard/webapp/notification_center/_redux/notification_center_effects_test.ts @@ -60,7 +60,8 @@ describe('notification center effects', () => { }).compileComponents(); store = TestBed.inject>(Store) as MockStore; - spyOn(store, 'dispatch').and.callFake((action: Action) => { + // Cast to jasmine.Spy for compatibility between NgRx dispatch signature overloads. + (spyOn(store, 'dispatch') as jasmine.Spy).and.callFake((action: Action) => { actualActions.push(action); }); effects = TestBed.inject(NotificationCenterEffects); @@ -96,7 +97,7 @@ describe('notification center effects', () => { it('dispatches failed action when notification fetch failed', () => { fetchNotificationsSpy.and.returnValue( - throwError(new Error('Request failed')) + throwError(() => new Error('Request failed')) ); actions$.next(TEST_ONLY.initAction()); diff --git a/tensorboard/webapp/notification_center/_views/BUILD b/tensorboard/webapp/notification_center/_views/BUILD index da3a90082e6..d8b4fe2ad68 100644 --- a/tensorboard/webapp/notification_center/_views/BUILD +++ b/tensorboard/webapp/notification_center/_views/BUILD @@ -1,14 +1,16 @@ -load("//tensorboard/defs:defs.bzl", "tf_ng_module", "tf_sass_binary", "tf_ts_library") +load("@io_bazel_rules_sass//:defs.bzl", "sass_binary") +load("//tensorboard/defs:defs.bzl", "tf_ng_module", "tf_ts_library") package(default_visibility = ["//tensorboard/webapp/notification_center:__subpackages__"]) licenses(["notice"]) -tf_sass_binary( +sass_binary( name = "notification_center_styles", src = "notification_center_component.scss", + include_paths = ["external/npm/node_modules"], deps = [ - "//tensorboard/webapp:angular_material_sass_deps", + "//tensorboard/webapp/angular_components:material_sass", "//tensorboard/webapp/theme", ], ) diff --git a/tensorboard/webapp/notification_center/_views/notification_center_component.ts b/tensorboard/webapp/notification_center/_views/notification_center_component.ts index 093fd48ddf3..7585485be98 100644 --- a/tensorboard/webapp/notification_center/_views/notification_center_component.ts +++ b/tensorboard/webapp/notification_center/_views/notification_center_component.ts @@ -12,11 +12,18 @@ 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 {Component, EventEmitter, Input, Output} from '@angular/core'; +import { + ChangeDetectionStrategy, + Component, + EventEmitter, + Input, + Output, +} from '@angular/core'; import {CategoryEnum} from '../_redux/notification_center_types'; import {ViewNotificationExt} from './view_types'; @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'notification-center-component', templateUrl: './notification_center_component.ng.html', diff --git a/tensorboard/webapp/notification_center/_views/notification_center_container.ts b/tensorboard/webapp/notification_center/_views/notification_center_container.ts index 2d8bbb25a10..94fb9ee783f 100644 --- a/tensorboard/webapp/notification_center/_views/notification_center_container.ts +++ b/tensorboard/webapp/notification_center/_views/notification_center_container.ts @@ -12,7 +12,7 @@ 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 {Component} from '@angular/core'; +import {ChangeDetectionStrategy, Component} from '@angular/core'; import {Store} from '@ngrx/store'; import {combineLatest, Observable} from 'rxjs'; import {map, shareReplay} from 'rxjs/operators'; @@ -28,6 +28,7 @@ import {ViewNotificationExt} from './view_types'; const iconMap = new Map([[CategoryEnum.WHATS_NEW, 'info_outline_24px']]); @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'notification-center', template: ` diff --git a/tensorboard/webapp/notification_center/_views/notification_center_test.ts b/tensorboard/webapp/notification_center/_views/notification_center_test.ts index c8277479e9c..adb4369c44b 100644 --- a/tensorboard/webapp/notification_center/_views/notification_center_test.ts +++ b/tensorboard/webapp/notification_center/_views/notification_center_test.ts @@ -52,7 +52,8 @@ describe('notification center', () => { }).compileComponents(); store = TestBed.inject>(Store) as MockStore; recordedActions = []; - spyOn(store, 'dispatch').and.callFake((action: Action) => { + // Cast to jasmine.Spy for compatibility between NgRx dispatch signature overloads. + (spyOn(store, 'dispatch') as jasmine.Spy).and.callFake((action: Action) => { recordedActions.push(action); }); store.overrideSelector(selectors.getNotifications, []); diff --git a/tensorboard/webapp/persistent_settings/_redux/persistent_settings_effects_test.ts b/tensorboard/webapp/persistent_settings/_redux/persistent_settings_effects_test.ts index ea6c6eb10e3..46d490eb4fd 100644 --- a/tensorboard/webapp/persistent_settings/_redux/persistent_settings_effects_test.ts +++ b/tensorboard/webapp/persistent_settings/_redux/persistent_settings_effects_test.ts @@ -78,9 +78,12 @@ describe('persistent_settings effects test', () => { }).compileComponents(); store = TestBed.inject>(Store) as MockStore; - dispatchSpy = spyOn(store, 'dispatch').and.callFake((action: Action) => { - actualActions.push(action); - }); + // Cast to jasmine.Spy for compatibility between NgRx dispatch signature overloads. + dispatchSpy = (spyOn(store, 'dispatch') as jasmine.Spy).and.callFake( + (action: Action) => { + actualActions.push(action); + } + ); effects = TestBed.inject(PersistentSettingsEffects); const dataSource = TestBed.inject(PersistentSettingsTestingDataSource); getSettingsSpy = spyOn(dataSource, 'getSettings').and.returnValue(of({})); diff --git a/tensorboard/webapp/plugins/BUILD b/tensorboard/webapp/plugins/BUILD index ef34c03baf8..00e30c96825 100644 --- a/tensorboard/webapp/plugins/BUILD +++ b/tensorboard/webapp/plugins/BUILD @@ -1,12 +1,14 @@ -load("//tensorboard/defs:defs.bzl", "tf_ng_module", "tf_sass_binary", "tf_ts_library") +load("@io_bazel_rules_sass//:defs.bzl", "sass_binary") +load("//tensorboard/defs:defs.bzl", "tf_ng_module", "tf_ts_library") package(default_visibility = ["//tensorboard:internal"]) licenses(["notice"]) -tf_sass_binary( +sass_binary( name = "plugins_component_styles", src = "plugins_component.scss", + include_paths = ["external/npm/node_modules"], deps = ["//tensorboard/webapp/theme"], ) diff --git a/tensorboard/webapp/plugins/plugin_registry_module.ts b/tensorboard/webapp/plugins/plugin_registry_module.ts index f9ce7850dad..f7901ae7ac7 100644 --- a/tensorboard/webapp/plugins/plugin_registry_module.ts +++ b/tensorboard/webapp/plugins/plugin_registry_module.ts @@ -13,16 +13,15 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ import { - Component, Inject, ModuleWithProviders, NgModule, Optional, Type, } from '@angular/core'; -import {PluginConfig, PLUGIN_CONFIG_TOKEN} from './plugin_registry_types'; +import {PLUGIN_CONFIG_TOKEN, PluginConfig} from './plugin_registry_types'; -const pluginNameToComponent = new Map>(); +const pluginNameToComponent = new Map>(); @NgModule({}) export class PluginRegistryModule { @@ -40,7 +39,7 @@ export class PluginRegistryModule { for (const config of configs) { const {pluginName, componentClass} = config; - pluginNameToComponent.set(pluginName, componentClass as Type); + pluginNameToComponent.set(pluginName, componentClass as Type); } } @@ -71,7 +70,7 @@ export class PluginRegistryModule { }; } - getComponent(pluginName: string): Type | null { + getComponent(pluginName: string): Type | null { return pluginNameToComponent.get(pluginName) || null; } } diff --git a/tensorboard/webapp/plugins/plugins_component.ts b/tensorboard/webapp/plugins/plugins_component.ts index 4f40d1d58bc..d697fdc24aa 100644 --- a/tensorboard/webapp/plugins/plugins_component.ts +++ b/tensorboard/webapp/plugins/plugins_component.ts @@ -37,8 +37,8 @@ import { LoadingMechanismType, } from '../types/api'; import {DataLoadState} from '../types/data'; -import {UiPluginMetadata} from './plugins_container'; import {PluginRegistryModule} from './plugin_registry_module'; +import {UiPluginMetadata} from './plugins_container'; interface PolymerDashboard extends HTMLElement { reload?: () => void; diff --git a/tensorboard/webapp/plugins/plugins_container_test.ts b/tensorboard/webapp/plugins/plugins_container_test.ts index bbbe4172ee8..9c588d02e3c 100644 --- a/tensorboard/webapp/plugins/plugins_container_test.ts +++ b/tensorboard/webapp/plugins/plugins_container_test.ts @@ -12,7 +12,7 @@ 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 {Component} from '@angular/core'; +import {ChangeDetectionStrategy, Component} from '@angular/core'; import {TestBed} from '@angular/core/testing'; import {By} from '@angular/platform-browser'; import {Store} from '@ngrx/store'; @@ -47,9 +47,9 @@ import { PluginId, } from '../types/api'; import {DataLoadState} from '../types/data'; +import {PluginRegistryModule} from './plugin_registry_module'; import {PluginsComponent} from './plugins_component'; import {PluginsContainer} from './plugins_container'; -import {PluginRegistryModule} from './plugin_registry_module'; import {ExtraDashboardModule} from './testing'; function expectPluginIframe(element: HTMLElement, name: string) { @@ -64,6 +64,7 @@ function expectPluginIframe(element: HTMLElement, name: string) { * the `plugins` component. */ @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, template: ` diff --git a/tensorboard/webapp/plugins/testing/index.ts b/tensorboard/webapp/plugins/testing/index.ts index 78807d8a617..f6cd1980816 100644 --- a/tensorboard/webapp/plugins/testing/index.ts +++ b/tensorboard/webapp/plugins/testing/index.ts @@ -12,10 +12,11 @@ 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 {Component, NgModule} from '@angular/core'; +import {ChangeDetectionStrategy, Component, NgModule} from '@angular/core'; import {PluginRegistryModule} from '../plugin_registry_module'; @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'extra-dashboard', template: `
I'm the extra Angular dashboard!
`, diff --git a/tensorboard/webapp/routes/index.ts b/tensorboard/webapp/routes/index.ts index 4ee5ad19416..dfa03d2cfbc 100644 --- a/tensorboard/webapp/routes/index.ts +++ b/tensorboard/webapp/routes/index.ts @@ -12,7 +12,7 @@ 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 {Component, Type} from '@angular/core'; +import {Type} from '@angular/core'; import {RouteDef} from '../app_routing/route_config_types'; import {RouteKind} from '../app_routing/types'; import {TensorBoardWrapperComponent} from '../tb_wrapper/tb_wrapper_component'; @@ -23,7 +23,7 @@ export function routesFactory(): RouteDef[] { { routeKind: RouteKind.EXPERIMENT, path: '/', - ngComponent: TensorBoardWrapperComponent as Type, + ngComponent: TensorBoardWrapperComponent as Type, defaultRoute: true, deepLinkProvider: new DashboardDeepLinkProvider(), }, diff --git a/tensorboard/webapp/runs/effects/runs_effects_test.ts b/tensorboard/webapp/runs/effects/runs_effects_test.ts index fccad4c6ba0..1971cfe0347 100644 --- a/tensorboard/webapp/runs/effects/runs_effects_test.ts +++ b/tensorboard/webapp/runs/effects/runs_effects_test.ts @@ -91,7 +91,8 @@ describe('runs_effects', () => { selectSpy = spyOn(store, 'select').and.callThrough(); actualActions = []; - spyOn(store, 'dispatch').and.callFake((action: Action) => { + // Cast to jasmine.Spy for compatibility between NgRx dispatch signature overloads. + (spyOn(store, 'dispatch') as jasmine.Spy).and.callFake((action: Action) => { actualActions.push(action); }); effects = TestBed.inject(RunsEffects); diff --git a/tensorboard/webapp/runs/views/runs_table/BUILD b/tensorboard/webapp/runs/views/runs_table/BUILD index 75f47fe218f..fb6ec4fcb89 100644 --- a/tensorboard/webapp/runs/views/runs_table/BUILD +++ b/tensorboard/webapp/runs/views/runs_table/BUILD @@ -1,35 +1,40 @@ -load("//tensorboard/defs:defs.bzl", "tf_ng_module", "tf_sass_binary", "tf_ts_library") +load("@io_bazel_rules_sass//:defs.bzl", "sass_binary") +load("//tensorboard/defs:defs.bzl", "tf_ng_module", "tf_ts_library") package(default_visibility = ["//tensorboard:internal"]) licenses(["notice"]) -tf_sass_binary( +sass_binary( name = "runs_group_menu_button_styles", src = "runs_group_menu_button_component.scss", + include_paths = ["external/npm/node_modules"], deps = [ - "//tensorboard/webapp:angular_material_sass_deps", + "//tensorboard/webapp/angular_components:material_sass", "//tensorboard/webapp/theme", ], ) -tf_sass_binary( +sass_binary( name = "regex_edit_dialog_styles", src = "regex_edit_dialog_component.scss", + include_paths = ["external/npm/node_modules"], deps = ["//tensorboard/webapp/theme"], ) -tf_sass_binary( +sass_binary( name = "filterbar_styles", src = "filterbar_component.scss", + include_paths = ["external/npm/node_modules"], deps = ["//tensorboard/webapp/theme"], ) -tf_sass_binary( +sass_binary( name = "runs_data_table_styles", src = "runs_data_table.scss", + include_paths = ["external/npm/node_modules"], deps = [ - "//tensorboard/webapp:angular_material_sass_deps", + "//tensorboard/webapp/angular_components:material_sass", "//tensorboard/webapp/theme", ], ) diff --git a/tensorboard/webapp/runs/views/runs_table/filterbar_test.ts b/tensorboard/webapp/runs/views/runs_table/filterbar_test.ts index c4b97d348da..0998b131bb5 100644 --- a/tensorboard/webapp/runs/views/runs_table/filterbar_test.ts +++ b/tensorboard/webapp/runs/views/runs_table/filterbar_test.ts @@ -12,32 +12,36 @@ 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 {TestbedHarnessEnvironment} from '@angular/cdk/testing/testbed'; +import { + ChangeDetectionStrategy, + Component, + NO_ERRORS_SCHEMA, +} from '@angular/core'; import {ComponentFixture, TestBed} from '@angular/core/testing'; -import {Component, NO_ERRORS_SCHEMA} from '@angular/core'; -import {FilterbarComponent} from './filterbar_component'; -import {FilterbarContainer} from './filterbar_container'; +import {MatChipRemove, MatChipsModule} from '@angular/material/chips'; +import {MatChipHarness} from '@angular/material/chips/testing'; +import {By} from '@angular/platform-browser'; import {NoopAnimationsModule} from '@angular/platform-browser/animations'; -import {provideMockTbStore} from '../../../testing/utils'; +import {Action, Store} from '@ngrx/store'; import {MockStore} from '@ngrx/store/testing'; import {State} from '../../../app_state'; -import {Action, Store} from '@ngrx/store'; -import {By} from '@angular/platform-browser'; import { actions as hparamsActions, selectors as hparamsSelectors, } from '../../../hparams'; +import {MatIconTestingModule} from '../../../testing/mat_icon_module'; +import {provideMockTbStore} from '../../../testing/utils'; +import {CustomModal} from '../../../widgets/custom_modal/custom_modal'; +import {FilterDialog} from '../../../widgets/data_table/filter_dialog_component'; +import {FilterDialogModule} from '../../../widgets/data_table/filter_dialog_module'; import { + DiscreteFilter, DomainType, IntervalFilter, - DiscreteFilter, } from '../../../widgets/data_table/types'; -import {MatChipHarness} from '@angular/material/chips/testing'; -import {TestbedHarnessEnvironment} from '@angular/cdk/testing/testbed'; -import {MatChipRemove, MatChipsModule} from '@angular/material/chips'; -import {MatIconTestingModule} from '../../../testing/mat_icon_module'; -import {FilterDialogModule} from '../../../widgets/data_table/filter_dialog_module'; -import {FilterDialog} from '../../../widgets/data_table/filter_dialog_component'; -import {CustomModal} from '../../../widgets/custom_modal/custom_modal'; +import {FilterbarComponent} from './filterbar_component'; +import {FilterbarContainer} from './filterbar_container'; const discreteFilter: DiscreteFilter = { type: DomainType.DISCRETE, @@ -61,6 +65,7 @@ const fakeFilterMap = new Map([ ]); @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'testable-component', template: ` `, @@ -95,9 +100,12 @@ describe('hparam_filterbar', () => { function createComponent(): ComponentFixture { store = TestBed.inject>(Store) as MockStore; actualActions = []; - dispatchSpy = spyOn(store, 'dispatch').and.callFake((action: Action) => { - actualActions.push(action); - }); + // Cast to jasmine.Spy for compatibility between NgRx dispatch signature overloads. + dispatchSpy = (spyOn(store, 'dispatch') as jasmine.Spy).and.callFake( + (action: Action) => { + actualActions.push(action); + } + ); const fixture = TestBed.createComponent(TestableComponent); return fixture; diff --git a/tensorboard/webapp/runs/views/runs_table/regex_edit_dialog_container.ts b/tensorboard/webapp/runs/views/runs_table/regex_edit_dialog_container.ts index eb267417c7d..d0eb31bb0e1 100644 --- a/tensorboard/webapp/runs/views/runs_table/regex_edit_dialog_container.ts +++ b/tensorboard/webapp/runs/views/runs_table/regex_edit_dialog_container.ts @@ -12,8 +12,8 @@ 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 {Component, inject} from '@angular/core'; -import {MatDialogRef, MAT_DIALOG_DATA} from '@angular/material/dialog'; +import {ChangeDetectionStrategy, Component, inject} from '@angular/core'; +import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; import {Store} from '@ngrx/store'; import {combineLatest, defer, merge, Observable, Subject} from 'rxjs'; import { @@ -28,17 +28,17 @@ import { import {State} from '../../../app_state'; import { getDarkModeEnabled, + getDashboardExperimentNames, getEnableColorByExperiment, } from '../../../selectors'; import {selectors as settingsSelectors} from '../../../settings/'; import {runGroupByChanged} from '../../actions'; import { getColorGroupRegexString, - getRunIdsForExperiment, getRunGroupBy, + getRunIdsForExperiment, getRuns, } from '../../store/runs_selectors'; -import {getDashboardExperimentNames} from '../../../selectors'; import {groupRuns} from '../../store/utils'; import {GroupByKey, Run} from '../../types'; import {ColorGroup} from './regex_edit_dialog_component'; @@ -46,6 +46,7 @@ import {ColorGroup} from './regex_edit_dialog_component'; const INPUT_CHANGE_DEBOUNCE_INTERVAL_MS = 500; @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'regex-edit-dialog', template: ` { }); store.overrideSelector(getEnableColorByExperiment, true); actualActions = []; - dispatchSpy = spyOn(store, 'dispatch').and.callFake((action: Action) => { - actualActions.push(action); - }); + // Cast to jasmine.Spy for compatibility between NgRx dispatch signature overloads. + dispatchSpy = (spyOn(store, 'dispatch') as jasmine.Spy).and.callFake( + (action: Action) => { + actualActions.push(action); + } + ); return TestBed.createComponent(RegexEditDialogContainer); } diff --git a/tensorboard/webapp/runs/views/runs_table/runs_data_table_test.ts b/tensorboard/webapp/runs/views/runs_table/runs_data_table_test.ts index b266c1dce84..0c778530db1 100644 --- a/tensorboard/webapp/runs/views/runs_table/runs_data_table_test.ts +++ b/tensorboard/webapp/runs/views/runs_table/runs_data_table_test.ts @@ -13,27 +13,34 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -import {Component, Input, NO_ERRORS_SCHEMA, ViewChild} from '@angular/core'; +import { + ChangeDetectionStrategy, + Component, + Input, + NO_ERRORS_SCHEMA, + ViewChild, +} from '@angular/core'; import {TestBed} from '@angular/core/testing'; -import {RunsDataTable} from './runs_data_table'; -import {DataTableModule} from '../../../widgets/data_table/data_table_module'; -import {MatIconTestingModule} from '../../../testing/mat_icon_module'; import {MatCheckboxModule} from '@angular/material/checkbox'; +import {By} from '@angular/platform-browser'; +import {sendKeys} from '../../../testing/dom'; +import {MatIconTestingModule} from '../../../testing/mat_icon_module'; +import {ContentCellComponent} from '../../../widgets/data_table/content_cell_component'; +import {DataTableComponent} from '../../../widgets/data_table/data_table_component'; +import {DataTableModule} from '../../../widgets/data_table/data_table_module'; +import {HeaderCellComponent} from '../../../widgets/data_table/header_cell_component'; import { - SortingOrder, - SortingInfo, - TableData, ColumnHeader, ColumnHeaderType, + SortingInfo, + SortingOrder, + TableData, } from '../../../widgets/data_table/types'; -import {By} from '@angular/platform-browser'; -import {HeaderCellComponent} from '../../../widgets/data_table/header_cell_component'; -import {DataTableComponent} from '../../../widgets/data_table/data_table_component'; -import {ContentCellComponent} from '../../../widgets/data_table/content_cell_component'; import {FilterInputModule} from '../../../widgets/filter_input/filter_input_module'; -import {sendKeys} from '../../../testing/dom'; +import {RunsDataTable} from './runs_data_table'; @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'testable-comp', template: ` diff --git a/tensorboard/webapp/runs_legacy/views/legacy_runs_selector/legacy_runs_selector_component.ts b/tensorboard/webapp/runs_legacy/views/legacy_runs_selector/legacy_runs_selector_component.ts index abbf82ee047..c9c61f3f1f3 100644 --- a/tensorboard/webapp/runs_legacy/views/legacy_runs_selector/legacy_runs_selector_component.ts +++ b/tensorboard/webapp/runs_legacy/views/legacy_runs_selector/legacy_runs_selector_component.ts @@ -14,6 +14,7 @@ limitations under the License. ==============================================================================*/ import { AfterViewInit, + ChangeDetectionStrategy, Component, ElementRef, EventEmitter, @@ -26,6 +27,7 @@ interface PolymerChangeEvent extends CustomEvent { } @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'tb-legacy-runs-selector-component', template: ` `, diff --git a/tensorboard/webapp/runs_legacy/views/legacy_runs_selector/legacy_runs_selector_container.ts b/tensorboard/webapp/runs_legacy/views/legacy_runs_selector/legacy_runs_selector_container.ts index 05fd8d92ec8..fc3b0436fb8 100644 --- a/tensorboard/webapp/runs_legacy/views/legacy_runs_selector/legacy_runs_selector_container.ts +++ b/tensorboard/webapp/runs_legacy/views/legacy_runs_selector/legacy_runs_selector_container.ts @@ -12,12 +12,13 @@ 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 {Component} from '@angular/core'; +import {ChangeDetectionStrategy, Component} from '@angular/core'; import {Store} from '@ngrx/store'; import {State} from '../../../app_state'; import {polymerInteropRunSelectionChanged} from '../../../core/actions'; @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'tb-legacy-runs-selector', template: ` diff --git a/tensorboard/webapp/runs_legacy/views/legacy_runs_selector/legacy_runs_selector_test.ts b/tensorboard/webapp/runs_legacy/views/legacy_runs_selector/legacy_runs_selector_test.ts index c5cfb870fb4..64ecc144dff 100644 --- a/tensorboard/webapp/runs_legacy/views/legacy_runs_selector/legacy_runs_selector_test.ts +++ b/tensorboard/webapp/runs_legacy/views/legacy_runs_selector/legacy_runs_selector_test.ts @@ -43,7 +43,8 @@ describe('legacy_runs_selector test', () => { store = TestBed.inject>(Store) as MockStore; recordedActions = []; - spyOn(store, 'dispatch').and.callFake((action: Action) => { + // Cast to jasmine.Spy for compatibility between NgRx dispatch signature overloads. + (spyOn(store, 'dispatch') as jasmine.Spy).and.callFake((action: Action) => { recordedActions.push(action); }); diff --git a/tensorboard/webapp/settings/_views/settings_button_component.ts b/tensorboard/webapp/settings/_views/settings_button_component.ts index 4e65ce97328..3a56cf35294 100644 --- a/tensorboard/webapp/settings/_views/settings_button_component.ts +++ b/tensorboard/webapp/settings/_views/settings_button_component.ts @@ -12,12 +12,13 @@ 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 {Component, Input} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input} from '@angular/core'; import {MatDialog} from '@angular/material/dialog'; import {DataLoadState} from '../../types/data'; import {SettingsDialogContainer} from './settings_dialog_container'; @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'settings-button-component', template: ` diff --git a/tensorboard/webapp/settings/_views/settings_button_container.ts b/tensorboard/webapp/settings/_views/settings_button_container.ts index 83ec77f7bee..b938b0ad20d 100644 --- a/tensorboard/webapp/settings/_views/settings_button_container.ts +++ b/tensorboard/webapp/settings/_views/settings_button_container.ts @@ -12,12 +12,13 @@ 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 {Component} from '@angular/core'; +import {ChangeDetectionStrategy, Component} from '@angular/core'; import {Store} from '@ngrx/store'; import {getSettingsLoadState} from '../_redux/settings_selectors'; import {State} from '../_redux/settings_types'; @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'settings-button', template: ` diff --git a/tensorboard/webapp/settings/_views/settings_dialog_component.ts b/tensorboard/webapp/settings/_views/settings_dialog_component.ts index 86f05043475..4b97c0da11a 100644 --- a/tensorboard/webapp/settings/_views/settings_dialog_component.ts +++ b/tensorboard/webapp/settings/_views/settings_dialog_component.ts @@ -13,6 +13,7 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ import { + ChangeDetectionStrategy, Component, EventEmitter, Input, @@ -41,6 +42,7 @@ export function createIntegerValidator(): ValidatorFn { } @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'settings-dialog-component', templateUrl: 'settings_dialog_component.ng.html', diff --git a/tensorboard/webapp/settings/_views/settings_dialog_container.ts b/tensorboard/webapp/settings/_views/settings_dialog_container.ts index 85ea32cf808..6ebd189c880 100644 --- a/tensorboard/webapp/settings/_views/settings_dialog_container.ts +++ b/tensorboard/webapp/settings/_views/settings_dialog_container.ts @@ -12,7 +12,7 @@ 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 {Component} from '@angular/core'; +import {ChangeDetectionStrategy, Component} from '@angular/core'; import {Store} from '@ngrx/store'; import { changePageSize, @@ -27,6 +27,7 @@ import { import {State} from '../_redux/settings_types'; @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'settings-dialog', template: ` diff --git a/tensorboard/webapp/testing/integration_test_module.ts b/tensorboard/webapp/testing/integration_test_module.ts index 3aca9baff3a..585403d7fd1 100644 --- a/tensorboard/webapp/testing/integration_test_module.ts +++ b/tensorboard/webapp/testing/integration_test_module.ts @@ -17,7 +17,7 @@ limitations under the License. * * This module does not facilitate any screenshot testing. */ -import {Component, NgModule} from '@angular/core'; +import {ChangeDetectionStrategy, Component, NgModule} from '@angular/core'; import {EffectsModule as NgrxEffectsModule} from '@ngrx/effects'; import {StoreModule as NgrxStoreModule} from '@ngrx/store'; import {AppRoutingModule} from '../app_routing/app_routing_module'; @@ -31,6 +31,7 @@ import {RunsModule} from '../runs/runs_module'; import {MatIconTestingModule} from './mat_icon_module'; @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'test', template: 'hello', diff --git a/tensorboard/webapp/testing/mat_icon_module.ts b/tensorboard/webapp/testing/mat_icon_module.ts index c37a7f36260..caa12707c95 100644 --- a/tensorboard/webapp/testing/mat_icon_module.ts +++ b/tensorboard/webapp/testing/mat_icon_module.ts @@ -12,7 +12,12 @@ 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 {Component, Input, NgModule} from '@angular/core'; +import { + ChangeDetectionStrategy, + Component, + Input, + NgModule, +} from '@angular/core'; import {MatIconRegistry} from '@angular/material/icon'; import {FakeMatIconRegistry} from '@angular/material/icon/testing'; @@ -74,6 +79,7 @@ const KNOWN_SVG_ICON = new Set([ * compilation time due to unknown input onto the template. */ @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, template: '{{svgIcon}}', selector: 'mat-icon', diff --git a/tensorboard/webapp/theme/BUILD b/tensorboard/webapp/theme/BUILD index 6afa1682489..bb07a8ee7f9 100644 --- a/tensorboard/webapp/theme/BUILD +++ b/tensorboard/webapp/theme/BUILD @@ -1,17 +1,17 @@ -load("//tensorboard/defs:defs.bzl", "tf_sass_library") +load("@io_bazel_rules_sass//:defs.bzl", "sass_library") package(default_visibility = ["//tensorboard:internal"]) licenses(["notice"]) -tf_sass_library( +sass_library( name = "theme", srcs = [ "_tb_palette.scss", "_tb_theme.scss", ], deps = [ - "//tensorboard/webapp:angular_material_sass_deps", + "//tensorboard/webapp/angular_components:material_sass", ], ) diff --git a/tensorboard/webapp/theme/_tb_theme.template.scss b/tensorboard/webapp/theme/_tb_theme.template.scss index dcfd5327f42..b89d269a230 100644 --- a/tensorboard/webapp/theme/_tb_theme.template.scss +++ b/tensorboard/webapp/theme/_tb_theme.template.scss @@ -271,15 +271,10 @@ $tb-dark-theme: map_merge( // Apply themed style for the global stylesheet (styles.scss). @mixin tb-global-themed-styles() { - // TODO(JamesHollyer): remove legacy component themes once all components - // are migrated. @include mat.core(); - @include mat.all-legacy-component-typographies(); @include mat.all-component-typographies(); // Include all theme-styles for the components based on the current theme. @include mat.all-component-themes($tb-theme); - @include mat.all-legacy-component-themes($tb-theme); - @include mat.all-component-themes($tb-theme); body { // Prevents ngx-color-picker from creating a scrollbar and misposition. @@ -370,9 +365,6 @@ $tb-dark-theme: map_merge( } } - // TODO(JamesHollyer): remove legacy component themes once all components - // are migrated. @include mat.all-component-themes($tb-dark-theme); - @include mat.all-legacy-component-themes($tb-dark-theme); } } diff --git a/tensorboard/webapp/widgets/card_fob/BUILD b/tensorboard/webapp/widgets/card_fob/BUILD index b4a848ff6af..0308842955f 100644 --- a/tensorboard/webapp/widgets/card_fob/BUILD +++ b/tensorboard/webapp/widgets/card_fob/BUILD @@ -1,19 +1,22 @@ -load("//tensorboard/defs:defs.bzl", "tf_ng_module", "tf_sass_binary", "tf_ts_library") +load("@io_bazel_rules_sass//:defs.bzl", "sass_binary") +load("//tensorboard/defs:defs.bzl", "tf_ng_module", "tf_ts_library") package(default_visibility = ["//tensorboard:internal"]) -tf_sass_binary( +sass_binary( name = "card_fob_styles", src = "card_fob_component.scss", + include_paths = ["external/npm/node_modules"], deps = [ - "//tensorboard/webapp:angular_material_sass_deps", + "//tensorboard/webapp/angular_components:material_sass", "//tensorboard/webapp/theme", ], ) -tf_sass_binary( +sass_binary( name = "card_fob_controller_styles", src = "card_fob_controller_component.scss", + include_paths = ["external/npm/node_modules"], ) tf_ng_module( diff --git a/tensorboard/webapp/widgets/card_fob/card_fob_controller_test.ts b/tensorboard/webapp/widgets/card_fob/card_fob_controller_test.ts index 061cd095049..56eceb304c7 100644 --- a/tensorboard/webapp/widgets/card_fob/card_fob_controller_test.ts +++ b/tensorboard/webapp/widgets/card_fob/card_fob_controller_test.ts @@ -13,7 +13,13 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -import {Component, Input, NO_ERRORS_SCHEMA, ViewChild} from '@angular/core'; +import { + ChangeDetectionStrategy, + Component, + Input, + NO_ERRORS_SCHEMA, + ViewChild, +} from '@angular/core'; import {ComponentFixture, TestBed} from '@angular/core/testing'; import {By} from '@angular/platform-browser'; import {CardFobComponent} from './card_fob_component'; @@ -27,6 +33,7 @@ import { } from './card_fob_types'; @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'testable-comp', template: ` diff --git a/tensorboard/webapp/widgets/card_fob/card_fob_test.ts b/tensorboard/webapp/widgets/card_fob/card_fob_test.ts index 30b7ee2a031..581cd6b82aa 100644 --- a/tensorboard/webapp/widgets/card_fob/card_fob_test.ts +++ b/tensorboard/webapp/widgets/card_fob/card_fob_test.ts @@ -13,13 +13,20 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -import {Component, Input, NO_ERRORS_SCHEMA, ViewChild} from '@angular/core'; +import { + ChangeDetectionStrategy, + Component, + Input, + NO_ERRORS_SCHEMA, + ViewChild, +} from '@angular/core'; import {ComponentFixture, TestBed} from '@angular/core/testing'; import {By} from '@angular/platform-browser'; import {CardFobComponent} from './card_fob_component'; import {AxisDirection} from './card_fob_types'; @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'testable-fob-comp', template: ` diff --git a/tensorboard/webapp/widgets/content_wrapping_input/BUILD b/tensorboard/webapp/widgets/content_wrapping_input/BUILD index a5dc7640267..4abf3e991f8 100644 --- a/tensorboard/webapp/widgets/content_wrapping_input/BUILD +++ b/tensorboard/webapp/widgets/content_wrapping_input/BUILD @@ -1,12 +1,14 @@ -load("//tensorboard/defs:defs.bzl", "tf_ng_module", "tf_sass_binary", "tf_ts_library") +load("@io_bazel_rules_sass//:defs.bzl", "sass_binary") +load("//tensorboard/defs:defs.bzl", "tf_ng_module", "tf_ts_library") package(default_visibility = ["//tensorboard:internal"]) -tf_sass_binary( +sass_binary( name = "content_wrapping_input_component_styles", src = "content_wrapping_input_component.scss", + include_paths = ["external/npm/node_modules"], deps = [ - "//tensorboard/webapp:angular_material_sass_deps", + "//tensorboard/webapp/angular_components:material_sass", "//tensorboard/webapp/theme", ], ) diff --git a/tensorboard/webapp/widgets/content_wrapping_input/content_wrapping_input_test.ts b/tensorboard/webapp/widgets/content_wrapping_input/content_wrapping_input_test.ts index a47deaf39d3..f25f60040e9 100644 --- a/tensorboard/webapp/widgets/content_wrapping_input/content_wrapping_input_test.ts +++ b/tensorboard/webapp/widgets/content_wrapping_input/content_wrapping_input_test.ts @@ -13,13 +13,14 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -import {Component, Input} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input} from '@angular/core'; import {ComponentFixture, TestBed} from '@angular/core/testing'; import {By} from '@angular/platform-browser'; import {KeyType, sendKey} from '../../testing/dom'; import {ContentWrappingInputComponent} from './content_wrapping_input_component'; @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'testing-component', template: ` diff --git a/tensorboard/webapp/widgets/custom_modal/custom_modal_test.ts b/tensorboard/webapp/widgets/custom_modal/custom_modal_test.ts index 9326e2299f1..011892a0135 100644 --- a/tensorboard/webapp/widgets/custom_modal/custom_modal_test.ts +++ b/tensorboard/webapp/widgets/custom_modal/custom_modal_test.ts @@ -12,25 +12,27 @@ 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 { - ComponentFixture, - TestBed, - fakeAsync, - tick, -} from '@angular/core/testing'; -import {By} from '@angular/platform-browser'; -import {CustomModal} from './custom_modal'; +import {Overlay, OverlayModule, OverlayRef} from '@angular/cdk/overlay'; import {CommonModule} from '@angular/common'; import { + ChangeDetectionStrategy, Component, TemplateRef, ViewChild, ViewContainerRef, } from '@angular/core'; -import {Overlay, OverlayModule, OverlayRef} from '@angular/cdk/overlay'; +import { + ComponentFixture, + TestBed, + fakeAsync, + tick, +} from '@angular/core/testing'; +import {By} from '@angular/platform-browser'; import {first} from 'rxjs/operators'; +import {CustomModal} from './custom_modal'; @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'fake-modal-view-container', template: ` diff --git a/tensorboard/webapp/widgets/data_table/BUILD b/tensorboard/webapp/widgets/data_table/BUILD index be4d4863d2a..fff14429957 100644 --- a/tensorboard/webapp/widgets/data_table/BUILD +++ b/tensorboard/webapp/widgets/data_table/BUILD @@ -1,58 +1,66 @@ -load("//tensorboard/defs:defs.bzl", "tf_ng_module", "tf_sass_binary", "tf_ts_library") +load("@io_bazel_rules_sass//:defs.bzl", "sass_binary") +load("//tensorboard/defs:defs.bzl", "tf_ng_module", "tf_ts_library") package(default_visibility = ["//tensorboard:internal"]) -tf_sass_binary( +sass_binary( name = "data_table_styles", src = "data_table_component.scss", + include_paths = ["external/npm/node_modules"], deps = [ - "//tensorboard/webapp:angular_material_sass_deps", + "//tensorboard/webapp/angular_components:material_sass", "//tensorboard/webapp/theme", ], ) -tf_sass_binary( +sass_binary( name = "header_cell_styles", src = "header_cell_component.scss", + include_paths = ["external/npm/node_modules"], deps = [ - "//tensorboard/webapp:angular_material_sass_deps", + "//tensorboard/webapp/angular_components:material_sass", "//tensorboard/webapp/theme", ], ) -tf_sass_binary( +sass_binary( name = "content_cell_styles", src = "content_cell_component.scss", + include_paths = ["external/npm/node_modules"], ) -tf_sass_binary( +sass_binary( name = "data_table_header_styles", src = "data_table_header_component.scss", + include_paths = ["external/npm/node_modules"], ) -tf_sass_binary( +sass_binary( name = "column_selector_component_styles", src = "column_selector_component.scss", + include_paths = ["external/npm/node_modules"], deps = [ - "//tensorboard/webapp:angular_material_sass_deps", + "//tensorboard/webapp/angular_components:material_sass", "//tensorboard/webapp/theme", ], ) -tf_sass_binary( +sass_binary( name = "context_menu_component_styles", src = "context_menu_component.scss", + include_paths = ["external/npm/node_modules"], deps = [ - "//tensorboard/webapp:angular_material_sass_deps", + "//tensorboard/webapp/angular_components:material_sass", "//tensorboard/webapp/theme", ], ) -tf_sass_binary( +sass_binary( name = "filter_dialog_styles", src = "filter_dialog_component.scss", + include_paths = ["external/npm/node_modules"], deps = [ - "//tensorboard/webapp:angular_material_sass_deps", + "//tensorboard/webapp/angular_components:material_sass", "//tensorboard/webapp/theme", ], ) diff --git a/tensorboard/webapp/widgets/data_table/content_cell_component_test.ts b/tensorboard/webapp/widgets/data_table/content_cell_component_test.ts index 93b48e2ba70..36f2303a69d 100644 --- a/tensorboard/webapp/widgets/data_table/content_cell_component_test.ts +++ b/tensorboard/webapp/widgets/data_table/content_cell_component_test.ts @@ -13,15 +13,21 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -import {Component, Input, ViewChild} from '@angular/core'; +import { + ChangeDetectionStrategy, + Component, + Input, + ViewChild, +} from '@angular/core'; import {ComponentFixture, TestBed} from '@angular/core/testing'; -import {MatIconTestingModule} from '../../testing/mat_icon_module'; import {By} from '@angular/platform-browser'; -import {ColumnHeader, ColumnHeaderType} from './types'; -import {DataTableModule} from './data_table_module'; +import {MatIconTestingModule} from '../../testing/mat_icon_module'; import {ContentCellComponent} from './content_cell_component'; +import {DataTableModule} from './data_table_module'; +import {ColumnHeader, ColumnHeaderType} from './types'; @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'testable-comp', template: ` diff --git a/tensorboard/webapp/widgets/data_table/data_table_test.ts b/tensorboard/webapp/widgets/data_table/data_table_test.ts index 4e7e8faa2da..caf9ee08df9 100644 --- a/tensorboard/webapp/widgets/data_table/data_table_test.ts +++ b/tensorboard/webapp/widgets/data_table/data_table_test.ts @@ -15,6 +15,7 @@ limitations under the License. import { ApplicationRef, + ChangeDetectionStrategy, Component, EventEmitter, Input, @@ -22,32 +23,33 @@ import { ViewChild, } from '@angular/core'; import {ComponentFixture, TestBed} from '@angular/core/testing'; -import {MatIconTestingModule} from '../../testing/mat_icon_module'; import {By} from '@angular/platform-browser'; +import {NoopAnimationsModule} from '@angular/platform-browser/animations'; +import {MatIconTestingModule} from '../../testing/mat_icon_module'; +import {CustomModal} from '../custom_modal/custom_modal'; +import {ColumnSelectorComponent} from './column_selector_component'; +import {ColumnSelectorModule} from './column_selector_module'; +import {ContentCellComponent} from './content_cell_component'; +import {DataTableComponent} from './data_table_component'; +import {DataTableModule} from './data_table_module'; +import {FilterDialog} from './filter_dialog_component'; +import {HeaderCellComponent} from './header_cell_component'; import { ColumnHeader, ColumnHeaderType, - TableData, - SortingInfo, - SortingOrder, DiscreteFilter, - IntervalFilter, DomainType, + IntervalFilter, Side, + SortingInfo, + SortingOrder, + TableData, } from './types'; -import {DataTableComponent} from './data_table_component'; -import {DataTableModule} from './data_table_module'; -import {HeaderCellComponent} from './header_cell_component'; -import {NoopAnimationsModule} from '@angular/platform-browser/animations'; -import {ColumnSelectorComponent} from './column_selector_component'; -import {ContentCellComponent} from './content_cell_component'; -import {ColumnSelectorModule} from './column_selector_module'; -import {FilterDialog} from './filter_dialog_component'; -import {CustomModal} from '../custom_modal/custom_modal'; const ADD_BUTTON_PREDICATE = By.css('.add-button'); @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'testable-comp', template: ` diff --git a/tensorboard/webapp/widgets/data_table/filter_dialog_component.ts b/tensorboard/webapp/widgets/data_table/filter_dialog_component.ts index fd9de24a97c..47da4015db2 100644 --- a/tensorboard/webapp/widgets/data_table/filter_dialog_component.ts +++ b/tensorboard/webapp/widgets/data_table/filter_dialog_component.ts @@ -12,16 +12,23 @@ 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 {Component, EventEmitter, Input, Output} from '@angular/core'; import { - DomainType, + ChangeDetectionStrategy, + Component, + EventEmitter, + Input, + Output, +} from '@angular/core'; +import {RangeValues} from '../range_input/types'; +import { DiscreteFilter, - IntervalFilter, DiscreteFilterValue, + DomainType, + IntervalFilter, } from './types'; -import {RangeValues} from '../range_input/types'; @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'tb-data-table-filter', templateUrl: 'filter_dialog_component.ng.html', diff --git a/tensorboard/webapp/widgets/data_table/header_cell_component_test.ts b/tensorboard/webapp/widgets/data_table/header_cell_component_test.ts index bf57bd9c6a2..9bfede287ad 100644 --- a/tensorboard/webapp/widgets/data_table/header_cell_component_test.ts +++ b/tensorboard/webapp/widgets/data_table/header_cell_component_test.ts @@ -13,25 +13,28 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -import {Component, EventEmitter, Input, Output, ViewChild} from '@angular/core'; import { - ComponentFixture, - TestBed, - fakeAsync, - flush, -} from '@angular/core/testing'; -import {MatIconTestingModule} from '../../testing/mat_icon_module'; + ChangeDetectionStrategy, + Component, + EventEmitter, + Input, + Output, + ViewChild, +} from '@angular/core'; +import {ComponentFixture, TestBed} from '@angular/core/testing'; import {By} from '@angular/platform-browser'; +import {MatIconTestingModule} from '../../testing/mat_icon_module'; +import {DataTableModule} from './data_table_module'; +import {HeaderCellComponent} from './header_cell_component'; import { ColumnHeader, ColumnHeaderType, SortingInfo, SortingOrder, } from './types'; -import {DataTableModule} from './data_table_module'; -import {HeaderCellComponent} from './header_cell_component'; @Component({ + changeDetection: ChangeDetectionStrategy.Default, standalone: false, selector: 'testable-comp', template: ` diff --git a/tensorboard/webapp/widgets/dropdown/BUILD b/tensorboard/webapp/widgets/dropdown/BUILD index ff69ccddd41..28cab5503b3 100644 --- a/tensorboard/webapp/widgets/dropdown/BUILD +++ b/tensorboard/webapp/widgets/dropdown/BUILD @@ -1,14 +1,16 @@ -load("//tensorboard/defs:defs.bzl", "tf_ng_module", "tf_sass_binary", "tf_ts_library") +load("@io_bazel_rules_sass//:defs.bzl", "sass_binary") +load("//tensorboard/defs:defs.bzl", "tf_ng_module", "tf_ts_library") package(default_visibility = ["//tensorboard:internal"]) licenses(["notice"]) -tf_sass_binary( +sass_binary( name = "dropdown_styles", src = "dropdown_component.scss", + include_paths = ["external/npm/node_modules"], deps = [ - "//tensorboard/webapp:angular_material_sass_deps", + "//tensorboard/webapp/angular_components:material_sass", "//tensorboard/webapp/theme", ], ) diff --git a/tensorboard/webapp/widgets/dropdown/dropdown_component.ts b/tensorboard/webapp/widgets/dropdown/dropdown_component.ts index ce48cca1823..8bc18511fca 100644 --- a/tensorboard/webapp/widgets/dropdown/dropdown_component.ts +++ b/tensorboard/webapp/widgets/dropdown/dropdown_component.ts @@ -12,7 +12,13 @@ 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 {Component, EventEmitter, Input, Output} from '@angular/core'; +import { + ChangeDetectionStrategy, + Component, + EventEmitter, + Input, + Output, +} from '@angular/core'; export interface DropdownOption { value: any; @@ -31,6 +37,7 @@ export interface DropdownOption { * A generic dropdown with options, similar to