From efbd4b040deb96eef86eb45cd420bfe5b64ffa96 Mon Sep 17 00:00:00 2001 From: hao-affirm <104030690+hao-affirm@users.noreply.github.com> Date: Tue, 4 Oct 2022 10:36:13 -0700 Subject: [PATCH 1/8] fix: Stream feature view meta undefined created_timestamp issue (#3266) fix stream feature view meta undefied created_timestap issue Signed-off-by: hao-affirm <104030690+hao-affirm@users.noreply.github.com> Signed-off-by: hao-affirm <104030690+hao-affirm@users.noreply.github.com> --- ui/src/parsers/feastSFVS.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/src/parsers/feastSFVS.ts b/ui/src/parsers/feastSFVS.ts index f21b3d1cda..f65a087222 100644 --- a/ui/src/parsers/feastSFVS.ts +++ b/ui/src/parsers/feastSFVS.ts @@ -28,8 +28,8 @@ const FeastSFVSchema = z.object({ }), }), meta: z.object({ - createdTimestamp: z.string().transform((val) => new Date(val)), - lastUpdatedTimestamp: z.string().transform((val) => new Date(val)), + createdTimestamp: z.string().transform((val) => new Date(val)).optional(), + lastUpdatedTimestamp: z.string().transform((val) => new Date(val)).optional(), }), }); From f4a83a7762ac0105b75b20e19822304cce97181c Mon Sep 17 00:00:00 2001 From: hao-affirm <104030690+hao-affirm@users.noreply.github.com> Date: Tue, 4 Oct 2022 16:55:12 -0700 Subject: [PATCH 2/8] fix: Udf in stream feature view UI shows pickled data (#3268) * fix udf in stream feature view UI shows pickeled data Signed-off-by: hao-affirm <104030690+hao-affirm@users.noreply.github.com> * fix lint Signed-off-by: hao-affirm <104030690+hao-affirm@users.noreply.github.com> * fix lint Signed-off-by: hao-affirm <104030690+hao-affirm@users.noreply.github.com> * fix test Signed-off-by: hao-affirm <104030690+hao-affirm@users.noreply.github.com> * fix lint Signed-off-by: hao-affirm <104030690+hao-affirm@users.noreply.github.com> Signed-off-by: hao-affirm <104030690+hao-affirm@users.noreply.github.com> --- sdk/python/feast/infra/registry/base_registry.py | 9 ++++++--- sdk/python/feast/stream_feature_view.py | 13 +++++++++++++ 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/sdk/python/feast/infra/registry/base_registry.py b/sdk/python/feast/infra/registry/base_registry.py index e1e9ba99e1..fc65932ea1 100644 --- a/sdk/python/feast/infra/registry/base_registry.py +++ b/sdk/python/feast/infra/registry/base_registry.py @@ -638,9 +638,12 @@ def to_dict(self, project: str) -> Dict[str, List[Any]]: self.list_stream_feature_views(project=project), key=lambda stream_feature_view: stream_feature_view.name, ): - registry_dict["streamFeatureViews"].append( - self._message_to_sorted_dict(stream_feature_view.to_proto()) - ) + sfv_dict = self._message_to_sorted_dict(stream_feature_view.to_proto()) + + sfv_dict["spec"]["userDefinedFunction"][ + "body" + ] = stream_feature_view.udf_string + registry_dict["streamFeatureViews"].append(sfv_dict) for saved_dataset in sorted( self.list_saved_datasets(project=project), key=lambda item: item.name ): diff --git a/sdk/python/feast/stream_feature_view.py b/sdk/python/feast/stream_feature_view.py index 176f38d093..d3a2164788 100644 --- a/sdk/python/feast/stream_feature_view.py +++ b/sdk/python/feast/stream_feature_view.py @@ -71,6 +71,7 @@ class StreamFeatureView(FeatureView): timestamp_field: str materialization_intervals: List[Tuple[datetime, datetime]] udf: Optional[FunctionType] + udf_string: Optional[str] def __init__( self, @@ -88,6 +89,7 @@ def __init__( mode: Optional[str] = "spark", timestamp_field: Optional[str] = "", udf: Optional[FunctionType] = None, + udf_string: Optional[str] = "", ): if not flags_helper.is_test(): warnings.warn( @@ -114,6 +116,7 @@ def __init__( self.mode = mode or "" self.timestamp_field = timestamp_field or "" self.udf = udf + self.udf_string = udf_string super().__init__( name=name, @@ -143,6 +146,7 @@ def __eq__(self, other): self.mode != other.mode or self.timestamp_field != other.timestamp_field or self.udf.__code__.co_code != other.udf.__code__.co_code + or self.udf_string != other.udf_string or self.aggregations != other.aggregations ): return False @@ -171,6 +175,7 @@ def to_proto(self): udf_proto = UserDefinedFunctionProto( name=self.udf.__name__, body=dill.dumps(self.udf, recurse=True), + body_text=self.udf_string, ) spec = StreamFeatureViewSpecProto( name=self.name, @@ -209,6 +214,11 @@ def from_proto(cls, sfv_proto): if sfv_proto.spec.HasField("user_defined_function") else None ) + udf_string = ( + sfv_proto.spec.user_defined_function.body_text + if sfv_proto.spec.HasField("user_defined_function") + else None + ) stream_feature_view = cls( name=sfv_proto.spec.name, description=sfv_proto.spec.description, @@ -226,6 +236,7 @@ def from_proto(cls, sfv_proto): source=stream_source, mode=sfv_proto.spec.mode, udf=udf, + udf_string=udf_string, aggregations=[ Aggregation.from_proto(agg_proto) for agg_proto in sfv_proto.spec.aggregations @@ -315,6 +326,7 @@ def mainify(obj): obj.__module__ = "__main__" def decorator(user_function): + udf_string = dill.source.getsource(user_function) mainify(user_function) stream_feature_view_obj = StreamFeatureView( name=user_function.__name__, @@ -323,6 +335,7 @@ def decorator(user_function): source=source, schema=schema, udf=user_function, + udf_string=udf_string, description=description, tags=tags, online=online, From 7fa4bbf2be98847fa2b795fe0d7dc77d5e45b2fb Mon Sep 17 00:00:00 2001 From: Francisco Javier Arceo Date: Tue, 4 Oct 2022 17:59:10 -0600 Subject: [PATCH 3/8] fix: Updated quickstart notebook to patch an incorrect reference to an outdated featureview name (#3271) Signed-off-by: Francisco Javier Arceo Signed-off-by: Francisco Javier Arceo --- examples/quickstart/quickstart.ipynb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/quickstart/quickstart.ipynb b/examples/quickstart/quickstart.ipynb index 68b9d63911..cec4df91b1 100644 --- a/examples/quickstart/quickstart.ipynb +++ b/examples/quickstart/quickstart.ipynb @@ -512,7 +512,7 @@ "\n", "# This groups features into a model version\n", "driver_stats_fs = FeatureService(\n", - " name=\"driver_activity\", features=[driver_hourly_stats_view, transformed_conv_rate]\n", + " name=\"driver_activity_v1\", features=[driver_hourly_stats_view, transformed_conv_rate]\n", ")\n", "```" ] @@ -547,7 +547,7 @@ "Created entity \u001b[1m\u001b[32mdriver\u001b[0m\n", "Created feature view \u001b[1m\u001b[32mdriver_hourly_stats\u001b[0m\n", "Created on demand feature view \u001b[1m\u001b[32mtransformed_conv_rate\u001b[0m\n", - "Created feature service \u001b[1m\u001b[32mdriver_activity\u001b[0m\n", + "Created feature service \u001b[1m\u001b[32mdriver_activity_v1\u001b[0m\n", "\n", "Created sqlite table \u001b[1m\u001b[32mfeature_repo_driver_hourly_stats\u001b[0m\n", "\n" @@ -942,11 +942,11 @@ "### Fetching features using feature services\n", "You can also use feature services to manage multiple features, and decouple feature view definitions and the features needed by end applications. The feature store can also be used to fetch either online or historical features using the same api below. More information can be found [here](https://docs.feast.dev/getting-started/concepts/feature-retrieval).\n", "\n", - " The `driver_activity` feature service pulls all features from the `driver_hourly_stats` feature view:\n", + " The `driver_activity_v1` feature service pulls all features from the `driver_hourly_stats` feature view:\n", "\n", "```python\n", "driver_stats_fs = FeatureService(\n", - " name=\"driver_activity\", features=[driver_hourly_stats_view]\n", + " name=\"driver_activity_v1\", features=[driver_hourly_stats_view]\n", ")\n", "```" ] @@ -979,7 +979,7 @@ "from feast import FeatureStore\n", "feature_store = FeatureStore('.') # Initialize the feature store\n", "\n", - "feature_service = feature_store.get_feature_service(\"driver_activity\")\n", + "feature_service = feature_store.get_feature_service(\"driver_activity_v1\")\n", "feature_vector = feature_store.get_online_features(\n", " features=feature_service,\n", " entity_rows=[\n", @@ -1101,4 +1101,4 @@ }, "nbformat": 4, "nbformat_minor": 0 -} \ No newline at end of file +} From f91dc0e15ae21feadfed5d1ee9b3972e38a29cdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Viveret?= Date: Thu, 6 Oct 2022 01:32:17 +0200 Subject: [PATCH 4/8] chore: Replace zod by protobufjs (#3208) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: Replace zod by protobufjs Signed-off-by: Jérôme Viveret Signed-off-by: Danny Chiao * Remove unneeded pages and fix bugs Signed-off-by: Danny Chiao * Update the ui_server Signed-off-by: Danny Chiao * Replace manually generated json registry by protobuf version Signed-off-by: Danny Chiao * Correctly display protobufjs enums Signed-off-by: Danny Chiao Signed-off-by: Jérôme Viveret Signed-off-by: Danny Chiao Co-authored-by: Jérôme Viveret Co-authored-by: Danny Chiao --- protos/feast/core/DataSource.proto | 7 + sdk/python/feast/ui/README.md | 5 +- sdk/python/feast/ui/package.json | 12 +- sdk/python/feast/ui/yarn.lock | 80 +- sdk/python/feast/ui_server.py | 11 +- ui/.gitignore | 2 + ui/feature_repo/test_get_features.py | 86 --- ui/package.json | 21 +- ui/public/projects-list.json | 2 +- ui/public/registry.db | Bin 0 -> 5527 bytes ui/public/registry.json | 706 ------------------ .../components/FeaturesInServiceDisplay.tsx | 43 +- ui/src/components/FeaturesListDisplay.tsx | 80 +- ui/src/components/NumericFeaturesTable.tsx | 60 -- ui/src/components/SparklineHistogram.tsx | 58 -- ui/src/hooks/useFCOExploreSuggestions.ts | 6 +- ui/src/hooks/useTagsAggregation.ts | 27 +- .../BatchSourcePropertiesView.tsx | 63 +- ui/src/pages/data-sources/DataSourceDbt.tsx | 35 - .../pages/data-sources/DataSourceInstance.tsx | 18 +- .../data-sources/DataSourceOverviewTab.tsx | 11 +- .../data-sources/DataSourcesListingTable.tsx | 9 +- .../RequestDataSourceSchemaTable.tsx | 8 +- .../pages/entities/EntitiesListingTable.tsx | 16 +- ui/src/pages/entities/EntityOverviewTab.tsx | 20 +- ui/src/pages/entities/useLoadEntity.ts | 4 +- .../FeatureServiceListingTable.tsx | 28 +- .../FeatureServiceOverviewTab.tsx | 23 +- ui/src/pages/feature-services/Index.tsx | 10 +- .../feature-services/useLoadFeatureService.ts | 24 +- .../feature-views/FeatureViewInstance.tsx | 12 +- .../feature-views/FeatureViewListingTable.tsx | 2 +- .../FeatureViewSummaryStatisticsTab.tsx | 84 --- ui/src/pages/feature-views/Index.tsx | 2 +- .../OnDemandFeatureViewInstance.tsx | 4 +- .../OnDemandFeatureViewOverviewTab.tsx | 33 +- .../RegularFeatureViewInstance.tsx | 11 +- .../RegularFeatureViewOverviewTab.tsx | 31 +- .../StreamFeatureViewInstance.tsx | 4 +- .../StreamFeatureViewOverviewTab.tsx | 24 +- .../FeatureViewProjectionDisplayPanel.tsx | 17 +- .../components/RequestDataDisplayPanel.tsx | 12 +- .../pages/feature-views/useLoadFeatureView.ts | 10 +- ui/src/pages/features/FeatureOverviewTab.tsx | 3 +- ui/src/pages/features/useLoadFeature.ts | 12 +- .../DatasetExpectationsTab.tsx | 12 +- .../saved-data-sets/DatasetOverviewTab.tsx | 13 +- .../saved-data-sets/DatasetsListingTable.tsx | 13 +- .../pages/saved-data-sets/useLoadDataset.ts | 4 +- ui/src/parsers/feastDatasources.ts | 30 - ui/src/parsers/feastEntities.ts | 21 - ui/src/parsers/feastFeatureServices.ts | 31 - ui/src/parsers/feastFeatureViews.ts | 64 -- ui/src/parsers/feastFeatures.ts | 11 - ui/src/parsers/feastODFVS.ts | 47 -- ui/src/parsers/feastRegistry.ts | 24 - ui/src/parsers/feastSFVS.ts | 41 - ui/src/parsers/feastSavedDataset.ts | 37 - .../parsers/featureViewSummaryStatistics.ts | 56 -- ui/src/parsers/mergedFVTypes.ts | 40 +- ui/src/parsers/parseEntityRelationships.ts | 86 +-- ui/src/parsers/parseIndirectRelationships.ts | 8 +- ui/src/parsers/types.ts | 23 +- .../useLoadFeatureViewSummaryStatistics.ts | 37 - ui/src/queries/useLoadRegistry.ts | 17 +- ui/src/utils/timestamp.ts | 13 + ui/yarn.lock | 309 +++++++- 67 files changed, 693 insertions(+), 1980 deletions(-) create mode 100644 ui/.gitignore delete mode 100644 ui/feature_repo/test_get_features.py create mode 100644 ui/public/registry.db delete mode 100644 ui/public/registry.json delete mode 100644 ui/src/components/NumericFeaturesTable.tsx delete mode 100644 ui/src/components/SparklineHistogram.tsx delete mode 100644 ui/src/pages/data-sources/DataSourceDbt.tsx delete mode 100644 ui/src/pages/feature-views/FeatureViewSummaryStatisticsTab.tsx delete mode 100644 ui/src/parsers/feastDatasources.ts delete mode 100644 ui/src/parsers/feastEntities.ts delete mode 100644 ui/src/parsers/feastFeatureServices.ts delete mode 100644 ui/src/parsers/feastFeatureViews.ts delete mode 100644 ui/src/parsers/feastFeatures.ts delete mode 100644 ui/src/parsers/feastODFVS.ts delete mode 100644 ui/src/parsers/feastRegistry.ts delete mode 100644 ui/src/parsers/feastSFVS.ts delete mode 100644 ui/src/parsers/feastSavedDataset.ts delete mode 100644 ui/src/parsers/featureViewSummaryStatistics.ts delete mode 100644 ui/src/queries/useLoadFeatureViewSummaryStatistics.ts create mode 100644 ui/src/utils/timestamp.ts diff --git a/protos/feast/core/DataSource.proto b/protos/feast/core/DataSource.proto index 5258618f3b..3992d2c247 100644 --- a/protos/feast/core/DataSource.proto +++ b/protos/feast/core/DataSource.proto @@ -23,6 +23,7 @@ option java_outer_classname = "DataSourceProto"; option java_package = "feast.proto.core"; import "google/protobuf/duration.proto"; +import "google/protobuf/timestamp.proto"; import "feast/core/DataFormat.proto"; import "feast/types/Value.proto"; import "feast/core/Feature.proto"; @@ -89,6 +90,12 @@ message DataSource { // Optional batch source for streaming sources for historical features and materialization. DataSource batch_source = 26; + SourceMeta meta = 50; + + message SourceMeta { + google.protobuf.Timestamp earliestEventTimestamp = 1; + google.protobuf.Timestamp latestEventTimestamp = 2; + } // Defines options for DataSource that sources features from a file message FileOptions { diff --git a/sdk/python/feast/ui/README.md b/sdk/python/feast/ui/README.md index 0c11dcf134..220f40a225 100644 --- a/sdk/python/feast/ui/README.md +++ b/sdk/python/feast/ui/README.md @@ -22,4 +22,7 @@ It is used by the `feast ui` command to scaffold a local UI server. The feast py The `feast ui` command will generate the necessary `projects-list.json` file and initialize it for the UI to read. -**Note**: yarn start will not work on this because of the above dependency. +**Note**: `yarn start` will not work on this because of the above dependency. + +## Dev +To test, do `yarn link` in ui/ and then come here to do `yarn link @feast-dev/feast` \ No newline at end of file diff --git a/sdk/python/feast/ui/package.json b/sdk/python/feast/ui/package.json index 358aa2cdd2..6ffebcc834 100644 --- a/sdk/python/feast/ui/package.json +++ b/sdk/python/feast/ui/package.json @@ -4,7 +4,7 @@ "private": true, "dependencies": { "@elastic/datemath": "^5.0.3", - "@elastic/eui": "^57.0.0", + "@elastic/eui": "^55.0.1", "@emotion/react": "^11.9.0", "@feast-dev/feast-ui": "latest", "@testing-library/jest-dom": "^5.16.4", @@ -16,11 +16,11 @@ "moment": "^2.29.4", "prop-types": "^15.8.1", "query-string": "^7.1.1", - "react": "^18.1.0", - "react-dom": "^18.1.0", - "react-query": "^3.39.0", - "react-router-dom": "^6.3.0", - "react-scripts": "5.0.1", + "react": "^17.0.2", + "react-dom": "^17.0.2", + "react-query": "^3.34.12", + "react-router-dom": "6", + "react-scripts": "^5.0.0", "typescript": "^4.6.4", "use-query-params": "^1.2.3", "web-vitals": "^2.1.4", diff --git a/sdk/python/feast/ui/yarn.lock b/sdk/python/feast/ui/yarn.lock index df2bfe45ff..1b9cf5f067 100644 --- a/sdk/python/feast/ui/yarn.lock +++ b/sdk/python/feast/ui/yarn.lock @@ -1202,51 +1202,6 @@ uuid "^8.3.0" vfile "^4.2.0" -"@elastic/eui@^57.0.0": - version "57.0.0" - resolved "https://registry.yarnpkg.com/@elastic/eui/-/eui-57.0.0.tgz#86d43e27196f9997ef44d2a4c701d092ce99e132" - integrity sha512-VBgW6Pr0JJB3JhJ59MV8guxb2v4Gd3SJEmsMGKGyIY+KcvSMWbVEGa44Ep12VAJYynIA05Z3OXXc/ge5dMycpA== - dependencies: - "@types/chroma-js" "^2.0.0" - "@types/lodash" "^4.14.160" - "@types/numeral" "^0.0.28" - "@types/react-beautiful-dnd" "^13.1.2" - "@types/react-input-autosize" "^2.2.1" - "@types/react-virtualized-auto-sizer" "^1.0.1" - "@types/react-window" "^1.8.5" - "@types/refractor" "^3.0.0" - "@types/resize-observer-browser" "^0.1.5" - "@types/vfile-message" "^2.0.0" - chroma-js "^2.1.0" - classnames "^2.2.6" - lodash "^4.17.21" - mdast-util-to-hast "^10.0.0" - numeral "^2.0.6" - prop-types "^15.6.0" - react-beautiful-dnd "^13.1.0" - react-dropzone "^11.5.3" - react-element-to-jsx-string "^14.3.4" - react-focus-on "^3.5.4" - react-input-autosize "^3.0.0" - react-is "^17.0.2" - react-virtualized-auto-sizer "^1.0.6" - react-window "^1.8.6" - refractor "^3.5.0" - rehype-raw "^5.0.0" - rehype-react "^6.0.0" - rehype-stringify "^8.0.0" - remark-breaks "^2.0.2" - remark-emoji "^2.1.0" - remark-parse "^8.0.3" - remark-rehype "^8.0.0" - tabbable "^5.2.1" - text-diff "^1.0.1" - unified "^9.2.0" - unist-util-visit "^2.0.3" - url-parse "^1.5.10" - uuid "^8.3.0" - vfile "^4.2.0" - "@emotion/babel-plugin@^11.7.1": version "11.9.2" resolved "https://registry.yarnpkg.com/@emotion/babel-plugin/-/babel-plugin-11.9.2.tgz#723b6d394c89fb2ef782229d92ba95a740576e95" @@ -8403,13 +8358,14 @@ react-dev-utils@^12.0.1: strip-ansi "^6.0.1" text-table "^0.2.0" -react-dom@^18.1.0: - version "18.1.0" - resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.1.0.tgz#7f6dd84b706408adde05e1df575b3a024d7e8a2f" - integrity sha512-fU1Txz7Budmvamp7bshe4Zi32d0ll7ect+ccxNu9FlObT605GOEB8BfO4tmRJ39R5Zj831VCpvQ05QPBW5yb+w== +react-dom@^17.0.2: + version "17.0.2" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.2.tgz#ecffb6845e3ad8dbfcdc498f0d0a939736502c23" + integrity sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA== dependencies: loose-envify "^1.1.0" - scheduler "^0.22.0" + object-assign "^4.1.1" + scheduler "^0.20.2" react-dropzone@^11.5.3: version "11.7.1" @@ -8481,7 +8437,7 @@ react-is@^18.0.0: resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.1.0.tgz#61aaed3096d30eacf2a2127118b5b41387d32a67" integrity sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg== -react-query@^3.34.12, react-query@^3.39.0: +react-query@^3.34.12: version "3.39.0" resolved "https://registry.yarnpkg.com/react-query/-/react-query-3.39.0.tgz#0caca7b0da98e65008bbcd4df0d25618c2100050" integrity sha512-Od0IkSuS79WJOhzWBx/ys0x13+7wFqgnn64vBqqAAnZ9whocVhl/y1padD5uuZ6EIkXbFbInax0qvY7zGM0thA== @@ -8526,7 +8482,7 @@ react-remove-scroll@^2.5.2: use-callback-ref "^1.3.0" use-sidecar "^1.1.2" -react-router-dom@6, react-router-dom@^6.3.0: +react-router-dom@6: version "6.3.0" resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-6.3.0.tgz#a0216da813454e521905b5fa55e0e5176123f43d" integrity sha512-uaJj7LKytRxZNQV8+RbzJWnJ8K2nPsOOEuX7aQstlMZKQT0164C+X2w6bnkqU3sjtLvpd5ojrezAyfZ1+0sStw== @@ -8541,7 +8497,7 @@ react-router@6.3.0: dependencies: history "^5.2.0" -react-scripts@5.0.1, react-scripts@^5.0.0: +react-scripts@^5.0.0: version "5.0.1" resolved "https://registry.yarnpkg.com/react-scripts/-/react-scripts-5.0.1.tgz#6285dbd65a8ba6e49ca8d651ce30645a6d980003" integrity sha512-8VAmEm/ZAwQzJ+GOMLbBsTdDKOpuZh7RPs0UymvBR2vRk4iZWCskjbFnxqjrzoIvlNNRZ3QJFx6/qDSi6zSnaQ== @@ -8618,12 +8574,13 @@ react-window@^1.8.6: "@babel/runtime" "^7.0.0" memoize-one ">=3.1.1 <6" -react@^18.1.0: - version "18.1.0" - resolved "https://registry.yarnpkg.com/react/-/react-18.1.0.tgz#6f8620382decb17fdc5cc223a115e2adbf104890" - integrity sha512-4oL8ivCz5ZEPyclFQXaNksK3adutVS8l2xzZU0cqEFrE9Sb7fC0EFK5uEk74wIreL1DERyjvsU915j1pcT2uEQ== +react@^17.0.2: + version "17.0.2" + resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037" + integrity sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA== dependencies: loose-envify "^1.1.0" + object-assign "^4.1.1" readable-stream@^2.0.1: version "2.3.7" @@ -9001,12 +8958,13 @@ saxes@^5.0.1: dependencies: xmlchars "^2.2.0" -scheduler@^0.22.0: - version "0.22.0" - resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.22.0.tgz#83a5d63594edf074add9a7198b1bae76c3db01b8" - integrity sha512-6QAm1BgQI88NPYymgGQLCZgvep4FyePDWFpXVK+zNSUgHwlqpJy8VEh8Et0KxTACS4VWwMousBElAZOH9nkkoQ== +scheduler@^0.20.2: + version "0.20.2" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.20.2.tgz#4baee39436e34aa93b4874bddcbf0fe8b8b50e91" + integrity sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ== dependencies: loose-envify "^1.1.0" + object-assign "^4.1.1" schema-utils@2.7.0: version "2.7.0" diff --git a/sdk/python/feast/ui_server.py b/sdk/python/feast/ui_server.py index 4d1fd67dc1..f79030e8d3 100644 --- a/sdk/python/feast/ui_server.py +++ b/sdk/python/feast/ui_server.py @@ -30,14 +30,14 @@ def get_app( ) # Asynchronously refresh registry, notifying shutdown and canceling the active timer if the app is shutting down - registry_json = "" + registry_proto = None shutting_down = False active_timer: Optional[threading.Timer] = None def async_refresh(): store.refresh_registry() - nonlocal registry_json - registry_json = get_registry_dump(store.config, store.repo_path) + nonlocal registry_proto + registry_proto = store.registry.proto() if shutting_down: return nonlocal active_timer @@ -70,7 +70,10 @@ def shutdown_event(): @app.get("/registry") def read_registry(): - return json.loads(registry_json) + return Response( + content=registry_proto.SerializeToString(), + media_type="application/octet-stream", + ) # For all other paths (such as paths that would otherwise be handled by react router), pass to React @app.api_route("/p/{path_name:path}", methods=["GET"]) diff --git a/ui/.gitignore b/ui/.gitignore new file mode 100644 index 0000000000..728f2aab71 --- /dev/null +++ b/ui/.gitignore @@ -0,0 +1,2 @@ +src/protos.d.ts +src/protos.js diff --git a/ui/feature_repo/test_get_features.py b/ui/feature_repo/test_get_features.py deleted file mode 100644 index 722c5a3dd4..0000000000 --- a/ui/feature_repo/test_get_features.py +++ /dev/null @@ -1,86 +0,0 @@ -import pandas as pd -from great_expectations.core.expectation_suite import ExpectationSuite -from great_expectations.dataset import PandasDataset - -from feast import FeatureStore -from feast.dqm.profilers.ge_profiler import ge_profiler -from feast.infra.offline_stores.file import SavedDatasetFileStorage - -DELTA = 0.1 # controlling allowed window in fraction of the value on scale [0, 1] -# Note: the GE integration allows asserting differences between datasets. The "ds" below is the reference dataset to check and this generates the expectation suite which can be used against future datasets. -# It's used via ge.validate(new_dataset, ExpectationSuite) -# For this demo though, we ignore this and - - -@ge_profiler -def credit_profiler(ds: PandasDataset) -> ExpectationSuite: - # simple checks on data consistency - ds.expect_column_values_to_be_between( - "credit_card_due", min_value=0, mostly=0.99, # allow some outliers - ) - - ds.expect_column_values_to_be_between( - "missed_payments_1y", - min_value=0, - max_value=5, - mostly=0.99, # allow some outliers - ) - - return ds.get_expectation_suite() - - -def generate_saved_dataset(): - store = FeatureStore(repo_path=".") - entity_df = pd.read_parquet(path="data/loan_table.parquet") - - fs = store.get_feature_service("credit_score_v1") - job = store.get_historical_features(entity_df=entity_df, features=fs,) - store.create_saved_dataset( - from_=job, - name="my_training_ds", - storage=SavedDatasetFileStorage(path="my_training_ds.parquet"), - feature_service=fs, - profiler=credit_profiler, - ) - - -def get_latest_timestamps(): - store = FeatureStore(repo_path=".") - feature_views = store.list_feature_views() - for fv in feature_views: - print( - f"Data source latest event for {fv.name} is {fv.batch_source._meta.latest_event_timestamp}" - ) - - -def test_ge(): - store = FeatureStore(repo_path=".") - - print("--- Historical features (from saved dataset) ---") - ds = store.get_saved_dataset("my_training_ds") - print(ds._profile) - - -def run_demo(): - store = FeatureStore(repo_path=".") - - print("--- Historical features (from saved dataset) ---") - ds = store.get_saved_dataset("my_training_ds") - print(ds.to_df()) - - print("\n--- Online features ---") - features = store.get_online_features( - features=store.get_feature_service("credit_score_v3"), - entity_rows=[ - {"zipcode": 30721, "dob_ssn": "19530219_5179", "transaction_amt": 1023} - ], - ).to_dict() - for key, value in sorted(features.items()): - print(key, " : ", value) - - -if __name__ == "__main__": - generate_saved_dataset() - get_latest_timestamps() - # test_ge() - run_demo() diff --git a/ui/package.json b/ui/package.json index bcb5af1fa8..9fa8b58fb4 100644 --- a/ui/package.json +++ b/ui/package.json @@ -25,8 +25,7 @@ "react-router-dom": "6", "react-scripts": "^5.0.0", "typescript": "^4.4.2", - "use-query-params": "^1.2.3", - "zod": "^3.11.6" + "use-query-params": "^1.2.3" }, "dependencies": { "@elastic/datemath": "^5.0.3", @@ -41,20 +40,21 @@ "inter-ui": "^3.19.3", "moment": "^2.29.1", "prop-types": "^15.8.1", + "protobufjs": "^7.1.1", "query-string": "^7.1.1", "react-query": "^3.34.12", "react-router-dom": "6", "react-scripts": "^5.0.0", - "use-query-params": "^1.2.3", - "zod": "^3.11.6" + "use-query-params": "^1.2.3" }, "scripts": { - "start": "react-scripts start", - "build": "react-scripts build", - "build:lib": "rimraf ./dist && tsc && rollup -c", - "build:lib-dev": "rimraf ./dist && tsc && rollup -c && yalc publish -f", - "test": "react-scripts test", - "eject": "react-scripts eject" + "start": "npm run generate-protos && react-scripts start", + "build": "npm run generate-protos && react-scripts build", + "build:lib": "npm run generate-protos && rimraf ./dist && tsc && rollup -c", + "build:lib-dev": "npm run generate-protos && rimraf ./dist && tsc && rollup -c && yalc publish -f", + "test": "npm run generate-protos && react-scripts test", + "eject": "react-scripts eject", + "generate-protos": "pbjs --no-encode -o src/protos.js -w commonjs -t static-module `find ../protos/feast/ -iname *.proto` && pbts -n protos -o src/protos.d.ts src/protos.js" }, "eslintConfig": { "extends": [ @@ -92,6 +92,7 @@ "@testing-library/react": "^12.0.0", "@testing-library/user-event": "^13.2.1", "msw": "^0.36.8", + "protobufjs-cli": "^1.0.2", "react": "^17.0.2", "react-dom": "^17.0.2", "rimraf": "^3.0.2", diff --git a/ui/public/projects-list.json b/ui/public/projects-list.json index d3d7c3b7d9..8e2bc3c616 100644 --- a/ui/public/projects-list.json +++ b/ui/public/projects-list.json @@ -4,7 +4,7 @@ "name": "Credit Score Project", "description": "Project for credit scoring team and associated models.", "id": "credit_score_project", - "registryPath": "/registry.json" + "registryPath": "/registry.db" }, { "name": "Empty Registry", diff --git a/ui/public/registry.db b/ui/public/registry.db new file mode 100644 index 0000000000000000000000000000000000000000..617771999c7e43ef6bdb1e6acf9eed18b06b1dae GIT binary patch literal 5527 zcmds5TZkJ~7|tZ=ZuabUH#_!XQ!nGR=x*3#cc*&|uGC#A=t_mwr`9^0%sJVNom*#4 zcAL^lu~?->5gls_Vs9@+P%QXRq%Rg96cp>5FG5j4QADd?`yl8!lgwtanQhYw-X@Sa z|37EW`Op7<|82lI4!q2Pc4X#d$1zg(KLiOD%z}_tZBi7VfdmaYL@1agTR`fZN*wmo zF%=bRf`gTkt&*}}l=M8dMSq#;wP1z0U|^f?CZ?o$K8gnvSaQHhwSK{ppSC6+PzdQZHNse!zz{8*)w97Io>3UfNwSlan z8!UD0v!j8fJPJGwo&@dtR7)`tPIWve)P|zZ3lVtwcK>ia2pYlD-C+NpUpx`m-=k98 zu(%OT;E94XI+~fBz+;(_5ea7|M#pewa&khEM$zPuG&-L4HE{NW%V#+0g*f;=2D)pS zE2<7L?J^&t$&_yr@ix#?o320`QRU%eTug#4-L%OZoWnKFDv)$Y31NfCnhA|McODm2 zMZ-aEHvmPpmQ~U;hpx5;@Ve?am~voQr%O1pR1W74FT)?xt5W5mvD+?LL{TwaIlUGD zM1d(ogfQYeq#;Sl3`v=>^hVGH6$LwvJZGCFi(gg16s{SDu{!F~>p>^pYhhdUgyOsE zMCL)MEphPLH@`%4N4Nx+>cR8u=!DL62-K}~FI5`d8P!=k?&Q}~Vc=k+_OlkW_mnU> z!VP;eWL2YJ!>m~-XsUr_W+Cik3o2EiL!C*%*)4Ru-5Z|fmY8xgm+xG3%49U)59hx) z8vv00HB+nRtj=pa*mklR!;g zpvYhb7;V(xy+I8Q1c>P%G1H=Xma*=5uQ;)Ac_gKx$MAC3=x2|oCxPM+EdHV_*c4pcm}&CwJhE zZSeQCG%eXKc6lhC!+Z?kd2zX#AiZkFD*%LA0U+o!7i$6kI(F#2)AbU-qjFa`aESve zegCSy5|;n|0X>TA`~o2fby`8edM0XANxJ*dnrAni`Rs>Z1&EK3tibmrbq9INDOjYP9-w;Bg&5JpaR+ zXX;MiQMvb{;CK@thC=}{)fAup?a^pid()zoB}W=o+S!e^3^$A*m#@4NP@YFkzXZUK z9W6z&P=&S}1i$8*RDX#}ecH?oHAr(72`$ih%55&tS;P+(=wZo*73g7nmW0CitU%|f zRE-6?I7th}dg|cQd|#sd6>fEk9xA|>p-z(V(_C#tb?hE?D{ZP_ zm54*1p#r0&!J?_-!KbjzZZvHUddGoGJV3yT4lGGm_0O;h^$CNyZ>m5 zx&8gb-R2%}D+yUP=r*$K4Rxp*bm$ZlTensx&?!B#Oj}r5>9d6I(8mX;-d0w6Eta;N zEUS33w2Ps#7CT?1(pLKfw|G~{Iqc?(tGpvoMR&`pZqY`P_8zFDF;!REs%yBi=7RoLfuwTeL(7?!f(xHMd z)xhrSukm-bB;_vpdQ~Y*G1ZM5-=uCN?h+nYe72-Q6L)$0Rd=nLOh5$?D5=i>`o^hx zHu0!!=VIUp2L?R6`OT{l>|LEbno4kXyLWq>byngIFxnzuy|&Es*2|(ie@{*1z(*gy z&a8dS0F|2+=80PsWh$T*bX2%dz00_gd7b^rhX literal 0 HcmV?d00001 diff --git a/ui/public/registry.json b/ui/public/registry.json deleted file mode 100644 index 279c9d0832..0000000000 --- a/ui/public/registry.json +++ /dev/null @@ -1,706 +0,0 @@ -{ - "dataSources": [ - { - "createdTimestampColumn": "created_timestamp", - "fileOptions": { - "uri": "data/credit_history.parquet" - }, - "name": "credit_history", - "timestampField": "event_timestamp", - "type": "BATCH_FILE" - }, - { - "name": "transaction", - "requestDataOptions": { - "schema": [ - { - "name": "transaction_amt", - "valueType": "INT64" - } - ] - }, - "type": "REQUEST_SOURCE" - }, - { - "createdTimestampColumn": "created_timestamp", - "fileOptions": { - "uri": "data/zipcode_table.parquet" - }, - "name": "zipcode", - "timestampField": "event_timestamp", - "type": "BATCH_FILE" - }, - { - "batchSource": { - "fileOptions": { - "uri": "data/zipcode_table.parquet" - }, - "name": "user_stats", - "timestampField": "timestamp", - "type": "BATCH_FILE" - }, - "dataSourceClassType": "feast.data_source.KafkaSource", - "description": "The Kafka stream example", - "kafkaOptions": {"messageFormat": {"jsonFormat": {"schemaJson": "id string, timestamp timestamp"}}, - "watermarkDelayThreshold": "300s"}, - "name": "driver_stats_stream", - "owner": "test@gmail.com", - "timestampField": "timestamp", - "type": "STREAM_KAFKA" - } - ], - "entities": [ - { - "meta": { - "createdTimestamp": "2022-05-11T19:27:03.171062Z", - "lastUpdatedTimestamp": "2022-05-11T19:27:03.171062Z" - }, - "spec": { - "joinKey": "__dummy_id", - "name": "__dummy", - "valueType": "STRING" - } - }, - { - "meta": { - "createdTimestamp": "2022-05-11T19:27:03.171112Z", - "lastUpdatedTimestamp": "2022-05-11T19:27:03.171112Z" - }, - "spec": { - "description": "Date of birth and last four digits of social security number", - "joinKey": "dob_ssn", - "name": "dob_ssn", - "tags": { - "owner": "tony@tecton.ai", - "team": "hack week" - }, - "valueType": "STRING" - } - }, - { - "meta": { - "createdTimestamp": "2022-05-11T19:27:03.171153Z", - "lastUpdatedTimestamp": "2022-05-11T19:27:03.171153Z" - }, - "spec": { - "description": "A zipcode", - "joinKey": "zipcode", - "name": "zipcode", - "tags": { - "owner": "danny@tecton.ai", - "team": "hack week" - }, - "valueType": "INT64" - } - } - ], - "featureServices": [ - { - "meta": { - "createdTimestamp": "2022-05-11T19:27:03.172623Z", - "lastUpdatedTimestamp": "2022-05-11T19:27:03.172623Z" - }, - "spec": { - "description": "Credit scoring model", - "features": [ - { - "featureColumns": [ - { - "name": "credit_card_due", - "valueType": "INT64" - }, - { - "name": "missed_payments_1y", - "valueType": "INT64" - } - ], - "featureViewName": "credit_history" - }, - { - "featureColumns": [ - { - "name": "city", - "valueType": "STRING" - }, - { - "name": "state", - "valueType": "STRING" - }, - { - "name": "location_type", - "valueType": "STRING" - }, - { - "name": "tax_returns_filed", - "valueType": "INT64" - }, - { - "name": "population", - "valueType": "INT64" - }, - { - "name": "total_wages", - "valueType": "INT64" - } - ], - "featureViewName": "zipcode_features" - } - ], - "name": "credit_score_v1", - "tags": { - "owner": "tony@tecton.ai", - "stage": "staging" - } - } - }, - { - "meta": { - "createdTimestamp": "2022-05-11T19:27:03.172405Z", - "lastUpdatedTimestamp": "2022-05-11T19:27:03.172405Z" - }, - "spec": { - "description": "Credit scoring model", - "features": [ - { - "featureColumns": [ - { - "name": "credit_card_due", - "valueType": "INT64" - }, - { - "name": "mortgage_due", - "valueType": "INT64" - }, - { - "name": "missed_payments_1y", - "valueType": "INT64" - } - ], - "featureViewName": "credit_history" - }, - { - "featureColumns": [ - { - "name": "city", - "valueType": "STRING" - }, - { - "name": "state", - "valueType": "STRING" - }, - { - "name": "location_type", - "valueType": "STRING" - }, - { - "name": "tax_returns_filed", - "valueType": "INT64" - }, - { - "name": "population", - "valueType": "INT64" - }, - { - "name": "total_wages", - "valueType": "INT64" - } - ], - "featureViewName": "zipcode_features" - } - ], - "name": "credit_score_v2", - "tags": { - "owner": "tony@tecton.ai", - "stage": "prod" - } - } - }, - { - "meta": { - "createdTimestamp": "2022-05-11T19:27:03.172264Z", - "lastUpdatedTimestamp": "2022-05-11T19:27:03.172264Z" - }, - "spec": { - "description": "Credit scoring model", - "features": [ - { - "featureColumns": [ - { - "name": "credit_card_due", - "valueType": "INT64" - }, - { - "name": "mortgage_due", - "valueType": "INT64" - }, - { - "name": "missed_payments_1y", - "valueType": "INT64" - } - ], - "featureViewName": "credit_history" - }, - { - "featureColumns": [ - { - "name": "city", - "valueType": "STRING" - }, - { - "name": "state", - "valueType": "STRING" - }, - { - "name": "location_type", - "valueType": "STRING" - }, - { - "name": "tax_returns_filed", - "valueType": "INT64" - }, - { - "name": "population", - "valueType": "INT64" - }, - { - "name": "total_wages", - "valueType": "INT64" - } - ], - "featureViewName": "zipcode_features" - }, - { - "featureColumns": [ - { - "name": "transaction_gt_last_credit_card_due", - "valueType": "BOOL" - } - ], - "featureViewName": "transaction_gt_last_credit_card_due" - } - ], - "name": "credit_score_v3", - "tags": { - "owner": "tony@tecton.ai", - "stage": "dev" - } - } - }, - { - "meta": { - "createdTimestamp": "2022-05-11T19:27:03.172530Z", - "lastUpdatedTimestamp": "2022-05-11T19:27:03.172530Z" - }, - "spec": { - "description": "Location model", - "features": [ - { - "featureColumns": [ - { - "name": "city", - "valueType": "STRING" - }, - { - "name": "state", - "valueType": "STRING" - }, - { - "name": "location_type", - "valueType": "STRING" - }, - { - "name": "tax_returns_filed", - "valueType": "INT64" - }, - { - "name": "population", - "valueType": "INT64" - }, - { - "name": "total_wages", - "valueType": "INT64" - } - ], - "featureViewName": "zipcode_features" - } - ], - "name": "zipcode_model", - "tags": { - "owner": "amanda@tecton.ai", - "stage": "dev" - } - } - }, - { - "meta": { - "createdTimestamp": "2022-05-11T19:27:03.172188Z", - "lastUpdatedTimestamp": "2022-05-11T19:27:03.172188Z" - }, - "spec": { - "description": "Location model", - "features": [ - { - "featureColumns": [ - { - "name": "tax_returns_filed", - "valueType": "INT64" - }, - { - "name": "total_wages", - "valueType": "INT64" - } - ], - "featureViewName": "zipcode_money_features" - } - ], - "name": "zipcode_model_v2", - "tags": { - "owner": "amanda@tecton.ai", - "stage": "dev" - } - } - } - ], - "featureViews": [ - { - "meta": { - "createdTimestamp": "2022-05-11T19:27:03.171421Z", - "lastUpdatedTimestamp": "2022-05-11T19:28:21.444739Z", - "materializationIntervals": [ - { - "endTime": "2019-05-11T19:27:05Z", - "startTime": "1997-09-19T19:27:13.273753Z" - }, - { - "endTime": "2022-05-11T19:27:43Z", - "startTime": "2019-05-11T19:27:05Z" - } - ] - }, - "spec": { - "batchSource": { - "createdTimestampColumn": "created_timestamp", - "dataSourceClassType": "feast.infra.offline_stores.file_source.FileSource", - "fileOptions": { - "uri": "data/credit_history.parquet" - }, - "name": "credit_history", - "timestampField": "event_timestamp", - "type": "BATCH_FILE" - }, - "entities": [ - "dob_ssn" - ], - "features": [ - { - "name": "credit_card_due", - "valueType": "INT64" - }, - { - "name": "mortgage_due", - "valueType": "INT64" - }, - { - "name": "student_loan_due", - "valueType": "INT64" - }, - { - "name": "vehicle_loan_due", - "valueType": "INT64" - }, - { - "name": "hard_pulls", - "valueType": "INT64" - }, - { - "name": "missed_payments_2y", - "valueType": "INT64" - }, - { - "name": "missed_payments_1y", - "valueType": "INT64" - }, - { - "name": "missed_payments_6m", - "valueType": "INT64" - }, - { - "name": "bankruptcies", - "valueType": "INT64" - } - ], - "name": "credit_history", - "online": true, - "tags": { - "access_group": "feast-team@tecton.ai", - "date_added": "2022-02-6", - "experiments": "experiment-A" - }, - "ttl": "777600000s" - } - }, - { - "meta": { - "createdTimestamp": "2022-05-11T19:27:03.171300Z", - "lastUpdatedTimestamp": "2022-05-11T19:27:46.002348Z", - "materializationIntervals": [ - { - "endTime": "2019-05-11T19:27:05Z", - "startTime": "2012-05-13T19:27:08.483036Z" - }, - { - "endTime": "2022-05-11T19:27:43Z", - "startTime": "2019-05-11T19:27:05Z" - } - ] - }, - "spec": { - "batchSource": { - "createdTimestampColumn": "created_timestamp", - "dataSourceClassType": "feast.infra.offline_stores.file_source.FileSource", - "fileOptions": { - "uri": "data/zipcode_table.parquet" - }, - "name": "zipcode", - "timestampField": "event_timestamp", - "type": "BATCH_FILE" - }, - "entities": [ - "zipcode" - ], - "features": [ - { - "name": "city", - "valueType": "STRING" - }, - { - "name": "state", - "valueType": "STRING" - }, - { - "name": "location_type", - "valueType": "STRING" - }, - { - "name": "tax_returns_filed", - "valueType": "INT64" - }, - { - "name": "population", - "valueType": "INT64" - }, - { - "name": "total_wages", - "valueType": "INT64" - } - ], - "name": "zipcode_features", - "online": true, - "tags": { - "access_group": "feast-team@tecton.ai", - "date_added": "2022-02-7", - "experiments": "experiment-A,experiment-B,experiment-C" - }, - "ttl": "315360000s" - } - }, - { - "meta": { - "createdTimestamp": "2022-05-11T19:27:03.171195Z", - "lastUpdatedTimestamp": "2022-05-11T19:27:45.942549Z", - "materializationIntervals": [ - { - "endTime": "2019-05-11T19:27:05Z", - "startTime": "2012-05-13T19:27:06.493847Z" - }, - { - "endTime": "2022-05-11T19:27:43Z", - "startTime": "2019-05-11T19:27:05Z" - } - ] - }, - "spec": { - "batchSource": { - "createdTimestampColumn": "created_timestamp", - "dataSourceClassType": "feast.infra.offline_stores.file_source.FileSource", - "fileOptions": { - "uri": "data/zipcode_table.parquet" - }, - "name": "zipcode", - "timestampField": "event_timestamp", - "type": "BATCH_FILE" - }, - "entities": [ - "zipcode" - ], - "features": [ - { - "name": "tax_returns_filed", - "valueType": "INT64" - }, - { - "name": "total_wages", - "valueType": "INT64" - } - ], - "name": "zipcode_money_features", - "online": true, - "tags": { - "access_group": "feast-team@tecton.ai", - "date_added": "2022-02-7", - "experiments": "experiment-A,experiment-B,experiment-C" - }, - "ttl": "315360000s" - } - } - ], - "infra": [ - { - "name": "credit_scoring_aws_credit_history", - "path": "/Users/dannychiao/GitHub/feast/ui/feature_repo/data/online.db" - }, - { - "name": "credit_scoring_aws_zipcode_features", - "path": "/Users/dannychiao/GitHub/feast/ui/feature_repo/data/online.db" - }, - { - "name": "credit_scoring_aws_zipcode_money_features", - "path": "/Users/dannychiao/GitHub/feast/ui/feature_repo/data/online.db" - } - ], - "onDemandFeatureViews": [ - { - "meta": { - "createdTimestamp": "2022-05-11T19:27:03.171556Z", - "lastUpdatedTimestamp": "2022-05-11T19:27:03.171556Z" - }, - "spec": { - "features": [ - { - "name": "transaction_gt_last_credit_card_due", - "valueType": "BOOL" - } - ], - "name": "transaction_gt_last_credit_card_due", - "sources": { - "credit_history": { - "featureViewProjection": { - "featureColumns": [ - { - "name": "credit_card_due", - "valueType": "INT64" - }, - { - "name": "mortgage_due", - "valueType": "INT64" - }, - { - "name": "student_loan_due", - "valueType": "INT64" - }, - { - "name": "vehicle_loan_due", - "valueType": "INT64" - }, - { - "name": "hard_pulls", - "valueType": "INT64" - }, - { - "name": "missed_payments_2y", - "valueType": "INT64" - }, - { - "name": "missed_payments_1y", - "valueType": "INT64" - }, - { - "name": "missed_payments_6m", - "valueType": "INT64" - }, - { - "name": "bankruptcies", - "valueType": "INT64" - } - ], - "featureViewName": "credit_history" - } - }, - "transaction": { - "requestDataSource": { - "name": "transaction", - "requestDataOptions": { - "schema": [ - { - "name": "transaction_amt", - "valueType": "INT64" - } - ] - }, - "type": "REQUEST_SOURCE" - } - } - }, - "userDefinedFunction": { - "body": "@on_demand_feature_view(\n sources=[credit_history, input_request],\n schema=[\n Field(name=\"transaction_gt_last_credit_card_due\", dtype=Bool),\n ],\n)\ndef transaction_gt_last_credit_card_due(inputs: pd.DataFrame) -> pd.DataFrame:\n df = pd.DataFrame()\n df[\"transaction_gt_last_credit_card_due\"] = (\n inputs[\"transaction_amt\"] > inputs[\"credit_card_due\"]\n )\n return df\n", - "name": "transaction_gt_last_credit_card_due" - } - } - } - ], - "streamFeatureViews": [ - { - "meta": { - "createdTimestamp": "2022-05-11T19:27:03.171556Z", - "lastUpdatedTimestamp": "2022-05-11T19:27:03.171556Z" - }, - "spec": { - "batchSource": { - "createdTimestampColumn": "created_timestamp", - "dataSourceClassType": "feast.infra.offline_stores.file_source.FileSource", - "fileOptions": { - "uri": "data/zipcode_table.parquet" - }, - "name": "zipcode", - "timestampField": "event_timestamp", - "type": "BATCH_FILE" - }, - "features": [ - { - "name": "conv_percentage", - "valueType": "FLOAT" - }, - { - "name": "acc_percentage", - "valueType": "FLOAT" - } - ], - "name": "transaction_stream_example", - "streamSource": { - "batchSource": { - "fileOptions": { - "uri": "data/zipcode_table.parquet" - }, - "name": "user_stats", - "timestampField": "timestamp", - "type": "BATCH_FILE" - }, - "dataSourceClassType": "feast.data_source.KafkaSource", - "description": "The Kafka stream example", - "kafkaOptions": {"messageFormat": {"jsonFormat": {"schemaJson": "id string, timestamp timestamp"}}, - "watermarkDelayThreshold": "300s"}, - "name": "driver_stats_stream", - "owner": "test@gmail.com", - "timestampField": "timestamp", - "type": "STREAM_KAFKA" - }, - "ttl": "86400s", - "userDefinedFunction": { - "body": "@stream_feature_view(\n sources=[driver_stats_stream_source],\n mode=\"spark\",\n schema=[\n Field(name=\"conv_percentage\", dtype=Float32),\n Field(name=\"acc_percentage\", dtype=Float32),\n ],\n timestamp_field=\"event_timestamp\",\n online=True,\n source=driver_stats_stream_source,\n tags={},\n)\ndef driver_hourly_stats_stream(df: DataFrame) -> DataFrame:\n from pyspark.sql.functions import col\n return (\n df.withColumn(\"conv_percentage\", col(\"conv_rate\") * 100.0)\n .withColumn(\"acc_percentage\", col(\"acc_rate\") * 100.0)\n .drop(\"conv_rate\", \"acc_rate\")\n )\n", - "name": "driver_hourly_stats_stream" - } - } - } - ], - "project": "credit_scoring_aws" -} diff --git a/ui/src/components/FeaturesInServiceDisplay.tsx b/ui/src/components/FeaturesInServiceDisplay.tsx index 39091b81de..6ca2fcc8b0 100644 --- a/ui/src/components/FeaturesInServiceDisplay.tsx +++ b/ui/src/components/FeaturesInServiceDisplay.tsx @@ -1,36 +1,26 @@ import React from "react"; -import { z } from "zod"; import { EuiBasicTable } from "@elastic/eui"; -import { FeastFeatureInServiceType } from "../parsers/feastFeatureServices"; import EuiCustomLink from "./EuiCustomLink"; -import { FEAST_FEATURE_VALUE_TYPES } from "../parsers/types"; import { useParams } from "react-router-dom"; +import { feast } from "../protos"; interface FeatureViewsListInterace { - featureViews: FeastFeatureInServiceType[]; + featureViews: feast.core.IFeatureViewProjection[]; +} + +interface IFeatureColumnInService { + featureViewName: string; + name: string; + valueType: feast.types.ValueType.Enum; } const FeaturesInServiceList = ({ featureViews }: FeatureViewsListInterace) => { const { projectName } = useParams(); - - const FeatureInService = z.object({ - featureViewName: z.string(), - featureColumnName: z.string(), - valueType: z.nativeEnum(FEAST_FEATURE_VALUE_TYPES), - }); - type FeatureInServiceType = z.infer; - - var items: FeatureInServiceType[] = []; - featureViews.forEach((featureView) => { - featureView.featureColumns.forEach((featureColumn) => { - const row: FeatureInServiceType = { - featureViewName: featureView.featureViewName, - featureColumnName: featureColumn.name, - valueType: featureColumn.valueType, - }; - items.push(row); - }); - }); + const items: IFeatureColumnInService[] = featureViews.flatMap(featureView => featureView.featureColumns!.map(featureColumn => ({ + featureViewName: featureView.featureViewName!, + name: featureColumn.name!, + valueType: featureColumn.valueType!, + }))); const columns = [ { @@ -49,15 +39,18 @@ const FeaturesInServiceList = ({ featureViews }: FeatureViewsListInterace) => { }, { name: "Feature Column", - field: "featureColumnName", + field: "name", }, { name: "Value Type", field: "valueType", + render: (valueType: feast.types.ValueType.Enum) => { + return feast.types.ValueType.Enum[valueType]; + }, }, ]; - const getRowProps = (item: FeatureInServiceType) => { + const getRowProps = (item: IFeatureColumnInService) => { return { "data-test-subj": `row-${item.featureViewName}`, }; diff --git a/ui/src/components/FeaturesListDisplay.tsx b/ui/src/components/FeaturesListDisplay.tsx index dcb6ba81eb..a40730c687 100644 --- a/ui/src/components/FeaturesListDisplay.tsx +++ b/ui/src/components/FeaturesListDisplay.tsx @@ -1,38 +1,39 @@ -import React, { useContext } from "react"; -import { EuiBasicTable, EuiLoadingSpinner, EuiBadge } from "@elastic/eui"; -import { FeastFeatureColumnType } from "../parsers/feastFeatureViews"; -import useLoadFeatureViewSummaryStatistics from "../queries/useLoadFeatureViewSummaryStatistics"; -import SparklineHistogram from "./SparklineHistogram"; -import FeatureFlagsContext from "../contexts/FeatureFlagsContext"; +import { EuiBasicTable } from "@elastic/eui"; import EuiCustomLink from "./EuiCustomLink"; +import { feast } from "../protos"; interface FeaturesListProps { projectName: string; featureViewName: string; - features: FeastFeatureColumnType[]; + features: feast.core.IFeatureSpecV2[]; link: boolean; } -const FeaturesList = ({ projectName, featureViewName, features, link }: FeaturesListProps) => { - const { enabledFeatureStatistics } = useContext(FeatureFlagsContext); - const { isLoading, isError, isSuccess, data } = - useLoadFeatureViewSummaryStatistics(featureViewName); - +const FeaturesList = ({ + projectName, + featureViewName, + features, + link, +}: FeaturesListProps) => { let columns: { name: string; render?: any; field: any }[] = [ - { + { name: "Name", field: "name", - render: (item: string) => ( - ( + + to={`/p/${projectName}/feature-view/${featureViewName}/feature/${item}`} + > {item} - ) + ), }, { name: "Value Type", field: "valueType", + render: (valueType: feast.types.ValueType.Enum) => { + return feast.types.ValueType.Enum[valueType]; + }, }, ]; @@ -40,50 +41,7 @@ const FeaturesList = ({ projectName, featureViewName, features, link }: Features columns[0].render = undefined; } - if (enabledFeatureStatistics) { - columns.push( - ...[ - { - name: "Sample", - field: "", - render: (item: FeastFeatureColumnType) => { - const statistics = - isSuccess && data && data.columnsSummaryStatistics[item.name]; - - return ( - - {isLoading && } - {isError && ( - error loading samples - )} - {statistics && statistics.sampleValues.join(",")} - - ); - }, - }, - { - name: "Sparklines", - field: "", - render: (item: FeastFeatureColumnType) => { - const statistics = - isSuccess && data && data.columnsSummaryStatistics[item.name]; - - if ( - statistics && - statistics.valueType === "INT64" && - statistics.histogram - ) { - return ; - } else { - return ""; - } - }, - }, - ] - ); - } - - const getRowProps = (item: FeastFeatureColumnType) => { + const getRowProps = (item: feast.core.IFeatureSpecV2) => { return { "data-test-subj": `row-${item.name}`, }; diff --git a/ui/src/components/NumericFeaturesTable.tsx b/ui/src/components/NumericFeaturesTable.tsx deleted file mode 100644 index 7c55f5ddba..0000000000 --- a/ui/src/components/NumericFeaturesTable.tsx +++ /dev/null @@ -1,60 +0,0 @@ -import { EuiBasicTable } from "@elastic/eui"; -import React from "react"; -import { NumericColumnSummaryStatisticType } from "../parsers/featureViewSummaryStatistics"; -import SparklineHistogram from "./SparklineHistogram"; - -interface NumericFeaturesTableProps { - data: NumericColumnSummaryStatisticType[]; -} - -const NumericFeaturesTable = ({ data }: NumericFeaturesTableProps) => { - const columns = [ - { name: "Name", field: "name" }, - { - name: "Value Type", - field: "valueType", - }, - { - name: "Sample", - render: (statistics: NumericColumnSummaryStatisticType) => { - return ( - - {statistics && statistics.sampleValues.join(",")} - - ); - }, - }, - { - name: "Min/Max", - render: (statistics: NumericColumnSummaryStatisticType) => { - return statistics.min !== undefined && statistics.max !== undefined - ? `${statistics.min}/${statistics.max}` - : undefined; - }, - }, - { name: "zeros", field: "proportionOfZeros" }, - { name: "missing", field: "proportionMissing" }, - { - name: "Sparklines", - render: (statistics: NumericColumnSummaryStatisticType) => { - if (statistics && statistics.histogram) { - return ; - } else { - return ""; - } - }, - }, - ]; - - const getRowProps = (item: NumericColumnSummaryStatisticType) => { - return { - "data-test-subj": `row-${item.name}`, - }; - }; - - return ( - - ); -}; - -export default NumericFeaturesTable; diff --git a/ui/src/components/SparklineHistogram.tsx b/ui/src/components/SparklineHistogram.tsx deleted file mode 100644 index bd632ec20d..0000000000 --- a/ui/src/components/SparklineHistogram.tsx +++ /dev/null @@ -1,58 +0,0 @@ -import React from "react"; -import { HistogramDataType } from "../parsers/featureViewSummaryStatistics"; -import { extent } from "d3-array"; -import { scaleLinear } from "d3"; -import { EuiBadge, useEuiTheme } from "@elastic/eui"; - -interface SparklineHistogramProps { - data: HistogramDataType; -} - -const SparklineHistogram = ({ data }: SparklineHistogramProps) => { - const width = 100; - const height = 24; - - const yMax = height - 2; - - const { euiTheme } = useEuiTheme(); - - if (data.length > 0) { - const x0Extent = extent(data, (d) => d.x0) as [number, number]; - const xScale = scaleLinear() - .domain(x0Extent) - .range([0, width - width / data.length]); - - const yExtent = extent(data, (d) => d.count) as [number, number]; - const yScale = scaleLinear().domain(yExtent).range([0, yMax]); - - return ( - - - {data.map((d) => { - const barHeight = yScale(d.count); - - return ( - - ); - })} - - ); - } else { - return histogram n/a; - } -}; - -export default SparklineHistogram; diff --git a/ui/src/hooks/useFCOExploreSuggestions.ts b/ui/src/hooks/useFCOExploreSuggestions.ts index 5767f73bed..822642daf4 100644 --- a/ui/src/hooks/useFCOExploreSuggestions.ts +++ b/ui/src/hooks/useFCOExploreSuggestions.ts @@ -1,9 +1,9 @@ import { encodeSearchQueryString } from "./encodeSearchQueryString"; import { FEAST_FCO_TYPES } from "../parsers/types"; -import { FeastFeatureViewType } from "../parsers/feastFeatureViews"; import { useParams } from "react-router-dom"; import { useFeatureViewTagsAggregation } from "./useTagsAggregation"; +import { feast } from "../protos"; interface ExplorationSuggestionItem { name: string; @@ -66,14 +66,14 @@ const sortTagsByTotalUsage = ( }; const generateExplorationSuggestions = ( - tagAggregation: Record>, + tagAggregation: Record>, projectName: string ) => { const suggestions: ExplorationSuggestion[] = []; if (tagAggregation) { const SortedCandidates = - sortTagByUniqueValues(tagAggregation); + sortTagByUniqueValues(tagAggregation); SortedCandidates.slice(0, NUMBER_OF_SUGGESTION_GROUPS).forEach( ([selectedTag, selectedTagValuesMap]) => { diff --git a/ui/src/hooks/useTagsAggregation.ts b/ui/src/hooks/useTagsAggregation.ts index 21480fa8b0..13d0c2f966 100644 --- a/ui/src/hooks/useTagsAggregation.ts +++ b/ui/src/hooks/useTagsAggregation.ts @@ -1,8 +1,7 @@ import { useContext, useMemo } from "react"; import RegistryPathContext from "../contexts/RegistryPathContext"; -import { FeastFeatureServiceType } from "../parsers/feastFeatureServices"; -import { FeastFeatureViewType } from "../parsers/feastFeatureViews"; import useLoadRegistry from "../queries/useLoadRegistry"; +import { feast } from "../protos"; // Usage of generic type parameter T // https://stackoverflow.com/questions/53203409/how-to-tell-typescript-that-im-returning-an-array-of-arrays-of-the-input-type @@ -44,12 +43,12 @@ const useFeatureViewTagsAggregation = () => { const data = useMemo(() => { return query.data && query.data.objects && query.data.objects.featureViews - ? buildTagCollection( - query.data.objects.featureViews, - (fv) => { - return fv.spec.tags; - } - ) + ? buildTagCollection( + query.data.objects.featureViews!, + (fv) => { + return fv.spec?.tags!; + } + ) : undefined; }, [query.data]); @@ -67,12 +66,12 @@ const useFeatureServiceTagsAggregation = () => { return query.data && query.data.objects && query.data.objects.featureServices - ? buildTagCollection( - query.data.objects.featureServices, - (fs) => { - return fs.spec.tags; - } - ) + ? buildTagCollection( + query.data.objects.featureServices, + (fs) => { + return fs.spec?.tags!; + } + ) : undefined; }, [query.data]); diff --git a/ui/src/pages/data-sources/BatchSourcePropertiesView.tsx b/ui/src/pages/data-sources/BatchSourcePropertiesView.tsx index 97f9f58d27..c19e4ff50f 100644 --- a/ui/src/pages/data-sources/BatchSourcePropertiesView.tsx +++ b/ui/src/pages/data-sources/BatchSourcePropertiesView.tsx @@ -1,38 +1,16 @@ import React from "react"; import { - EuiCodeBlock, EuiDescriptionList, EuiDescriptionListDescription, EuiDescriptionListTitle, EuiFlexGroup, EuiFlexItem, - EuiSpacer, - EuiTitle, } from "@elastic/eui"; +import { feast } from "../../protos"; +import { toDate } from "../../utils/timestamp"; interface BatchSourcePropertiesViewProps { - batchSource: { - type?: string | undefined; - owner?: string | undefined; - description?: string | undefined; - dataSourceClassType?: string | undefined; - fileOptions?: - | { - uri?: string | undefined; - } - | undefined; - meta?: - | { - latestEventTimestamp?: Date | undefined; - earliestEventTimestamp?: Date | undefined; - } - | undefined; - bigqueryOptions?: - | { - dbtModelSerialized?: string | undefined; - } - | undefined; - }; + batchSource: feast.core.IDataSource; } const BatchSourcePropertiesView = (props: BatchSourcePropertiesViewProps) => { @@ -49,7 +27,7 @@ const BatchSourcePropertiesView = (props: BatchSourcePropertiesViewProps) => { {batchSource.dataSourceClassType.split(".").at(-1)} - ) : batchSource.type ? ( + ) : feast.core.DataSource.SourceType[batchSource.type!] ? ( {batchSource.type} @@ -87,9 +65,9 @@ const BatchSourcePropertiesView = (props: BatchSourcePropertiesViewProps) => { Latest Event - {batchSource.meta.latestEventTimestamp.toLocaleDateString( - "en-CA" - )} + {toDate( + batchSource.meta.latestEventTimestamp + ).toLocaleDateString("en-CA")} )} @@ -99,35 +77,14 @@ const BatchSourcePropertiesView = (props: BatchSourcePropertiesViewProps) => { Earliest Event - {batchSource.meta.earliestEventTimestamp.toLocaleDateString( - "en-CA" - )} + {toDate( + batchSource.meta?.earliestEventTimestamp + ).toLocaleDateString("en-CA")} )} - - {batchSource.bigqueryOptions?.dbtModelSerialized && ( - - - - )} - {batchSource.bigqueryOptions?.dbtModelSerialized && ( - - -

Dbt Transformation

-
- - {batchSource.bigqueryOptions.dbtModelSerialized} - -
- )} ); diff --git a/ui/src/pages/data-sources/DataSourceDbt.tsx b/ui/src/pages/data-sources/DataSourceDbt.tsx deleted file mode 100644 index 4e61ba8026..0000000000 --- a/ui/src/pages/data-sources/DataSourceDbt.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import React from "react"; -import { - EuiCodeBlock, - EuiPanel, - EuiHorizontalRule, - EuiTitle, -} from "@elastic/eui"; -import { useParams } from "react-router-dom"; -import useLoadDataSource from "./useLoadDataSource"; - -const DataSourceDbt = () => { - let { dataSourceName } = useParams(); - - const dsName = dataSourceName === undefined ? "" : dataSourceName; - - const { isSuccess, data } = useLoadDataSource(dsName); - - return isSuccess && data && data.bigqueryOptions ? ( - - -

Dbt Transformation

-
- - - {data.bigqueryOptions.dbtModelSerialized} - -
- ) : ( - - No data so sad - - ); -}; - -export default DataSourceDbt; diff --git a/ui/src/pages/data-sources/DataSourceInstance.tsx b/ui/src/pages/data-sources/DataSourceInstance.tsx index 332f51e023..d6db4c8747 100644 --- a/ui/src/pages/data-sources/DataSourceInstance.tsx +++ b/ui/src/pages/data-sources/DataSourceInstance.tsx @@ -7,12 +7,10 @@ import { } from "@elastic/eui"; import { DataSourceIcon32 } from "../../graphics/DataSourceIcon"; -import { useMatchExact, useMatchSubpath } from "../../hooks/useMatchSubpath"; +import { useMatchExact } from "../../hooks/useMatchSubpath"; import { useDocumentTitle } from "../../hooks/useDocumentTitle"; import DataSourceRawData from "./DataSourceRawData"; import DataSourceOverviewTab from "./DataSourceOverviewTab"; -import DataSourceDbt from "./DataSourceDbt"; -import useLoadDataSource from "./useLoadDataSource"; import { useDataSourceCustomTabs, @@ -24,8 +22,6 @@ const DataSourceInstance = () => { let { dataSourceName } = useParams(); useDocumentTitle(`${dataSourceName} | Data Source | Feast`); - const dsName = dataSourceName === undefined ? "" : dataSourceName; - const { isSuccess, data } = useLoadDataSource(dsName); let tabs = [ { @@ -37,17 +33,6 @@ const DataSourceInstance = () => { }, ]; - const dbtTab = { - label: "Dbt Definition", - isSelected: useMatchSubpath("dbt"), - onClick: () => { - navigate("dbt"); - }, - }; - if (isSuccess && data?.bigqueryOptions?.dbtModelSerialized) { - tabs.push(dbtTab); - } - const { customNavigationTabs } = useDataSourceCustomTabs(navigate); tabs = tabs.concat(customNavigationTabs); @@ -72,7 +57,6 @@ const DataSourceInstance = () => { } /> } /> - } /> {CustomTabRoutes} diff --git a/ui/src/pages/data-sources/DataSourceOverviewTab.tsx b/ui/src/pages/data-sources/DataSourceOverviewTab.tsx index 124a0e6ab9..6eadfc42d0 100644 --- a/ui/src/pages/data-sources/DataSourceOverviewTab.tsx +++ b/ui/src/pages/data-sources/DataSourceOverviewTab.tsx @@ -19,6 +19,7 @@ import BatchSourcePropertiesView from "./BatchSourcePropertiesView"; import FeatureViewEdgesList from "../entities/FeatureViewEdgesList"; import RequestDataSourceSchemaTable from "./RequestDataSourceSchemaTable"; import useLoadDataSource from "./useLoadDataSource"; +import { feast } from "../../protos"; const DataSourceOverviewTab = () => { let { dataSourceName } = useParams(); @@ -57,7 +58,7 @@ const DataSourceOverviewTab = () => { Source Type - {data.type} + {feast.core.DataSource.SourceType[data.type]} @@ -77,12 +78,12 @@ const DataSourceOverviewTab = () => { { + fields={data?.requestDataOptions?.schema!.map((obj) => { return { - fieldName: obj.name, - valueType: obj.valueType, + fieldName: obj.name!, + valueType: obj.valueType!, }; - })} + })!} /> ) : ( diff --git a/ui/src/pages/data-sources/DataSourcesListingTable.tsx b/ui/src/pages/data-sources/DataSourcesListingTable.tsx index 661d18c7e9..50c1f933a9 100644 --- a/ui/src/pages/data-sources/DataSourcesListingTable.tsx +++ b/ui/src/pages/data-sources/DataSourcesListingTable.tsx @@ -1,11 +1,11 @@ import React from "react"; import { EuiBasicTable } from "@elastic/eui"; import EuiCustomLink from "../../components/EuiCustomLink"; -import { FeastDatasourceType } from "../../parsers/feastDatasources"; import { useParams } from "react-router-dom"; +import { feast } from "../../protos"; interface DatasourcesListingTableProps { - dataSources: FeastDatasourceType[]; + dataSources: feast.core.IDataSource[]; } const DatasourcesListingTable = ({ @@ -33,10 +33,13 @@ const DatasourcesListingTable = ({ name: "Type", field: "type", sortable: true, + render: (valueType: feast.types.ValueType.Enum) => { + return feast.types.ValueType.Enum[valueType]; + }, }, ]; - const getRowProps = (item: FeastDatasourceType) => { + const getRowProps = (item: feast.core.IDataSource) => { return { "data-test-subj": `row-${item.name}`, }; diff --git a/ui/src/pages/data-sources/RequestDataSourceSchemaTable.tsx b/ui/src/pages/data-sources/RequestDataSourceSchemaTable.tsx index 60ef4c406a..a55aeac028 100644 --- a/ui/src/pages/data-sources/RequestDataSourceSchemaTable.tsx +++ b/ui/src/pages/data-sources/RequestDataSourceSchemaTable.tsx @@ -1,10 +1,10 @@ import React from "react"; import { EuiBasicTable } from "@elastic/eui"; -import { FEAST_FEATURE_VALUE_TYPES } from "../../parsers/types"; +import { feast } from "../../protos"; interface RequestDataSourceSchemaField { fieldName: string; - valueType: FEAST_FEATURE_VALUE_TYPES; + valueType: feast.types.ValueType.Enum; } interface RequestDataSourceSchema { @@ -12,7 +12,6 @@ interface RequestDataSourceSchema { } const RequestDataSourceSchemaTable = ({ fields }: RequestDataSourceSchema) => { - console.log(fields); const columns = [ { name: "Field", @@ -21,6 +20,9 @@ const RequestDataSourceSchemaTable = ({ fields }: RequestDataSourceSchema) => { { name: "Value Type", field: "valueType", + render: (valueType: feast.types.ValueType.Enum) => { + return feast.types.ValueType.Enum[valueType]; + }, }, ]; diff --git a/ui/src/pages/entities/EntitiesListingTable.tsx b/ui/src/pages/entities/EntitiesListingTable.tsx index 2e608e3769..2a017b18aa 100644 --- a/ui/src/pages/entities/EntitiesListingTable.tsx +++ b/ui/src/pages/entities/EntitiesListingTable.tsx @@ -1,12 +1,12 @@ import React from "react"; import { EuiBasicTable } from "@elastic/eui"; import EuiCustomLink from "../../components/EuiCustomLink"; -import { FeastEntityType } from "../../parsers/feastEntities"; import useFeatureViewEdgesByEntity from "./useFeatureViewEdgesByEntity"; import { useParams } from "react-router-dom"; +import { feast } from "../../protos"; interface EntitiesListingTableProps { - entities: FeastEntityType[]; + entities: feast.core.IEntity[]; } const EntitiesListingTable = ({ entities }: EntitiesListingTableProps) => { @@ -33,15 +33,15 @@ const EntitiesListingTable = ({ entities }: EntitiesListingTableProps) => { name: "Type", field: "spec.valueType", sortable: true, - render: (valueType: string) => { - return valueType; + render: (valueType: feast.types.ValueType.Enum) => { + return feast.types.ValueType.Enum[valueType]; }, }, { name: "# of FVs", - render: (item: FeastEntityType) => { + render: (item: feast.core.IEntity) => { if (isSuccess && data) { - return data[item.spec.name] ? data[item.spec.name].length : "0"; + return data[item?.spec?.name!] ? data[item?.spec?.name!].length : "0"; } else { return "."; } @@ -49,9 +49,9 @@ const EntitiesListingTable = ({ entities }: EntitiesListingTableProps) => { }, ]; - const getRowProps = (item: FeastEntityType) => { + const getRowProps = (item: feast.core.IEntity) => { return { - "data-test-subj": `row-${item.spec.name}`, + "data-test-subj": `row-${item?.spec?.name}`, }; }; diff --git a/ui/src/pages/entities/EntityOverviewTab.tsx b/ui/src/pages/entities/EntityOverviewTab.tsx index dc649c2a9f..b4df67bba4 100644 --- a/ui/src/pages/entities/EntityOverviewTab.tsx +++ b/ui/src/pages/entities/EntityOverviewTab.tsx @@ -19,6 +19,8 @@ import TagsDisplay from "../../components/TagsDisplay"; import FeatureViewEdgesList from "./FeatureViewEdgesList"; import useFeatureViewEdgesByEntity from "./useFeatureViewEdgesByEntity"; import useLoadEntity from "./useLoadEntity"; +import { toDate } from "../../utils/timestamp"; +import { feast } from "../../protos"; const EntityOverviewTab = () => { let { entityName } = useParams(); @@ -52,17 +54,17 @@ const EntityOverviewTab = () => { Join Key - {data.spec.joinKey} + {data?.spec?.joinKey} Description - {data.spec.description} + {data?.spec?.description} Value Type - {data.spec.valueType} + {feast.types.ValueType.Enum[data?.spec?.valueType!]} @@ -71,8 +73,8 @@ const EntityOverviewTab = () => { Created - {data.meta.createdTimestamp ? ( - data.meta.createdTimestamp.toLocaleDateString("en-CA") + {data?.meta?.createdTimestamp ? ( + toDate(data.meta.createdTimestamp).toLocaleDateString("en-CA") ) : ( No createdTimestamp specified on this entity. )} @@ -80,8 +82,8 @@ const EntityOverviewTab = () => { Updated - {data.meta.lastUpdatedTimestamp ? ( - data.meta.lastUpdatedTimestamp.toLocaleDateString("en-CA") + {data?.meta?.lastUpdatedTimestamp ? ( + toDate(data.meta.lastUpdatedTimestamp).toLocaleDateString("en-CA") ) : ( No lastUpdatedTimestamp specified on this entity. )} @@ -117,8 +119,8 @@ const EntityOverviewTab = () => {

Labels

- {data.spec.labels ? ( - + {data?.spec?.tags ? ( + ) : ( No labels specified on this entity. )} diff --git a/ui/src/pages/entities/useLoadEntity.ts b/ui/src/pages/entities/useLoadEntity.ts index a1ca6d55c1..6f7bb1f59c 100644 --- a/ui/src/pages/entities/useLoadEntity.ts +++ b/ui/src/pages/entities/useLoadEntity.ts @@ -10,8 +10,8 @@ const useLoadEntity = (entityName: string) => { registryQuery.data === undefined ? undefined : registryQuery.data.objects.entities?.find( - (fv) => fv.spec.name === entityName - ); + (fv) => fv?.spec?.name === entityName + ); return { ...registryQuery, diff --git a/ui/src/pages/feature-services/FeatureServiceListingTable.tsx b/ui/src/pages/feature-services/FeatureServiceListingTable.tsx index b865da6e23..c81edeaeb5 100644 --- a/ui/src/pages/feature-services/FeatureServiceListingTable.tsx +++ b/ui/src/pages/feature-services/FeatureServiceListingTable.tsx @@ -5,20 +5,18 @@ import { EuiTableFieldDataColumnType, } from "@elastic/eui"; import EuiCustomLink from "../../components/EuiCustomLink"; -import { - FeastFeatureInServiceType, - FeastFeatureServiceType, -} from "../../parsers/feastFeatureServices"; import { useParams } from "react-router-dom"; +import { feast } from "../../protos"; +import { toDate } from "../../utils/timestamp"; interface FeatureServiceListingTableProps { tagKeysSet: Set; - featureServices: FeastFeatureServiceType[]; + featureServices: feast.core.IFeatureService[]; } type FeatureServiceTypeColumn = - | EuiTableFieldDataColumnType - | EuiTableComputedColumnType; + | EuiTableFieldDataColumnType + | EuiTableComputedColumnType; const FeatureServiceListingTable = ({ tagKeysSet, @@ -44,10 +42,10 @@ const FeatureServiceListingTable = ({ { name: "# of Features", field: "spec.features", - render: (featureViews: FeastFeatureInServiceType[]) => { + render: (featureViews: feast.core.IFeatureViewProjection[]) => { var numFeatures = 0; featureViews.forEach((featureView) => { - numFeatures += featureView.featureColumns.length; + numFeatures += featureView.featureColumns!.length; }); return numFeatures; }, @@ -55,8 +53,8 @@ const FeatureServiceListingTable = ({ { name: "Last updated", field: "meta.lastUpdatedTimestamp", - render: (date: Date) => { - return date ? date.toLocaleDateString("en-CA") : "n/a"; + render: (date: any) => { + return date ? toDate(date).toLocaleDateString("en-CA") : "n/a"; }, }, ]; @@ -64,10 +62,10 @@ const FeatureServiceListingTable = ({ tagKeysSet.forEach((key) => { columns.push({ name: key, - render: (item: FeastFeatureServiceType) => { + render: (item: feast.core.IFeatureService) => { let tag = n/a; - const value = item.spec.tags ? item.spec.tags[key] : undefined; + const value = item?.spec?.tags ? item.spec.tags[key] : undefined; if (value) { tag = {value}; @@ -78,9 +76,9 @@ const FeatureServiceListingTable = ({ }); }); - const getRowProps = (item: FeastFeatureServiceType) => { + const getRowProps = (item: feast.core.IFeatureService) => { return { - "data-test-subj": `row-${item.spec.name}`, + "data-test-subj": `row-${item?.spec?.name}`, }; }; diff --git a/ui/src/pages/feature-services/FeatureServiceOverviewTab.tsx b/ui/src/pages/feature-services/FeatureServiceOverviewTab.tsx index ea62b3b3a7..387320778f 100644 --- a/ui/src/pages/feature-services/FeatureServiceOverviewTab.tsx +++ b/ui/src/pages/feature-services/FeatureServiceOverviewTab.tsx @@ -19,6 +19,7 @@ import TagsDisplay from "../../components/TagsDisplay"; import { encodeSearchQueryString } from "../../hooks/encodeSearchQueryString"; import FeatureViewEdgesList from "../entities/FeatureViewEdgesList"; import useLoadFeatureService from "./useLoadFeatureService"; +import { toDate } from "../../utils/timestamp"; const FeatureServiceOverviewTab = () => { let { featureServiceName, projectName } = useParams(); @@ -32,9 +33,9 @@ const FeatureServiceOverviewTab = () => { let numFeatures = 0; let numFeatureViews = 0; if (data) { - data.spec.features.forEach((featureView) => { + data?.spec?.features?.forEach((featureView) => { numFeatureViews += 1; - numFeatures += featureView.featureColumns.length; + numFeatures += featureView?.featureColumns!.length; }); } @@ -66,10 +67,10 @@ const FeatureServiceOverviewTab = () => { description="Feature Views" /> - {data.meta.lastUpdatedTimestamp ? ( + {data?.meta?.lastUpdatedTimestamp ? ( {

Features

- {data.spec.features ? ( - + {data?.spec?.features ? ( + ) : ( No features specified for this feature service. @@ -103,7 +104,7 @@ const FeatureServiceOverviewTab = () => {

Tags

- {data.spec.tags ? ( + {data?.spec?.tags ? ( { @@ -154,11 +155,11 @@ const FeatureServiceOverviewTab = () => {

All Feature Views

- {data.spec.features.length > 0 ? ( + {data?.spec?.features?.length! > 0 ? ( { - return f.featureViewName; - })} + fvNames={data?.spec?.features?.map((f) => { + return f.featureViewName!; + })!} /> ) : ( No feature views in this feature service diff --git a/ui/src/pages/feature-services/Index.tsx b/ui/src/pages/feature-services/Index.tsx index 441f3cf82c..d034a24bd7 100644 --- a/ui/src/pages/feature-services/Index.tsx +++ b/ui/src/pages/feature-services/Index.tsx @@ -22,12 +22,12 @@ import { filterInputInterface, tagTokenGroupsType, } from "../../hooks/useSearchInputWithTags"; -import { FeastFeatureServiceType } from "../../parsers/feastFeatureServices"; import { useDocumentTitle } from "../../hooks/useDocumentTitle"; import RegistryPathContext from "../../contexts/RegistryPathContext"; import FeatureServiceIndexEmptyState from "./FeatureServiceIndexEmptyState"; import TagSearch from "../../components/TagSearch"; import { useFeatureServiceTagsAggregation } from "../../hooks/useTagsAggregation"; +import { feast } from "../../protos"; const useLoadFeatureServices = () => { const registryUrl = useContext(RegistryPathContext); @@ -45,11 +45,11 @@ const useLoadFeatureServices = () => { }; const shouldIncludeFSsGivenTokenGroups = ( - entry: FeastFeatureServiceType, + entry: feast.core.IFeatureService, tagTokenGroups: tagTokenGroupsType ) => { return Object.entries(tagTokenGroups).every(([key, values]) => { - const entryTagValue = entry.spec.tags ? entry.spec.tags[key] : undefined; + const entryTagValue = entry?.spec?.tags ? entry.spec.tags[key] : undefined; if (entryTagValue) { return values.every((value) => { @@ -62,7 +62,7 @@ const shouldIncludeFSsGivenTokenGroups = ( }; const filterFn = ( - data: FeastFeatureServiceType[], + data: feast.core.IFeatureService[], filterInput: filterInputInterface ) => { let filteredByTags = data; @@ -79,7 +79,7 @@ const filterFn = ( if (filterInput.searchTokens.length) { return filteredByTags.filter((entry) => { return filterInput.searchTokens.find((token) => { - return token.length >= 3 && entry.spec.name.indexOf(token) >= 0; + return token.length >= 3 && entry?.spec?.name?.indexOf(token)! >= 0; }); }); } diff --git a/ui/src/pages/feature-services/useLoadFeatureService.ts b/ui/src/pages/feature-services/useLoadFeatureService.ts index be2242eae0..7d991533a1 100644 --- a/ui/src/pages/feature-services/useLoadFeatureService.ts +++ b/ui/src/pages/feature-services/useLoadFeatureService.ts @@ -13,23 +13,23 @@ const useLoadFeatureService = (featureServiceName: string) => { registryQuery.data === undefined ? undefined : registryQuery.data.objects.featureServices?.find( - (fs) => fs.spec.name === featureServiceName - ); + (fs) => fs?.spec?.name === featureServiceName + ); let entities = data === undefined ? undefined : registryQuery.data?.indirectRelationships - .filter((relationship) => { - return ( - relationship.target.type === FEAST_FCO_TYPES.featureService && - relationship.target.name === data.spec.name && - relationship.source.type === FEAST_FCO_TYPES.entity - ); - }) - .map((relationship) => { - return relationship.source; - }); + .filter((relationship) => { + return ( + relationship.target.type === FEAST_FCO_TYPES.featureService && + relationship.target.name === data?.spec?.name && + relationship.source.type === FEAST_FCO_TYPES.entity + ); + }) + .map((relationship) => { + return relationship.source; + }); // Deduplicate on name of entity if (entities) { let entityToName: { [key: string]: EntityReference } = {}; diff --git a/ui/src/pages/feature-views/FeatureViewInstance.tsx b/ui/src/pages/feature-views/FeatureViewInstance.tsx index 5352507573..dbe4dad6ec 100644 --- a/ui/src/pages/feature-views/FeatureViewInstance.tsx +++ b/ui/src/pages/feature-views/FeatureViewInstance.tsx @@ -3,15 +3,13 @@ import React from "react"; import { useParams } from "react-router-dom"; import { EuiLoadingSpinner } from "@elastic/eui"; -import { FeastFeatureViewType } from "../../parsers/feastFeatureViews"; import RegularFeatureInstance from "./RegularFeatureViewInstance"; import { FEAST_FV_TYPES } from "../../parsers/mergedFVTypes"; -import { FeastODFVType } from "../../parsers/feastODFVS"; -import { FeastSFVType } from "../../parsers/feastSFVS"; + import useLoadFeatureView from "./useLoadFeatureView"; import OnDemandFeatureInstance from "./OnDemandFeatureViewInstance"; import StreamFeatureInstance from "./StreamFeatureViewInstance"; - +import { feast } from "../../protos"; const FeatureViewInstance = () => { const { featureViewName } = useParams(); @@ -38,18 +36,18 @@ const FeatureViewInstance = () => { if (isSuccess && !isEmpty) { if (data.type === FEAST_FV_TYPES.regular) { - const fv: FeastFeatureViewType = data.object; + const fv: feast.core.IFeatureView = data.object; return ; } if (data.type === FEAST_FV_TYPES.ondemand) { - const odfv: FeastODFVType = data.object; + const odfv: feast.core.IOnDemandFeatureView = data.object; return ; } if (data.type === FEAST_FV_TYPES.stream) { - const sfv: FeastSFVType = data.object; + const sfv: feast.core.IStreamFeatureView = data.object; return ; } diff --git a/ui/src/pages/feature-views/FeatureViewListingTable.tsx b/ui/src/pages/feature-views/FeatureViewListingTable.tsx index ceb756db80..e4eccecc97 100644 --- a/ui/src/pages/feature-views/FeatureViewListingTable.tsx +++ b/ui/src/pages/feature-views/FeatureViewListingTable.tsx @@ -58,7 +58,7 @@ const FeatureViewListingTable = ({ let tag = n/a; if (item.type === "regular") { - const value = item.object.spec.tags + const value = item?.object?.spec!.tags ? item.object.spec.tags[key] : undefined; diff --git a/ui/src/pages/feature-views/FeatureViewSummaryStatisticsTab.tsx b/ui/src/pages/feature-views/FeatureViewSummaryStatisticsTab.tsx deleted file mode 100644 index 7371d4a73b..0000000000 --- a/ui/src/pages/feature-views/FeatureViewSummaryStatisticsTab.tsx +++ /dev/null @@ -1,84 +0,0 @@ -import React from "react"; - -import { EuiEmptyPrompt, EuiLoadingContent, EuiTitle } from "@elastic/eui"; -import { useParams } from "react-router-dom"; -import useLoadFeatureViewSummaryStatistics from "../../queries/useLoadFeatureViewSummaryStatistics"; -import { - NumericColumnSummaryStatisticType, - StringColumnSummaryStatisticType, -} from "../../parsers/featureViewSummaryStatistics"; -import NumericFeaturesTable from "../../components/NumericFeaturesTable"; - -interface ColumnsByGroup { - INT64?: NumericColumnSummaryStatisticType[]; - STRING?: StringColumnSummaryStatisticType[]; -} - -const FeatureViewSummaryStatisticsTab = () => { - let { featureViewName } = useParams(); - - if (!featureViewName) { - throw new Error("Unable to get Feature View Name"); - } - - const { isError, data } = - useLoadFeatureViewSummaryStatistics(featureViewName); - - if (isError) { - return ( - Error loading Statistics} - body={ -

- There was an error loading statistics for{" "} - {featureViewName}. Please check that statistics - have been generated. -

- } - /> - ); - } - - if (data) { - const columnsByGroup = Object.entries( - data.columnsSummaryStatistics - ).reduce((memo, [key, columnStatistics]) => { - if (columnStatistics.valueType === "INT64") { - if (!memo["INT64"]) { - memo[columnStatistics.valueType] = [columnStatistics]; - } else { - memo["INT64"].push(columnStatistics); - } - } - - if (columnStatistics.valueType === "STRING") { - if (!memo["STRING"]) { - memo[columnStatistics.valueType] = [columnStatistics]; - } else { - memo["STRING"].push(columnStatistics); - } - } - - return memo; - }, {}); - - return ( - - {columnsByGroup["INT64"] && ( - <> - -

Numeric Columns

-
- - - )} -
- ); - } - - return ; -}; - -export default FeatureViewSummaryStatisticsTab; diff --git a/ui/src/pages/feature-views/Index.tsx b/ui/src/pages/feature-views/Index.tsx index 3abd42a22b..b874a53236 100644 --- a/ui/src/pages/feature-views/Index.tsx +++ b/ui/src/pages/feature-views/Index.tsx @@ -48,7 +48,7 @@ const shouldIncludeFVsGivenTokenGroups = ( tagTokenGroups: Record ) => { return Object.entries(tagTokenGroups).every(([key, values]) => { - const entryTagValue = entry.object.spec.tags + const entryTagValue = entry?.object?.spec!.tags ? entry.object.spec.tags[key] : undefined; diff --git a/ui/src/pages/feature-views/OnDemandFeatureViewInstance.tsx b/ui/src/pages/feature-views/OnDemandFeatureViewInstance.tsx index 1db2f5194f..166746df22 100644 --- a/ui/src/pages/feature-views/OnDemandFeatureViewInstance.tsx +++ b/ui/src/pages/feature-views/OnDemandFeatureViewInstance.tsx @@ -9,16 +9,16 @@ import { import { FeatureViewIcon32 } from "../../graphics/FeatureViewIcon"; import { useMatchExact } from "../../hooks/useMatchSubpath"; -import { FeastODFVType } from "../../parsers/feastODFVS"; import OnDemandFeatureViewOverviewTab from "./OnDemandFeatureViewOverviewTab"; import { useOnDemandFeatureViewCustomTabs, useOnDemandFeatureViewCustomTabRoutes, } from "../../custom-tabs/TabsRegistryContext"; +import { feast } from "../../protos"; interface OnDemandFeatureInstanceProps { - data: FeastODFVType; + data: feast.core.IOnDemandFeatureView; } const OnDemandFeatureInstance = ({ data }: OnDemandFeatureInstanceProps) => { diff --git a/ui/src/pages/feature-views/OnDemandFeatureViewOverviewTab.tsx b/ui/src/pages/feature-views/OnDemandFeatureViewOverviewTab.tsx index 0922f62102..ee8e41bbf6 100644 --- a/ui/src/pages/feature-views/OnDemandFeatureViewOverviewTab.tsx +++ b/ui/src/pages/feature-views/OnDemandFeatureViewOverviewTab.tsx @@ -10,11 +10,6 @@ import { } from "@elastic/eui"; import React from "react"; import FeaturesListDisplay from "../../components/FeaturesListDisplay"; -import { - FeastODFVType, - RequestDataSourceType, - FeatureViewProjectionType, -} from "../../parsers/feastODFVS"; import { useParams } from "react-router-dom"; import { EntityRelation } from "../../parsers/parseEntityRelationships"; import { FEAST_FCO_TYPES } from "../../parsers/types"; @@ -22,9 +17,10 @@ import useLoadRelationshipData from "../../queries/useLoadRelationshipsData"; import FeatureViewProjectionDisplayPanel from "./components/FeatureViewProjectionDisplayPanel"; import RequestDataDisplayPanel from "./components/RequestDataDisplayPanel"; import ConsumingFeatureServicesList from "./ConsumingFeatureServicesList"; +import { feast } from "../../protos"; interface OnDemandFeatureViewOverviewTabProps { - data: FeastODFVType; + data: feast.core.IOnDemandFeatureView; } const whereFSconsumesThisFv = (fvName: string) => { @@ -39,13 +35,13 @@ const whereFSconsumesThisFv = (fvName: string) => { const OnDemandFeatureViewOverviewTab = ({ data, }: OnDemandFeatureViewOverviewTabProps) => { - const inputs = Object.entries(data.spec.sources); + const inputs = Object.entries(data?.spec?.sources!); const { projectName } = useParams(); const relationshipQuery = useLoadRelationshipData(); const fsNames = relationshipQuery.data ? relationshipQuery.data - .filter(whereFSconsumesThisFv(data.spec.name)) + .filter(whereFSconsumesThisFv(data?.spec?.name!)) .map((fs) => { return fs.target.name; }) @@ -61,7 +57,7 @@ const OnDemandFeatureViewOverviewTab = ({ - {data.spec.userDefinedFunction.body} + {data?.spec?.userDefinedFunction?.bodyText}
@@ -70,13 +66,13 @@ const OnDemandFeatureViewOverviewTab = ({ -

Features ({data.spec.features.length})

+

Features ({data?.spec?.features!.length})

- {projectName && data.spec.features ? ( + {projectName && data?.spec?.features ? ( @@ -93,21 +89,26 @@ const OnDemandFeatureViewOverviewTab = ({ {inputs.map(([key, inputGroup]) => { - if ((inputGroup as RequestDataSourceType).requestDataSource) { + if ( + (inputGroup as feast.core.IOnDemandSource).requestDataSource + ) { return ( ); } - if (inputGroup as FeatureViewProjectionType) { + if ( + (inputGroup as feast.core.IOnDemandSource) + .featureViewProjection + ) { return ( ); diff --git a/ui/src/pages/feature-views/RegularFeatureViewInstance.tsx b/ui/src/pages/feature-views/RegularFeatureViewInstance.tsx index 7200163614..6d34745d7c 100644 --- a/ui/src/pages/feature-views/RegularFeatureViewInstance.tsx +++ b/ui/src/pages/feature-views/RegularFeatureViewInstance.tsx @@ -9,18 +9,17 @@ import { import { FeatureViewIcon32 } from "../../graphics/FeatureViewIcon"; import { useMatchExact, useMatchSubpath } from "../../hooks/useMatchSubpath"; -import { FeastFeatureViewType } from "../../parsers/feastFeatureViews"; import RegularFeatureViewOverviewTab from "./RegularFeatureViewOverviewTab"; -import FeatureViewSummaryStatisticsTab from "./FeatureViewSummaryStatisticsTab"; import { useRegularFeatureViewCustomTabs, useRegularFeatureViewCustomTabRoutes, } from "../../custom-tabs/TabsRegistryContext"; import FeatureFlagsContext from "../../contexts/FeatureFlagsContext"; +import { feast } from "../../protos"; interface RegularFeatureInstanceProps { - data: FeastFeatureViewType; + data: feast.core.IFeatureView; } const RegularFeatureInstance = ({ data }: RegularFeatureInstanceProps) => { @@ -58,7 +57,7 @@ const RegularFeatureInstance = ({ data }: RegularFeatureInstanceProps) => { { path="/" element={} /> - } - /> {TabRoutes} diff --git a/ui/src/pages/feature-views/RegularFeatureViewOverviewTab.tsx b/ui/src/pages/feature-views/RegularFeatureViewOverviewTab.tsx index 689bc6b902..3bbb906e05 100644 --- a/ui/src/pages/feature-views/RegularFeatureViewOverviewTab.tsx +++ b/ui/src/pages/feature-views/RegularFeatureViewOverviewTab.tsx @@ -15,12 +15,13 @@ import { useNavigate, useParams } from "react-router-dom"; import FeaturesListDisplay from "../../components/FeaturesListDisplay"; import TagsDisplay from "../../components/TagsDisplay"; import { encodeSearchQueryString } from "../../hooks/encodeSearchQueryString"; -import { FeastFeatureViewType } from "../../parsers/feastFeatureViews"; import { EntityRelation } from "../../parsers/parseEntityRelationships"; import { FEAST_FCO_TYPES } from "../../parsers/types"; import useLoadRelationshipData from "../../queries/useLoadRelationshipsData"; import BatchSourcePropertiesView from "../data-sources/BatchSourcePropertiesView"; import ConsumingFeatureServicesList from "./ConsumingFeatureServicesList"; +import { feast } from "../../protos"; +import { toDate } from "../../utils/timestamp"; const whereFSconsumesThisFv = (fvName: string) => { return (r: EntityRelation) => { @@ -32,7 +33,7 @@ const whereFSconsumesThisFv = (fvName: string) => { }; interface RegularFeatureViewOverviewTabProps { - data: FeastFeatureViewType; + data: feast.core.IFeatureView; } const RegularFeatureViewOverviewTab = ({ @@ -49,8 +50,8 @@ const RegularFeatureViewOverviewTab = ({ const fsNames = relationshipQuery.data ? relationshipQuery.data.filter(whereFSconsumesThisFv(fvName)).map((fs) => { - return fs.target.name; - }) + return fs.target.name; + }) : []; const numOfFs = fsNames.length; @@ -66,13 +67,13 @@ const RegularFeatureViewOverviewTab = ({ -

Features ({data.spec.features.length})

+

Features ({data?.spec?.features?.length})

- {projectName && data.spec.features ? ( + {projectName && data?.spec?.features ? ( @@ -87,7 +88,7 @@ const RegularFeatureViewOverviewTab = ({

Entities

- {data.spec.entities ? ( + {data?.spec?.entities ? ( {data.spec.entities.map((entity) => { return ( @@ -128,7 +129,7 @@ const RegularFeatureViewOverviewTab = ({

Tags

- {data.spec.tags ? ( + {data?.spec?.tags ? ( { @@ -137,8 +138,8 @@ const RegularFeatureViewOverviewTab = ({ encodeSearchQueryString(`${key}:${value}`) ); }} - owner={data.spec.owner} - description={data.spec.description} + owner={data?.spec?.owner!} + description={data?.spec?.description!} /> ) : ( No Tags specified on this feature view. @@ -154,7 +155,7 @@ const RegularFeatureViewOverviewTab = ({

Batch Source

- +
@@ -164,11 +165,11 @@ const RegularFeatureViewOverviewTab = ({

Materialization Intervals

- {data.meta.materializationIntervals?.map((interval, i) => { + {data?.meta?.materializationIntervals?.map((interval, i) => { return (

- {interval.startTime.toLocaleDateString("en-CA")} to{" "} - {interval.endTime.toLocaleDateString("en-CA")} + {toDate(interval.startTime!).toLocaleDateString("en-CA")} to{" "} + {toDate(interval.endTime!).toLocaleDateString("en-CA")}

); })} diff --git a/ui/src/pages/feature-views/StreamFeatureViewInstance.tsx b/ui/src/pages/feature-views/StreamFeatureViewInstance.tsx index ba4c008727..52bc06bc5e 100644 --- a/ui/src/pages/feature-views/StreamFeatureViewInstance.tsx +++ b/ui/src/pages/feature-views/StreamFeatureViewInstance.tsx @@ -9,16 +9,16 @@ import { import { FeatureViewIcon32 } from "../../graphics/FeatureViewIcon"; import { useMatchExact } from "../../hooks/useMatchSubpath"; -import { FeastSFVType } from "../../parsers/feastSFVS"; import StreamFeatureViewOverviewTab from "./StreamFeatureViewOverviewTab"; import { useStreamFeatureViewCustomTabs, useStreamFeatureViewCustomTabRoutes, } from "../../custom-tabs/TabsRegistryContext"; +import { feast } from "../../protos"; interface StreamFeatureInstanceProps { - data: FeastSFVType; + data: feast.core.IStreamFeatureView; } const StreamFeatureInstance = ({ data }: StreamFeatureInstanceProps) => { diff --git a/ui/src/pages/feature-views/StreamFeatureViewOverviewTab.tsx b/ui/src/pages/feature-views/StreamFeatureViewOverviewTab.tsx index 56efc42845..b6cf12d372 100644 --- a/ui/src/pages/feature-views/StreamFeatureViewOverviewTab.tsx +++ b/ui/src/pages/feature-views/StreamFeatureViewOverviewTab.tsx @@ -10,18 +10,16 @@ import { } from "@elastic/eui"; import React from "react"; import FeaturesListDisplay from "../../components/FeaturesListDisplay"; -import { - FeastSFVType, -} from "../../parsers/feastSFVS"; import { useParams } from "react-router-dom"; import { EntityRelation } from "../../parsers/parseEntityRelationships"; import { FEAST_FCO_TYPES } from "../../parsers/types"; import useLoadRelationshipData from "../../queries/useLoadRelationshipsData"; import ConsumingFeatureServicesList from "./ConsumingFeatureServicesList"; import EuiCustomLink from "../../components/EuiCustomLink"; +import { feast } from "../../protos"; interface StreamFeatureViewOverviewTabProps { - data: FeastSFVType; + data: feast.core.IStreamFeatureView; } const whereFSconsumesThisFv = (fvName: string) => { @@ -36,13 +34,13 @@ const whereFSconsumesThisFv = (fvName: string) => { const StreamFeatureViewOverviewTab = ({ data, }: StreamFeatureViewOverviewTabProps) => { - const inputs = Object.entries([data.spec.streamSource]); + const inputs = Object.entries([data.spec?.streamSource]); const { projectName } = useParams(); const relationshipQuery = useLoadRelationshipData(); const fsNames = relationshipQuery.data ? relationshipQuery.data - .filter(whereFSconsumesThisFv(data.spec.name)) + .filter(whereFSconsumesThisFv(data.spec?.name!)) .map((fs) => { return fs.target.name; }) @@ -58,7 +56,7 @@ const StreamFeatureViewOverviewTab = ({ - {data.spec.userDefinedFunction.body} + {data.spec?.userDefinedFunction?.body}
@@ -67,13 +65,13 @@ const StreamFeatureViewOverviewTab = ({ -

Features ({data.spec.features.length})

+

Features ({data.spec?.features?.length})

- {projectName && data.spec.features ? ( + {projectName && data.spec?.features ? ( @@ -98,10 +96,10 @@ const StreamFeatureViewOverviewTab = ({ - {inputGroup.name} + {inputGroup?.name} diff --git a/ui/src/pages/feature-views/components/FeatureViewProjectionDisplayPanel.tsx b/ui/src/pages/feature-views/components/FeatureViewProjectionDisplayPanel.tsx index 7b110f326d..156f6db1ec 100644 --- a/ui/src/pages/feature-views/components/FeatureViewProjectionDisplayPanel.tsx +++ b/ui/src/pages/feature-views/components/FeatureViewProjectionDisplayPanel.tsx @@ -1,25 +1,26 @@ import React from "react"; import { EuiBasicTable, EuiPanel, EuiText, EuiTitle } from "@elastic/eui"; -import { FeatureViewProjectionType } from "../../../parsers/feastODFVS"; import { useParams } from "react-router-dom"; import EuiCustomLink from "../../../components/EuiCustomLink"; +import { feast } from "../../../protos"; -interface RequestDataDisplayPanelProps extends FeatureViewProjectionType {} +interface RequestDataDisplayPanelProps extends feast.core.IFeatureViewProjection { } -const FeatureViewProjectionDisplayPanel = ({ - featureViewProjection, -}: RequestDataDisplayPanelProps) => { +const FeatureViewProjectionDisplayPanel = (featureViewProjection: RequestDataDisplayPanelProps) => { const { projectName } = useParams(); const columns = [ { name: "Column Name", - field: "name", + field: "name" }, { name: "Type", field: "valueType", + render: (valueType: any) => { + return feast.types.ValueType.Enum[valueType]; + }, }, ]; @@ -33,12 +34,12 @@ const FeatureViewProjectionDisplayPanel = ({ href={`/p/${projectName}/feature-view/${featureViewProjection.featureViewName}`} to={`/p/${projectName}/feature-view/${featureViewProjection.featureViewName}`} > - {featureViewProjection.featureViewName} + {featureViewProjection?.featureViewName}
); diff --git a/ui/src/pages/feature-views/components/RequestDataDisplayPanel.tsx b/ui/src/pages/feature-views/components/RequestDataDisplayPanel.tsx index a6e546d9d8..e8e6854389 100644 --- a/ui/src/pages/feature-views/components/RequestDataDisplayPanel.tsx +++ b/ui/src/pages/feature-views/components/RequestDataDisplayPanel.tsx @@ -1,17 +1,17 @@ import React from "react"; import { EuiBasicTable, EuiPanel, EuiText, EuiTitle } from "@elastic/eui"; import { useParams } from "react-router-dom"; -import { RequestDataSourceType } from "../../../parsers/feastODFVS"; import EuiCustomLink from "../../../components/EuiCustomLink"; +import { feast } from "../../../protos"; -interface RequestDataDisplayPanelProps extends RequestDataSourceType {} +interface RequestDataDisplayPanelProps extends feast.core.IOnDemandSource { } const RequestDataDisplayPanel = ({ requestDataSource, }: RequestDataDisplayPanelProps) => { const { projectName } = useParams(); - const items = Object.entries(requestDataSource.requestDataOptions.schema).map( + const items = Object.entries(requestDataSource?.requestDataOptions?.schema!).map( ([key, type]) => { return { key, @@ -38,10 +38,10 @@ const RequestDataDisplayPanel = ({ - {requestDataSource.name} + {requestDataSource?.name} diff --git a/ui/src/pages/feature-views/useLoadFeatureView.ts b/ui/src/pages/feature-views/useLoadFeatureView.ts index 7685171b72..14970360f2 100644 --- a/ui/src/pages/feature-views/useLoadFeatureView.ts +++ b/ui/src/pages/feature-views/useLoadFeatureView.ts @@ -25,8 +25,8 @@ const useLoadRegularFeatureView = (featureViewName: string) => { registryQuery.data === undefined ? undefined : registryQuery.data.objects.featureViews?.find((fv) => { - return fv.spec.name === featureViewName; - }); + return fv?.spec?.name === featureViewName; + }); return { ...registryQuery, @@ -42,8 +42,8 @@ const useLoadOnDemandFeatureView = (featureViewName: string) => { registryQuery.data === undefined ? undefined : registryQuery.data.objects.onDemandFeatureViews?.find((fv) => { - return fv.spec.name === featureViewName; - }); + return fv?.spec?.name === featureViewName; + }); return { ...registryQuery, @@ -59,7 +59,7 @@ const useLoadStreamFeatureView = (featureViewName: string) => { registryQuery.data === undefined ? undefined : registryQuery.data.objects.streamFeatureViews?.find((fv) => { - return fv.spec.name === featureViewName; + return fv.spec?.name === featureViewName; }); return { diff --git a/ui/src/pages/features/FeatureOverviewTab.tsx b/ui/src/pages/features/FeatureOverviewTab.tsx index 0a1c48509c..09da62a87a 100644 --- a/ui/src/pages/features/FeatureOverviewTab.tsx +++ b/ui/src/pages/features/FeatureOverviewTab.tsx @@ -13,6 +13,7 @@ import EuiCustomLink from "../../components/EuiCustomLink"; import React from "react"; import { useParams } from "react-router-dom"; import useLoadFeature from "./useLoadFeature"; +import { feast } from "../../protos"; const FeatureOverviewTab = () => { let { projectName, FeatureViewName, FeatureName } = useParams(); @@ -48,7 +49,7 @@ const FeatureOverviewTab = () => { Value Type - {featureData?.valueType} + {feast.types.ValueType.Enum[featureData?.valueType!]} FeatureView diff --git a/ui/src/pages/features/useLoadFeature.ts b/ui/src/pages/features/useLoadFeature.ts index 5ddaf28204..f1918dd4d5 100644 --- a/ui/src/pages/features/useLoadFeature.ts +++ b/ui/src/pages/features/useLoadFeature.ts @@ -10,15 +10,15 @@ const useLoadFeature = (featureViewName: string, featureName: string) => { registryQuery.data === undefined ? undefined : registryQuery.data.objects.featureViews?.find((fv) => { - return fv.spec.name === featureViewName; - }); + return fv?.spec?.name === featureViewName; + }); - const featureData = + const featureData = data === undefined ? undefined - : data?.spec.features.find((f) => { - return f.name === featureName; - }); + : data?.spec?.features?.find((f) => { + return f.name === featureName; + }); return { ...registryQuery, diff --git a/ui/src/pages/saved-data-sets/DatasetExpectationsTab.tsx b/ui/src/pages/saved-data-sets/DatasetExpectationsTab.tsx index 10ebb87297..dc49355c28 100644 --- a/ui/src/pages/saved-data-sets/DatasetExpectationsTab.tsx +++ b/ui/src/pages/saved-data-sets/DatasetExpectationsTab.tsx @@ -11,7 +11,7 @@ const DatasetExpectationsTab = () => { } const { isSuccess, data } = useLoadDataset(datasetName); - if (!data || !data.spec.profile) { + if (!data || !data.spec?.name) { return ( No data so sad @@ -21,15 +21,9 @@ const DatasetExpectationsTab = () => { let expectationsData; - try { - expectationsData = JSON.parse(data.spec.profile); - } catch (e) { - throw new Error(`Unable to parse Expectations Profile: ${e}`); - } - - return isSuccess && expectationsData ? ( + return isSuccess ? ( -
{JSON.stringify(expectationsData, null, 2)}
+
{JSON.stringify(data.spec, null, 2)}
) : ( diff --git a/ui/src/pages/saved-data-sets/DatasetOverviewTab.tsx b/ui/src/pages/saved-data-sets/DatasetOverviewTab.tsx index a20c83b1e2..5f6ffa2101 100644 --- a/ui/src/pages/saved-data-sets/DatasetOverviewTab.tsx +++ b/ui/src/pages/saved-data-sets/DatasetOverviewTab.tsx @@ -15,6 +15,7 @@ import { useParams } from "react-router-dom"; import DatasetFeaturesTable from "./DatasetFeaturesTable"; import DatasetJoinKeysTable from "./DatasetJoinKeysTable"; import useLoadDataset from "./useLoadDataset"; +import { toDate } from "../../utils/timestamp"; const EntityOverviewTab = () => { let { datasetName } = useParams(); @@ -47,7 +48,7 @@ const EntityOverviewTab = () => { { + features={data.spec?.features!.map((joinedName: string) => { const [featureViewName, featureName] = joinedName.split(":"); @@ -55,7 +56,7 @@ const EntityOverviewTab = () => { featureViewName, featureName, }; - })} + })!} /> @@ -65,9 +66,9 @@ const EntityOverviewTab = () => { { + joinKeys={data?.spec?.joinKeys!.map((joinKey) => { return { name: joinKey }; - })} + })!} />
@@ -82,7 +83,7 @@ const EntityOverviewTab = () => { Source Feature Service - {data.spec.featureService} + {data?.spec?.featureServiceName!} @@ -91,7 +92,7 @@ const EntityOverviewTab = () => { Created - {data.meta.createdTimestamp.toLocaleDateString("en-CA")} + {toDate(data?.meta?.createdTimestamp!).toLocaleDateString("en-CA")} diff --git a/ui/src/pages/saved-data-sets/DatasetsListingTable.tsx b/ui/src/pages/saved-data-sets/DatasetsListingTable.tsx index 97d11b0b24..a1a9708417 100644 --- a/ui/src/pages/saved-data-sets/DatasetsListingTable.tsx +++ b/ui/src/pages/saved-data-sets/DatasetsListingTable.tsx @@ -2,10 +2,11 @@ import React from "react"; import { EuiBasicTable } from "@elastic/eui"; import EuiCustomLink from "../../components/EuiCustomLink"; import { useParams } from "react-router-dom"; -import { FeastSavedDatasetType } from "../../parsers/feastSavedDataset"; +import { feast } from "../../protos"; +import { toDate } from "../../utils/timestamp"; interface DatasetsListingTableProps { - datasets: FeastSavedDatasetType[]; + datasets: feast.core.ISavedDataset[]; } const DatasetsListingTable = ({ datasets }: DatasetsListingTableProps) => { @@ -33,15 +34,15 @@ const DatasetsListingTable = ({ datasets }: DatasetsListingTableProps) => { }, { name: "Created", - render: (item: FeastSavedDatasetType) => { - return item.meta.createdTimestamp.toLocaleDateString("en-CA"); + render: (item: feast.core.ISavedDataset) => { + return toDate(item?.meta?.createdTimestamp!).toLocaleString("en-CA")!; }, }, ]; - const getRowProps = (item: FeastSavedDatasetType) => { + const getRowProps = (item: feast.core.ISavedDataset) => { return { - "data-test-subj": `row-${item.spec.name}`, + "data-test-subj": `row-${item.spec?.name}`, }; }; diff --git a/ui/src/pages/saved-data-sets/useLoadDataset.ts b/ui/src/pages/saved-data-sets/useLoadDataset.ts index a3dbd3225d..17a77d9799 100644 --- a/ui/src/pages/saved-data-sets/useLoadDataset.ts +++ b/ui/src/pages/saved-data-sets/useLoadDataset.ts @@ -10,8 +10,8 @@ const useLoadEntity = (entityName: string) => { registryQuery.data === undefined ? undefined : registryQuery.data.objects.savedDatasets?.find( - (fv) => fv.spec.name === entityName - ); + (fv) => fv.spec?.name === entityName + ); return { ...registryQuery, diff --git a/ui/src/parsers/feastDatasources.ts b/ui/src/parsers/feastDatasources.ts deleted file mode 100644 index 3e1dca72d1..0000000000 --- a/ui/src/parsers/feastDatasources.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { z } from "zod"; -import { FeastFeatureColumnSchema } from "./feastFeatureViews"; - -const FeastDatasourceSchema = z.object({ - type: z.string(), - eventTimestampColumn: z.string().optional(), - createdTimestampColumn: z.string().optional(), - fileOptions: z.object({ - uri: z.string().optional(), - }).optional(), - name: z.string(), - description: z.string().optional(), - owner: z.string().optional(), - meta: z.object({ - latestEventTimestamp: z.string().transform((val) => new Date(val)), - earliestEventTimestamp: z.string().transform((val) => new Date(val)), - }).optional(), - requestDataOptions: z.object({ - schema: z.array(FeastFeatureColumnSchema), - }).optional(), - bigqueryOptions: z.object({ - tableRef: z.string().optional(), - dbtModelSerialized: z.string().optional() - }).optional(), -}); - -type FeastDatasourceType = z.infer; - -export { FeastDatasourceSchema }; -export type { FeastDatasourceType }; diff --git a/ui/src/parsers/feastEntities.ts b/ui/src/parsers/feastEntities.ts deleted file mode 100644 index 09057c6fe9..0000000000 --- a/ui/src/parsers/feastEntities.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { z } from "zod"; -import { FEAST_FEATURE_VALUE_TYPES } from "./types"; - -const FeastEntitySchema = z.object({ - spec: z.object({ - name: z.string(), - valueType: z.nativeEnum(FEAST_FEATURE_VALUE_TYPES).optional(), - joinKey: z.string(), - description: z.string().optional(), - labels: z.record(z.string()).optional(), - }), - meta: z.object({ - createdTimestamp: z.string().transform((val) => new Date(val)).optional(), - lastUpdatedTimestamp: z.string().transform((val) => new Date(val)).optional(), - }), -}); - -type FeastEntityType = z.infer; - -export { FeastEntitySchema }; -export type { FeastEntityType }; diff --git a/ui/src/parsers/feastFeatureServices.ts b/ui/src/parsers/feastFeatureServices.ts deleted file mode 100644 index 6812b7e02c..0000000000 --- a/ui/src/parsers/feastFeatureServices.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { z } from "zod"; -import { FEAST_FEATURE_VALUE_TYPES } from "./types"; - -const FeatureColumnInService = z.object({ - name: z.string(), - valueType: z.nativeEnum(FEAST_FEATURE_VALUE_TYPES), -}); - -const FeatureInServiceSchema = z.object({ - featureViewName: z.string(), - featureColumns: z.array(FeatureColumnInService), -}); - -const FeastFeatureServiceSchema = z.object({ - spec: z.object({ - name: z.string(), - features: z.array(FeatureInServiceSchema), - tags: z.record(z.string()).optional(), - description: z.string().optional(), - }), - meta: z.object({ - createdTimestamp: z.string().transform((val) => new Date(val)).optional(), - lastUpdatedTimestamp: z.string().transform((val) => new Date(val)).optional(), - }), -}); - -type FeastFeatureServiceType = z.infer; -type FeastFeatureInServiceType = z.infer; - -export { FeastFeatureServiceSchema }; -export type { FeastFeatureServiceType, FeastFeatureInServiceType }; diff --git a/ui/src/parsers/feastFeatureViews.ts b/ui/src/parsers/feastFeatureViews.ts deleted file mode 100644 index cbf15d280e..0000000000 --- a/ui/src/parsers/feastFeatureViews.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { z } from "zod"; -import { FEAST_FEATURE_VALUE_TYPES } from "./types"; - -const FeastFeatureColumnSchema = z.object({ - name: z.string(), - valueType: z.nativeEnum(FEAST_FEATURE_VALUE_TYPES), - tags: z.record(z.string()).optional(), -}); - -const FeastBatchSourceSchema = z.object({ - type: z.string(), - eventTimestampColumn: z.string().optional(), - createdTimestampColumn: z.string().optional(), - fileOptions: z.object({ - uri: z.string().optional(), - }).optional(), - name: z.string().optional(), - description: z.string().optional(), - owner: z.string().optional(), - meta: z.object({ - earliestEventTimestamp: z.string().transform((val) => new Date(val)), - latestEventTimestamp: z.string().transform((val) => new Date(val)), - }).optional(), - requestDataOptions: z.object({ - schema: z.record(z.nativeEnum(FEAST_FEATURE_VALUE_TYPES)), - }).optional(), - bigqueryOptions: z.object({ - tableRef: z.string().optional(), - dbtModelSerialized: z.string().optional() - }).optional(), - dataSourceClassType: z.string(), -}); - -const FeastFeatureViewSchema = z.object({ - spec: z.object({ - description: z.string().optional(), - name: z.string(), - entities: z.array(z.string()), - features: z.array(FeastFeatureColumnSchema), - ttl: z.string().transform((val) => parseInt(val)), - batchSource: FeastBatchSourceSchema, - online: z.boolean().optional(), - owner: z.string().optional(), - tags: z.record(z.string()).optional(), - }), - meta: z.object({ - createdTimestamp: z.string().transform((val) => new Date(val)).optional(), - lastUpdatedTimestamp: z.string().transform((val) => new Date(val)).optional(), - materializationIntervals: z - .array( - z.object({ - startTime: z.string().transform((val) => new Date(val)), - endTime: z.string().transform((val) => new Date(val)), - }) - ) - .optional(), - }), -}); - -type FeastFeatureViewType = z.infer; -type FeastFeatureColumnType = z.infer; - -export { FeastFeatureViewSchema, FeastFeatureColumnSchema }; -export type { FeastFeatureViewType, FeastFeatureColumnType }; diff --git a/ui/src/parsers/feastFeatures.ts b/ui/src/parsers/feastFeatures.ts deleted file mode 100644 index 129120c168..0000000000 --- a/ui/src/parsers/feastFeatures.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { z } from "zod"; -import { FEAST_FEATURE_VALUE_TYPES } from "./types"; -import { jsonSchema } from "./jsonType" - -const FeastFeatureSchema = z.object({ - name: z.string(), - valueType: z.nativeEnum(FEAST_FEATURE_VALUE_TYPES), - metadata: jsonSchema.optional(), -}); - -export { FeastFeatureSchema }; diff --git a/ui/src/parsers/feastODFVS.ts b/ui/src/parsers/feastODFVS.ts deleted file mode 100644 index 4d09cc72df..0000000000 --- a/ui/src/parsers/feastODFVS.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { z } from "zod"; -import { FeastFeatureColumnSchema } from "./feastFeatureViews"; - -const FeatureViewProjectionSchema = z.object({ - featureViewProjection: z.object({ - featureViewName: z.string(), - featureColumns: z.array(FeastFeatureColumnSchema), - }), -}); - -const RequestDataSourceSchema = z.object({ - requestDataSource: z.object({ - type: z.string(), - name: z.string(), - requestDataOptions: z.object({ - schema: z.array(FeastFeatureColumnSchema), - }), - }), -}); - -const ODFVInputsSchema = z.union([ - FeatureViewProjectionSchema, - RequestDataSourceSchema, -]); - -const FeastODFVSchema = z.object({ - spec: z.object({ - name: z.string(), - features: z.array(FeastFeatureColumnSchema), - sources: z.record(ODFVInputsSchema), - userDefinedFunction: z.object({ - name: z.string(), - body: z.string(), - }), - }), - meta: z.object({ - createdTimestamp: z.string().transform((val) => new Date(val)), - lastUpdatedTimestamp: z.string().transform((val) => new Date(val)), - }), -}); - -type FeastODFVType = z.infer; -type RequestDataSourceType = z.infer; -type FeatureViewProjectionType = z.infer; - -export { FeastODFVSchema }; -export type { FeastODFVType, RequestDataSourceType, FeatureViewProjectionType }; diff --git a/ui/src/parsers/feastRegistry.ts b/ui/src/parsers/feastRegistry.ts deleted file mode 100644 index f84187046a..0000000000 --- a/ui/src/parsers/feastRegistry.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { z } from "zod"; -import { FeastDatasourceSchema } from "./feastDatasources"; -import { FeastEntitySchema } from "./feastEntities"; -import { FeastFeatureServiceSchema } from "./feastFeatureServices"; -import { FeastFeatureViewSchema } from "./feastFeatureViews"; -import { FeastSavedDatasetSchema } from "./feastSavedDataset"; -import { FeastODFVSchema } from "./feastODFVS"; -import { FeastSFVSchema } from "./feastSFVS"; - -const FeastRegistrySchema = z.object({ - project: z.string(), - dataSources: z.array(FeastDatasourceSchema).optional(), - entities: z.array(FeastEntitySchema).optional(), - featureViews: z.array(FeastFeatureViewSchema).optional(), - onDemandFeatureViews: z.array(FeastODFVSchema).optional(), - streamFeatureViews: z.array(FeastSFVSchema).optional(), - featureServices: z.array(FeastFeatureServiceSchema).optional(), - savedDatasets: z.array(FeastSavedDatasetSchema).optional(), -}); - -type FeastRegistryType = z.infer; - -export { FeastRegistrySchema }; -export type { FeastRegistryType }; diff --git a/ui/src/parsers/feastSFVS.ts b/ui/src/parsers/feastSFVS.ts deleted file mode 100644 index f65a087222..0000000000 --- a/ui/src/parsers/feastSFVS.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { z } from "zod"; -import { FeastFeatureColumnSchema } from "./feastFeatureViews"; -import {FeastDatasourceSchema} from "./feastDatasources"; - -const FeatureViewProjectionSchema = z.object({ - featureViewProjection: z.object({ - featureViewName: z.string(), - featureColumns: z.array(FeastFeatureColumnSchema), - }), -}); - -const StreamSourceSchema = z.object({ - type: z.string(), - name: z.string(), - owner: z.string().optional(), - description: z.string().optional(), -}); - -const FeastSFVSchema = z.object({ - spec: z.object({ - name: z.string(), - features: z.array(FeastFeatureColumnSchema), - batchSource: FeastDatasourceSchema, - streamSource: StreamSourceSchema, - userDefinedFunction: z.object({ - name: z.string(), - body: z.string(), - }), - }), - meta: z.object({ - createdTimestamp: z.string().transform((val) => new Date(val)).optional(), - lastUpdatedTimestamp: z.string().transform((val) => new Date(val)).optional(), - }), -}); - -type FeastSFVType = z.infer; -type StreamSourceType = z.infer; -type FeatureViewProjectionType = z.infer; - -export { FeastSFVSchema }; -export type { FeastSFVType, StreamSourceType, FeatureViewProjectionType}; diff --git a/ui/src/parsers/feastSavedDataset.ts b/ui/src/parsers/feastSavedDataset.ts deleted file mode 100644 index ce1d39b4e7..0000000000 --- a/ui/src/parsers/feastSavedDataset.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { z } from "zod"; - -const FeastSavedDatasetSchema = z.object({ - spec: z.object({ - name: z.string(), - features: z.array(z.string()), - joinKeys: z.array(z.string()), - storage: z.object({ - fileStorage: z.object({ - fileFormat: z.object({ - parquetFormat: z.object({}).optional(), - }).optional(), - fileUrl: z.string(), - }).optional(), - }).optional(), - featureService: z - .object({ - spec: z.object({ - name: z.string(), - }), - }) - .transform((obj) => { - return obj.spec.name; - }).optional(), - profile: z.string().optional(), - }), - meta: z.object({ - createdTimestamp: z.string().transform((val) => new Date(val)), - minEventTimestamp: z.string().transform((val) => new Date(val)), - maxEventTimestamp: z.string().transform((val) => new Date(val)), - }), -}); - -type FeastSavedDatasetType = z.infer; - -export { FeastSavedDatasetSchema }; -export type { FeastSavedDatasetType }; diff --git a/ui/src/parsers/featureViewSummaryStatistics.ts b/ui/src/parsers/featureViewSummaryStatistics.ts deleted file mode 100644 index f8eca669d3..0000000000 --- a/ui/src/parsers/featureViewSummaryStatistics.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { z } from "zod"; - -const histogramSchema = z.array( - z.object({ - x0: z.number(), - x1: z.number(), - count: z.number(), - }) -); - -const numericColumnSummaryStaticsSchema = z.object({ - name: z.string(), - valueType: z.literal("INT64"), - sampleValues: z.array(z.number()), - histogram: histogramSchema.optional(), - proportionOfZeros: z.number().optional(), - proportionMissing: z.number().optional(), - min: z.number().optional(), - max: z.number().optional(), -}); - -const stringColumnSummaryStaticsSchema = z.object({ - name: z.string(), - valueType: z.literal("STRING"), - sampleValues: z.array(z.string()), -}); - -const columnsSummaryStatisticsSchema = z.union([ - numericColumnSummaryStaticsSchema, - stringColumnSummaryStaticsSchema, -]); - -const featureViewSummaryStatisticsSchema = z.object({ - columnsSummaryStatistics: z.record(columnsSummaryStatisticsSchema), -}); - -type FeatureViewSummaryStatisticsType = z.infer< - typeof featureViewSummaryStatisticsSchema ->; - -type NumericColumnSummaryStatisticType = z.infer< - typeof numericColumnSummaryStaticsSchema ->; -type StringColumnSummaryStatisticType = z.infer< - typeof stringColumnSummaryStaticsSchema ->; - -type HistogramDataType = z.infer; - -export { featureViewSummaryStatisticsSchema }; -export type { - FeatureViewSummaryStatisticsType, - HistogramDataType, - NumericColumnSummaryStatisticType, - StringColumnSummaryStatisticType, -}; diff --git a/ui/src/parsers/mergedFVTypes.ts b/ui/src/parsers/mergedFVTypes.ts index edf1adee9e..7e23e09520 100644 --- a/ui/src/parsers/mergedFVTypes.ts +++ b/ui/src/parsers/mergedFVTypes.ts @@ -1,10 +1,4 @@ -import { - FeastFeatureColumnType, - FeastFeatureViewType, -} from "./feastFeatureViews"; -import { FeastODFVType } from "./feastODFVS"; -import { FeastSFVType } from "./feastSFVS"; -import { FeastRegistryType } from "./feastRegistry"; +import { feast } from "../protos"; enum FEAST_FV_TYPES { regular = "regular", @@ -15,64 +9,64 @@ enum FEAST_FV_TYPES { interface regularFVInterface { name: string; type: FEAST_FV_TYPES.regular; - features: FeastFeatureColumnType[]; - object: FeastFeatureViewType; + features: feast.core.IFeatureSpecV2[]; + object: feast.core.IFeatureView; } interface ODFVInterface { name: string; type: FEAST_FV_TYPES.ondemand; - features: FeastFeatureColumnType[]; - object: FeastODFVType; + features: feast.core.IOnDemandFeatureViewSpec[]; + object: feast.core.IOnDemandFeatureView; } interface SFVInterface { name: string; type: FEAST_FV_TYPES.stream; - features: FeastFeatureColumnType[]; - object: FeastSFVType; + features: feast.core.IFeatureSpecV2[]; + object: feast.core.IStreamFeatureView; } type genericFVType = regularFVInterface | ODFVInterface | SFVInterface; -const mergedFVTypes = (objects: FeastRegistryType) => { +const mergedFVTypes = (objects: feast.core.Registry) => { const mergedFVMap: Record = {}; const mergedFVList: genericFVType[] = []; objects.featureViews?.forEach((fv) => { const obj: genericFVType = { - name: fv.spec.name, + name: fv.spec?.name!, type: FEAST_FV_TYPES.regular, - features: fv.spec.features, + features: fv.spec?.features!, object: fv, }; - mergedFVMap[fv.spec.name] = obj; + mergedFVMap[fv.spec?.name!] = obj; mergedFVList.push(obj); }); objects.onDemandFeatureViews?.forEach((odfv) => { const obj: genericFVType = { - name: odfv.spec.name, + name: odfv.spec?.name!, type: FEAST_FV_TYPES.ondemand, - features: odfv.spec.features, + features: odfv.spec?.features!, object: odfv, }; - mergedFVMap[odfv.spec.name] = obj; + mergedFVMap[odfv.spec?.name!] = obj; mergedFVList.push(obj); }); objects.streamFeatureViews?.forEach((sfv) => { const obj: genericFVType = { - name: sfv.spec.name, + name: sfv.spec?.name!, type: FEAST_FV_TYPES.stream, - features: sfv.spec.features, + features: sfv.spec?.features!, object: sfv, }; - mergedFVMap[sfv.spec.name] = obj; + mergedFVMap[sfv.spec?.name!] = obj; mergedFVList.push(obj); }); diff --git a/ui/src/parsers/parseEntityRelationships.ts b/ui/src/parsers/parseEntityRelationships.ts index 8424bb7a44..7a791fd0a1 100644 --- a/ui/src/parsers/parseEntityRelationships.ts +++ b/ui/src/parsers/parseEntityRelationships.ts @@ -1,5 +1,5 @@ -import { FeastRegistryType } from "./feastRegistry"; import { FEAST_FCO_TYPES } from "./types"; +import { feast } from "../protos"; interface EntityReference { type: FEAST_FCO_TYPES; @@ -11,26 +11,26 @@ interface EntityRelation { target: EntityReference; } -const parseEntityRelationships = (objects: FeastRegistryType) => { +const parseEntityRelationships = (objects: feast.core.Registry) => { const links: EntityRelation[] = []; objects.featureServices?.forEach((fs) => { - fs.spec.features.forEach((feature) => { + fs.spec?.features!.forEach((feature) => { links.push({ source: { type: FEAST_FCO_TYPES["featureView"], - name: feature.featureViewName, + name: feature?.featureViewName!, }, target: { type: FEAST_FCO_TYPES["featureService"], - name: fs.spec.name, + name: fs.spec?.name!, }, }); }); }); objects.featureViews?.forEach((fv) => { - fv.spec.entities.forEach((ent) => { + fv.spec?.entities?.forEach((ent) => { links.push({ source: { type: FEAST_FCO_TYPES["entity"], @@ -38,11 +38,11 @@ const parseEntityRelationships = (objects: FeastRegistryType) => { }, target: { type: FEAST_FCO_TYPES["featureView"], - name: fv.spec.name, + name: fv.spec?.name!, }, }); }); - if (fv.spec.batchSource) { + if (fv.spec?.batchSource) { links.push({ source: { type: FEAST_FCO_TYPES["dataSource"], @@ -50,54 +50,54 @@ const parseEntityRelationships = (objects: FeastRegistryType) => { }, target: { type: FEAST_FCO_TYPES["featureView"], - name: fv.spec.name, + name: fv.spec?.name!, } }) } }); objects.onDemandFeatureViews?.forEach((fv) => { - Object.values(fv.spec.sources).forEach((input: { [key: string]: any }) => { - if (input.requestDataSource) { - links.push({ - source: { - type: FEAST_FCO_TYPES["dataSource"], - name: input.requestDataSource.name, - }, - target: { - type: FEAST_FCO_TYPES["featureView"], - name: fv.spec.name, - }, - }); - } else if (input.featureViewProjection?.featureViewName) { - const source_fv = objects.featureViews?.find(el => el.spec.name === input.featureViewProjection.featureViewName); - if (!source_fv) { - return; - } - links.push({ - source: { - type: FEAST_FCO_TYPES["dataSource"], - name: source_fv?.spec.batchSource.name || '', - }, - target: { - type: FEAST_FCO_TYPES["featureView"], - name: fv.spec.name, - }, - }); - } - }); - }); + Object.values(fv.spec?.sources!).forEach((input: { [key: string]: any }) => { + if (input.requestDataSource) { + links.push({ + source: { + type: FEAST_FCO_TYPES["dataSource"], + name: input.requestDataSource.name, + }, + target: { + type: FEAST_FCO_TYPES["featureView"], + name: fv.spec?.name!, + }, + }); + } else if (input.featureViewProjection?.featureViewName) { + const source_fv = objects.featureViews?.find(el => el.spec?.name === input.featureViewProjection.featureViewName); + if (!source_fv) { + return; + } + links.push({ + source: { + type: FEAST_FCO_TYPES["dataSource"], + name: source_fv.spec?.batchSource?.name || '', + }, + target: { + type: FEAST_FCO_TYPES["featureView"], + name: fv.spec?.name!, + }, + }); + } + }); + }); objects.streamFeatureViews?.forEach((fv) => { // stream source links.push({ source: { type: FEAST_FCO_TYPES["dataSource"], - name: fv.spec.streamSource.name, + name: fv.spec?.streamSource?.name!, }, target: { type: FEAST_FCO_TYPES["featureView"], - name: fv.spec.name, + name: fv.spec?.name!, }, }); @@ -105,11 +105,11 @@ const parseEntityRelationships = (objects: FeastRegistryType) => { links.push({ source: { type: FEAST_FCO_TYPES["dataSource"], - name: fv.spec.batchSource.name, + name: fv.spec?.batchSource?.name!, }, target: { type: FEAST_FCO_TYPES["featureView"], - name: fv.spec.name, + name: fv.spec?.name!, }, }); }); diff --git a/ui/src/parsers/parseIndirectRelationships.ts b/ui/src/parsers/parseIndirectRelationships.ts index d7d532ad3e..092176c9b6 100644 --- a/ui/src/parsers/parseIndirectRelationships.ts +++ b/ui/src/parsers/parseIndirectRelationships.ts @@ -1,16 +1,16 @@ -import { FeastRegistryType } from "./feastRegistry"; import { EntityRelation } from "./parseEntityRelationships"; import { FEAST_FCO_TYPES } from "./types"; +import { feast } from "../protos"; const parseIndirectRelationships = ( relationships: EntityRelation[], - objects: FeastRegistryType + objects: feast.core.Registry ) => { const indirectLinks: EntityRelation[] = []; // Only contains Entity -> FS or DS -> FS relationships objects.featureServices?.forEach((featureService) => { - featureService.spec.features.forEach((featureView) => { + featureService.spec?.features?.forEach((featureView) => { relationships .filter( (relationship) => @@ -21,7 +21,7 @@ const parseIndirectRelationships = ( source: relationship.source, target: { type: FEAST_FCO_TYPES["featureService"], - name: featureService.spec.name, + name: featureService.spec?.name!, }, }); }); diff --git a/ui/src/parsers/types.ts b/ui/src/parsers/types.ts index 2f88eea4f0..1e515f23f3 100644 --- a/ui/src/parsers/types.ts +++ b/ui/src/parsers/types.ts @@ -5,25 +5,4 @@ enum FEAST_FCO_TYPES { featureService = "featureService", } -enum FEAST_FEATURE_VALUE_TYPES { - FLOAT = "FLOAT", - INT64 = "INT64", - STRING = "STRING", - BOOL = "BOOL", - BYTES = "BYTES", - INT32 = "INT32", - DOUBLE = "DOUBLE", - UNIX_TIMESTAMP = "UNIX_TIMESTAMP", - INVALID = "INVALID", - BYTES_LIST = "BYTES_LIST", - STRING_LIST = "STRING_LIST", - INT32_LIST = "INT32_LIST", - INT64_LIST = "INT64_LIST", - DOUBLE_LIST = "DOUBLE_LIST", - FLOAT_LIST = "FLOAT_LIST", - BOOL_LIST = "BOOL_LIST", - UNIX_TIMESTAMP_LIST = "UNIX_TIMESTAMP_LIST", - NULL = "NULL" -} - -export { FEAST_FCO_TYPES, FEAST_FEATURE_VALUE_TYPES }; +export { FEAST_FCO_TYPES }; diff --git a/ui/src/queries/useLoadFeatureViewSummaryStatistics.ts b/ui/src/queries/useLoadFeatureViewSummaryStatistics.ts deleted file mode 100644 index fea0bd9d81..0000000000 --- a/ui/src/queries/useLoadFeatureViewSummaryStatistics.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { useQuery } from "react-query"; -import { useParams } from "react-router-dom"; -import { - featureViewSummaryStatisticsSchema, - FeatureViewSummaryStatisticsType, -} from "../parsers/featureViewSummaryStatistics"; - -const useLoadFeatureViewSummaryStatistics = (featureViewName: string) => { - const { projectName } = useParams(); - - const queryKey = `featureViewSummaryStatistics:${featureViewName}`; - const url = `/data/${projectName}/featureView/${featureViewName}.json`; - - return useQuery( - queryKey, - () => { - return fetch(url, { - headers: { - "Content-Type": "application/json", - }, - }) - .then((res) => { - return res.json(); - }) - .then((json) => { - const summary = featureViewSummaryStatisticsSchema.parse(json); - - return summary; - }); - }, - { - staleTime: 15 * 60 * 1000, // Given that we are reading from a registry dump, this seems reasonable for now. - } - ); -}; - -export default useLoadFeatureViewSummaryStatistics; diff --git a/ui/src/queries/useLoadRegistry.ts b/ui/src/queries/useLoadRegistry.ts index ffb0675643..be8ab65a8c 100644 --- a/ui/src/queries/useLoadRegistry.ts +++ b/ui/src/queries/useLoadRegistry.ts @@ -1,18 +1,15 @@ import { useQuery } from "react-query"; -import { - FeastRegistrySchema, - FeastRegistryType, -} from "../parsers/feastRegistry"; import mergedFVTypes, { genericFVType } from "../parsers/mergedFVTypes"; import parseEntityRelationships, { EntityRelation, } from "../parsers/parseEntityRelationships"; import parseIndirectRelationships from "../parsers/parseIndirectRelationships"; +import { feast } from "../protos"; interface FeatureStoreAllData { project: string; description?: string; - objects: FeastRegistryType; + objects: feast.core.Registry; relationships: EntityRelation[]; mergedFVMap: Record; mergedFVList: genericFVType[]; @@ -29,10 +26,12 @@ const useLoadRegistry = (url: string) => { }, }) .then((res) => { - return res.json(); + return res.arrayBuffer(); }) - .then((json) => { - const objects = FeastRegistrySchema.parse(json); + .then((arrayBuffer) => { + + const objects = feast.core.Registry.decode(new Uint8Array(arrayBuffer)); + // const objects = FeastRegistrySchema.parse(json); const { mergedFVMap, mergedFVList } = mergedFVTypes(objects); @@ -53,7 +52,7 @@ const useLoadRegistry = (url: string) => { // }); return { - project: objects.project, + project: objects.projectMetadata[0].project!, objects, mergedFVMap, mergedFVList, diff --git a/ui/src/utils/timestamp.ts b/ui/src/utils/timestamp.ts new file mode 100644 index 0000000000..869d24870f --- /dev/null +++ b/ui/src/utils/timestamp.ts @@ -0,0 +1,13 @@ +import long from 'long'; +import { google } from '../protos'; + +export function toDate(ts: google.protobuf.ITimestamp) { + var seconds: number; + if (ts.seconds instanceof long) { + seconds = ts.seconds.low + } else { + seconds = ts.seconds!; + } + + return new Date(seconds * 1000); +} \ No newline at end of file diff --git a/ui/yarn.lock b/ui/yarn.lock index ad31cbeac5..e056cad617 100644 --- a/ui/yarn.lock +++ b/ui/yarn.lock @@ -334,6 +334,11 @@ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.17.3.tgz#b07702b982990bf6fdc1da5049a23fece4c5c3d0" integrity sha512-7yJPvPV+ESz2IUTPbOL+YkIGyCqOyNIzdguKQuJGnH7bg1WTIifuM21YqokFt/THWh1AkCRn9IgoykTRCBVpzA== +"@babel/parser@^7.9.4": + version "7.19.0" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.19.0.tgz#497fcafb1d5b61376959c1c338745ef0577aa02c" + integrity sha512-74bEXKX2h+8rrfQUfsBfuZZHzsEs6Eql4pqy/T4Nn6Y9wNPggQOqD6z6pn5Bl8ZfysKouFZT/UXEH94ummEeQw== + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.16.7": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.16.7.tgz#4eda6d6c2a0aa79c70fa7b6da67763dfe2141050" @@ -1592,6 +1597,59 @@ schema-utils "^3.0.0" source-map "^0.7.3" +"@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf" + integrity sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ== + +"@protobufjs/base64@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/base64/-/base64-1.1.2.tgz#4c85730e59b9a1f1f349047dbf24296034bb2735" + integrity sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg== + +"@protobufjs/codegen@^2.0.4": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@protobufjs/codegen/-/codegen-2.0.4.tgz#7ef37f0d010fb028ad1ad59722e506d9262815cb" + integrity sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg== + +"@protobufjs/eventemitter@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz#355cbc98bafad5978f9ed095f397621f1d066b70" + integrity sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q== + +"@protobufjs/fetch@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/fetch/-/fetch-1.1.0.tgz#ba99fb598614af65700c1619ff06d454b0d84c45" + integrity sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ== + dependencies: + "@protobufjs/aspromise" "^1.1.1" + "@protobufjs/inquire" "^1.1.0" + +"@protobufjs/float@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@protobufjs/float/-/float-1.0.2.tgz#5e9e1abdcb73fc0a7cb8b291df78c8cbd97b87d1" + integrity sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ== + +"@protobufjs/inquire@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/inquire/-/inquire-1.1.0.tgz#ff200e3e7cf2429e2dcafc1140828e8cc638f089" + integrity sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q== + +"@protobufjs/path@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/path/-/path-1.1.2.tgz#6cc2b20c5c9ad6ad0dccfd21ca7673d8d7fbf68d" + integrity sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA== + +"@protobufjs/pool@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/pool/-/pool-1.1.0.tgz#09fd15f2d6d3abfa9b65bc366506d6ad7846ff54" + integrity sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw== + +"@protobufjs/utf8@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570" + integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw== + "@rollup/plugin-babel@^5.2.0": version "5.3.0" resolved "https://registry.yarnpkg.com/@rollup/plugin-babel/-/plugin-babel-5.3.0.tgz#9cb1c5146ddd6a4968ad96f209c50c62f92f9879" @@ -2316,11 +2374,24 @@ resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4= +"@types/linkify-it@*": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@types/linkify-it/-/linkify-it-3.0.2.tgz#fd2cd2edbaa7eaac7e7f3c1748b52a19143846c9" + integrity sha512-HZQYqbiFVWufzCwexrvh694SOim8z2d+xJl5UNamcvQFejLY/2YUtzXHYi3cHdI7PMlS8ejH2slRAOJQ32aNbA== + "@types/lodash@^4.14.160": version "4.14.178" resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.178.tgz#341f6d2247db528d4a13ddbb374bcdc80406f4f8" integrity sha512-0d5Wd09ItQWH1qFbEyQ7oTQ3GZrMfth5JkbN3EvTKLXcHLRDSXeLnlvlOn0wvxVIwK5o2M8JzP/OWz7T3NRsbw== +"@types/markdown-it@^12.2.3": + version "12.2.3" + resolved "https://registry.yarnpkg.com/@types/markdown-it/-/markdown-it-12.2.3.tgz#0d6f6e5e413f8daaa26522904597be3d6cd93b51" + integrity sha512-GKMHFfv3458yYy+v/N8gjufHO6MSZKCOXpZc5GXIWWy8uldwfmPn98vp81gZ5f9SVw8YYBctgfJ22a2d7AOMeQ== + dependencies: + "@types/linkify-it" "*" + "@types/mdurl" "*" + "@types/mdast@^3.0.0": version "3.0.10" resolved "https://registry.yarnpkg.com/@types/mdast/-/mdast-3.0.10.tgz#4724244a82a4598884cbbe9bcfd73dff927ee8af" @@ -2328,6 +2399,11 @@ dependencies: "@types/unist" "*" +"@types/mdurl@*": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@types/mdurl/-/mdurl-1.0.2.tgz#e2ce9d83a613bacf284c7be7d491945e39e1f8e9" + integrity sha512-eC4U9MlIcu2q0KQmXszyn5Akca/0jrQmwDRgpAMJai7qBWq4amIQhZyNau4VYGtCeALvW1/NtjzJJ567aZxfKA== + "@types/mime@^1": version "1.3.2" resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.2.tgz#93e25bf9ee75fe0fd80b594bc4feb0e862111b5a" @@ -2343,6 +2419,11 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.13.tgz#5ed7ed7c662948335fcad6c412bb42d99ea754e3" integrity sha512-Y86MAxASe25hNzlDbsviXl8jQHb0RDvKt4c40ZJQ1Don0AAL0STLZSs4N+6gLEO55pedy7r2cLwS+ZDxPm/2Bw== +"@types/node@>=13.7.0": + version "18.7.18" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.7.18.tgz#633184f55c322e4fb08612307c274ee6d5ed3154" + integrity sha512-m+6nTEOadJZuTPkKR/SYK3A2d7FZrgElol9UP1Kae90VVU4a6mxnPuLiIW1m4Cq4gZ/nWb9GrdVXJCoCazDAbg== + "@types/node@^16.7.13": version "16.11.21" resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.21.tgz#474d7589a30afcf5291f59bd49cca9ad171ffde4" @@ -2809,7 +2890,7 @@ acorn-import-assertions@^1.7.6: resolved "https://registry.yarnpkg.com/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz#ba2b5939ce62c238db6d93d81c9b111b29b855e9" integrity sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw== -acorn-jsx@^5.3.1: +acorn-jsx@^5.3.1, acorn-jsx@^5.3.2: version "5.3.2" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== @@ -2838,6 +2919,11 @@ acorn@^8.2.4, acorn@^8.4.1, acorn@^8.5.0, acorn@^8.7.0: resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.1.tgz#0197122c843d1bf6d0a5e83220a788f278f63c30" integrity sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A== +acorn@^8.8.0: + version "8.8.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.0.tgz#88c0187620435c7f6015803f5539dae05a9dbea8" + integrity sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w== + address@^1.0.1, address@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/address/-/address-1.1.2.tgz#bf1116c9c758c51b7a933d296b72c221ed9428b6" @@ -3296,7 +3382,7 @@ bl@^4.1.0: inherits "^2.0.4" readable-stream "^3.4.0" -bluebird@^3.5.5: +bluebird@^3.5.5, bluebird@^3.7.2: version "3.7.2" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== @@ -3482,6 +3568,13 @@ case-sensitive-paths-webpack-plugin@^2.4.0: resolved "https://registry.yarnpkg.com/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.4.0.tgz#db64066c6422eed2e08cc14b986ca43796dbc6d4" integrity sha512-roIFONhcxog0JSSWbvVAh3OocukmSgpqOH6YpMkCvav/ySIV3JKg4Dc8vYtQjYi/UxpNE36r/9v+VqTQqgkYmw== +catharsis@^0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/catharsis/-/catharsis-0.9.0.tgz#40382a168be0e6da308c277d3a2b3eb40c7d2121" + integrity sha512-prMTQVpcns/tzFgFVkVp6ak6RykZyWb3gu8ckUpd6YkTlacOd3DXGJjIpD4Q6zJirizvaiAjSSHlOsA+6sNh2A== + dependencies: + lodash "^4.17.15" + ccount@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/ccount/-/ccount-1.1.0.tgz#246687debb6014735131be8abab2d93898f8d043" @@ -4736,6 +4829,11 @@ entities@^2.0.0: resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55" integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A== +entities@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/entities/-/entities-2.1.0.tgz#992d3129cf7df6870b96c57858c249a120f8b8b5" + integrity sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w== + error-ex@^1.3.1: version "1.3.2" resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" @@ -4815,6 +4913,18 @@ escape-string-regexp@^4.0.0: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== +escodegen@^1.13.0: + version "1.14.3" + resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.14.3.tgz#4e7b81fba61581dc97582ed78cab7f0e8d63f503" + integrity sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw== + dependencies: + esprima "^4.0.1" + estraverse "^4.2.0" + esutils "^2.0.2" + optionator "^0.8.1" + optionalDependencies: + source-map "~0.6.1" + escodegen@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-2.0.0.tgz#5e32b12833e8aa8fa35e1bf0befa89380484c7dd" @@ -4980,6 +5090,11 @@ eslint-visitor-keys@^3.0.0, eslint-visitor-keys@^3.1.0, eslint-visitor-keys@^3.2 resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.2.0.tgz#6fbb166a6798ee5991358bc2daa1ba76cc1254a1" integrity sha512-IOzT0X126zn7ALX0dwFiUQEdsfzrm4+ISsQS8nukaJXwEyYKRSnEIIDULYg1mCtGp7UUXgfGl7BIolXREQK+XQ== +eslint-visitor-keys@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826" + integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA== + eslint-webpack-plugin@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/eslint-webpack-plugin/-/eslint-webpack-plugin-3.1.1.tgz#83dad2395e5f572d6f4d919eedaa9cf902890fcb" @@ -5032,6 +5147,15 @@ eslint@^8.3.0: text-table "^0.2.0" v8-compile-cache "^2.0.3" +espree@^9.0.0: + version "9.4.0" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.4.0.tgz#cd4bc3d6e9336c433265fc0aa016fc1aaf182f8a" + integrity sha512-DQmnRpLj7f6TgN/NYb0MTzJXL+vJF9h3pHy4JhCIs3zwcgez8xmGg3sXHcEO97BrmO2OSvCwMdfdlyl+E9KjOw== + dependencies: + acorn "^8.8.0" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^3.3.0" + espree@^9.2.0, espree@^9.3.0: version "9.3.0" resolved "https://registry.yarnpkg.com/espree/-/espree-9.3.0.tgz#c1240d79183b72aaee6ccfa5a90bc9111df085a8" @@ -5060,7 +5184,7 @@ esrecurse@^4.3.0: dependencies: estraverse "^5.2.0" -estraverse@^4.1.1: +estraverse@^4.1.1, estraverse@^4.2.0: version "4.3.0" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== @@ -5536,6 +5660,17 @@ glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: once "^1.3.0" path-is-absolute "^1.0.0" +glob@^8.0.0: + version "8.0.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-8.0.3.tgz#415c6eb2deed9e502c68fa44a272e6da6eeca42e" + integrity sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^5.0.1" + once "^1.3.0" + global-modules@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-2.0.0.tgz#997605ad2345f27f51539bea26574421215c7780" @@ -5595,6 +5730,11 @@ graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4, resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.9.tgz#041b05df45755e587a24942279b9d113146e1c96" integrity sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ== +graceful-fs@^4.1.9: + version "4.2.10" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" + integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== + graphql@^15.5.1: version "15.8.0" resolved "https://registry.yarnpkg.com/graphql/-/graphql-15.8.0.tgz#33410e96b012fa3bdb1091cc99a94769db212b38" @@ -6862,6 +7002,34 @@ js-yaml@^4.1.0: dependencies: argparse "^2.0.1" +js2xmlparser@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/js2xmlparser/-/js2xmlparser-4.0.2.tgz#2a1fdf01e90585ef2ae872a01bc169c6a8d5e60a" + integrity sha512-6n4D8gLlLf1n5mNLQPRfViYzu9RATblzPEtm1SthMX1Pjao0r9YI9nw7ZIfRxQMERS87mcswrg+r/OYrPRX6jA== + dependencies: + xmlcreate "^2.0.4" + +jsdoc@^3.6.3: + version "3.6.11" + resolved "https://registry.yarnpkg.com/jsdoc/-/jsdoc-3.6.11.tgz#8bbb5747e6f579f141a5238cbad4e95e004458ce" + integrity sha512-8UCU0TYeIYD9KeLzEcAu2q8N/mx9O3phAGl32nmHlE0LpaJL71mMkP4d+QE5zWfNt50qheHtOZ0qoxVrsX5TUg== + dependencies: + "@babel/parser" "^7.9.4" + "@types/markdown-it" "^12.2.3" + bluebird "^3.7.2" + catharsis "^0.9.0" + escape-string-regexp "^2.0.0" + js2xmlparser "^4.0.2" + klaw "^3.0.0" + markdown-it "^12.3.2" + markdown-it-anchor "^8.4.1" + marked "^4.0.10" + mkdirp "^1.0.4" + requizzle "^0.2.3" + strip-json-comments "^3.1.0" + taffydb "2.6.2" + underscore "~1.13.2" + jsdom@^16.6.0: version "16.7.0" resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-16.7.0.tgz#918ae71965424b197c819f8183a754e18977b710" @@ -6983,6 +7151,13 @@ kind-of@^6.0.2: resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== +klaw@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/klaw/-/klaw-3.0.0.tgz#b11bec9cf2492f06756d6e809ab73a2910259146" + integrity sha512-0Fo5oir+O9jnXu5EefYbVK+mHMBeEVEy2cmctR1O1NECcCkPRreJKrS6Qt/j3KC2C148Dfo9i3pCmCMsdqGr0g== + dependencies: + graceful-fs "^4.1.9" + kleur@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" @@ -7036,6 +7211,13 @@ lines-and-columns@^1.1.6: resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== +linkify-it@^3.0.1: + version "3.0.3" + resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-3.0.3.tgz#a98baf44ce45a550efb4d49c769d07524cc2fa2e" + integrity sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ== + dependencies: + uc.micro "^1.0.1" + loader-runner@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.2.0.tgz#d7022380d66d14c5fb1d496b89864ebcfd478384" @@ -7132,6 +7314,11 @@ log-symbols@^4.1.0: chalk "^4.1.0" is-unicode-supported "^0.1.0" +long@^5.0.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/long/-/long-5.2.0.tgz#2696dadf4b4da2ce3f6f6b89186085d94d52fd61" + integrity sha512-9RTUNjK60eJbx3uz+TEGF7fUr29ZDxR5QzXcyDpeSfeH28S9ycINflOgOlppit5U+4kNTe83KQnMEerw7GmE8w== + loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" @@ -7184,6 +7371,27 @@ markdown-escapes@^1.0.0: resolved "https://registry.yarnpkg.com/markdown-escapes/-/markdown-escapes-1.0.4.tgz#c95415ef451499d7602b91095f3c8e8975f78535" integrity sha512-8z4efJYk43E0upd0NbVXwgSTQs6cT3T06etieCMEg7dRbzCbxUCK/GHlX8mhHRDcp+OLlHkPKsvqQTCvsRl2cg== +markdown-it-anchor@^8.4.1: + version "8.6.5" + resolved "https://registry.yarnpkg.com/markdown-it-anchor/-/markdown-it-anchor-8.6.5.tgz#30c4bc5bbff327f15ce3c429010ec7ba75e7b5f8" + integrity sha512-PI1qEHHkTNWT+X6Ip9w+paonfIQ+QZP9sCeMYi47oqhH+EsW8CrJ8J7CzV19QVOj6il8ATGbK2nTECj22ZHGvQ== + +markdown-it@^12.3.2: + version "12.3.2" + resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-12.3.2.tgz#bf92ac92283fe983fe4de8ff8abfb5ad72cd0c90" + integrity sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg== + dependencies: + argparse "^2.0.1" + entities "~2.1.0" + linkify-it "^3.0.1" + mdurl "^1.0.1" + uc.micro "^1.0.5" + +marked@^4.0.10: + version "4.1.0" + resolved "https://registry.yarnpkg.com/marked/-/marked-4.1.0.tgz#3fc6e7485f21c1ca5d6ec4a39de820e146954796" + integrity sha512-+Z6KDjSPa6/723PQYyc1axYZpYYpDnECDaU6hkaf5gqBieBkMKYReL5hteF2QizhlMbgbo8umXl/clZ67+GlsA== + match-sorter@^6.0.2: version "6.3.1" resolved "https://registry.yarnpkg.com/match-sorter/-/match-sorter-6.3.1.tgz#98cc37fda756093424ddf3cbc62bfe9c75b92bda" @@ -7228,7 +7436,7 @@ mdn-data@~1.1.0: resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-1.1.4.tgz#50b5d4ffc4575276573c4eedb8780812a8419f01" integrity sha512-FSYbp3lyKjyj3E7fMl6rYvUdX0FBXaluGqlFoYESWQlyUTq8R+wp0rkFxoYFqZlHCvsUXGjyJmLQSnXToYhOSA== -mdurl@^1.0.0: +mdurl@^1.0.0, mdurl@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" integrity sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4= @@ -7355,6 +7563,11 @@ mkdirp@^0.5.5, mkdirp@~0.5.1: dependencies: minimist "^1.2.5" +mkdirp@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" + integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== + moment@^2.29.1: version "2.29.4" resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.4.tgz#3dbe052889fe7c1b2ed966fcb3a77328964ef108" @@ -8502,6 +8715,40 @@ property-information@^5.0.0, property-information@^5.3.0: dependencies: xtend "^4.0.0" +protobufjs-cli@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/protobufjs-cli/-/protobufjs-cli-1.0.2.tgz#905fc49007cf4aaf3c45d5f250eb294eedeea062" + integrity sha512-cz9Pq9p/Zs7okc6avH20W7QuyjTclwJPgqXG11jNaulfS3nbVisID8rC+prfgq0gbZE0w9LBFd1OKFF03kgFzg== + dependencies: + chalk "^4.0.0" + escodegen "^1.13.0" + espree "^9.0.0" + estraverse "^5.1.0" + glob "^8.0.0" + jsdoc "^3.6.3" + minimist "^1.2.0" + semver "^7.1.2" + tmp "^0.2.1" + uglify-js "^3.7.7" + +protobufjs@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.1.1.tgz#0117befb4b0f5a49d028e93f2ca62c3c1f5e7c65" + integrity sha512-d0nMQqS/aT3lfV8bKi9Gbg73vPd2LcDdTDOu6RE/M+h9DY8g1EmDzk3ADPccthEWfTBjkR2oxNdx9Gs8YubT+g== + dependencies: + "@protobufjs/aspromise" "^1.1.2" + "@protobufjs/base64" "^1.1.2" + "@protobufjs/codegen" "^2.0.4" + "@protobufjs/eventemitter" "^1.1.0" + "@protobufjs/fetch" "^1.1.0" + "@protobufjs/float" "^1.0.2" + "@protobufjs/inquire" "^1.1.0" + "@protobufjs/path" "^1.1.2" + "@protobufjs/pool" "^1.1.0" + "@protobufjs/utf8" "^1.1.0" + "@types/node" ">=13.7.0" + long "^5.0.0" + proxy-addr@~2.0.7: version "2.0.7" resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" @@ -9104,6 +9351,13 @@ requires-port@^1.0.0: resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8= +requizzle@^0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/requizzle/-/requizzle-0.2.3.tgz#4675c90aacafb2c036bd39ba2daa4a1cb777fded" + integrity sha512-YanoyJjykPxGHii0fZP0uUPEXpvqfBDxWV7s6GKAiiOsiqhX6vHNyW3Qzdmqp/iq/ExbhaGbVrjB4ruEVSM4GQ== + dependencies: + lodash "^4.17.14" + resolve-cwd@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" @@ -9379,6 +9633,13 @@ semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== +semver@^7.1.2: + version "7.3.7" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f" + integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g== + dependencies: + lru-cache "^6.0.0" + semver@^7.3.2, semver@^7.3.5: version "7.3.5" resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" @@ -9929,6 +10190,11 @@ tabbable@^5.2.1: resolved "https://registry.yarnpkg.com/tabbable/-/tabbable-5.3.2.tgz#66d6119ee8a533634c3f17deb0caa1c379e36ac7" integrity sha512-6G/8EWRFx8CiSe2++/xHhXkmCRq2rHtDtZbQFHx34cvDfZzIBfvwG9zGUNTWMXWLCYvDj3aQqOzdl3oCxKuBkQ== +taffydb@2.6.2: + version "2.6.2" + resolved "https://registry.yarnpkg.com/taffydb/-/taffydb-2.6.2.tgz#7cbcb64b5a141b6a2efc2c5d2c67b4e150b2a268" + integrity sha512-y3JaeRSplks6NYQuCOj3ZFMO3j60rTwbuKCvZxsAraGYH2epusatvZ0baZYA01WsGqJBq/Dl6vOrMUJqyMj8kA== + tailwindcss@^3.0.2: version "3.0.18" resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.0.18.tgz#ea4825e6496d77dc21877b6b61c7cc56cda3add5" @@ -10060,6 +10326,13 @@ tmp@^0.0.33: dependencies: os-tmpdir "~1.0.2" +tmp@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.1.tgz#8457fc3037dcf4719c251367a1af6500ee1ccf14" + integrity sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ== + dependencies: + rimraf "^3.0.0" + tmpl@1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" @@ -10221,6 +10494,16 @@ typescript@^4.4.2: resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.5.5.tgz#d8c953832d28924a9e3d37c73d729c846c5896f3" integrity sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA== +uc.micro@^1.0.1, uc.micro@^1.0.5: + version "1.0.6" + resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.6.tgz#9c411a802a409a91fc6cf74081baba34b24499ac" + integrity sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA== + +uglify-js@^3.7.7: + version "3.17.0" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.17.0.tgz#55bd6e9d19ce5eef0d5ad17cd1f587d85b180a85" + integrity sha512-aTeNPVmgIMPpm1cxXr2Q/nEbvkmV8yq66F3om7X3P/cvOXQ0TMQ64Wk63iyT1gPlmdmGzjGpyLh1f3y8MZWXGg== + unbox-primitive@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.1.tgz#085e215625ec3162574dc8859abee78a59b14471" @@ -10231,6 +10514,11 @@ unbox-primitive@^1.0.1: has-symbols "^1.0.2" which-boxed-primitive "^1.0.2" +underscore@~1.13.2: + version "1.13.4" + resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.13.4.tgz#7886b46bbdf07f768e0052f1828e1dcab40c0dee" + integrity sha512-BQFnUDuAQ4Yf/cYY5LNrK9NCJFKriaRbD9uR1fTeXnBeoa97W0i41qkZfGO9pSo8I5KzjAcSY2XYtdf0oKd7KQ== + unherit@^1.0.4: version "1.1.3" resolved "https://registry.yarnpkg.com/unherit/-/unherit-1.1.3.tgz#6c9b503f2b41b262330c80e91c8614abdaa69c22" @@ -10988,6 +11276,11 @@ xmlchars@^2.2.0: resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== +xmlcreate@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/xmlcreate/-/xmlcreate-2.0.4.tgz#0c5ab0f99cdd02a81065fa9cd8f8ae87624889be" + integrity sha512-nquOebG4sngPmGPICTS5EnxqhKbCmz5Ox5hsszI2T6U5qdrJizBc+0ilYSEjTSzU0yZcmvppztXe/5Al5fUwdg== + xtend@^4.0.0, xtend@^4.0.1, xtend@^4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" @@ -11049,10 +11342,10 @@ yocto-queue@^0.1.0: resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== -zod@^3.11.6: - version "3.11.6" - resolved "https://registry.yarnpkg.com/zod/-/zod-3.11.6.tgz#e43a5e0c213ae2e02aefe7cb2b1a6fa3d7f1f483" - integrity sha512-daZ80A81I3/9lIydI44motWe6n59kRBfNzTuS2bfzVh1nAXi667TOTWWtatxyG+fwgNUiagSj/CWZwRRbevJIg== +zod@^3.19.1: + version "3.19.1" + resolved "https://registry.yarnpkg.com/zod/-/zod-3.19.1.tgz#112f074a97b50bfc4772d4ad1576814bd8ac4473" + integrity sha512-LYjZsEDhCdYET9ikFu6dVPGp2YH9DegXjdJToSzD9rO6fy4qiRYFoyEYwps88OseJlPyl2NOe2iJuhEhL7IpEA== zwitch@^1.0.0: version "1.0.5" From d118fe43756e16fbe912a31ed121be7c8e15b9da Mon Sep 17 00:00:00 2001 From: Danny Chiao Date: Wed, 5 Oct 2022 20:14:59 -0400 Subject: [PATCH 5/8] fix: Fix Feast UI release process to update the feast-ui package (#3267) fix: Fix Feast UI release process to update the feast-ui package to the latest version Signed-off-by: Danny Chiao Signed-off-by: Danny Chiao --- .releaserc.js | 1 + Makefile | 2 +- sdk/python/feast/ui/package.json | 2 +- sdk/python/feast/ui/yarn.lock | 8 ++++---- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/.releaserc.js b/.releaserc.js index 124ad8801c..114d65d1a2 100644 --- a/.releaserc.js +++ b/.releaserc.js @@ -67,6 +67,7 @@ module.exports = { "java/pom.xml", "infra/charts/**/*.*", "ui/package.json", + "sdk/python/feast/ui/package.json", "sdk/python/feast/ui/yarn.lock" ], message: "chore(release): release ${nextRelease.version}\n\n${nextRelease.notes}" diff --git a/Makefile b/Makefile index fabcb388e8..9acd2fc862 100644 --- a/Makefile +++ b/Makefile @@ -446,4 +446,4 @@ build-helm-docs: # Note: requires node and yarn to be installed build-ui: - cd $(ROOT_DIR)/sdk/python/feast/ui && yarn install && npm run build --omit=dev + cd $(ROOT_DIR)/sdk/python/feast/ui && yarn upgrade @feast-dev/feast-ui --latest && yarn install && npm run build --omit=dev diff --git a/sdk/python/feast/ui/package.json b/sdk/python/feast/ui/package.json index 6ffebcc834..5854f20570 100644 --- a/sdk/python/feast/ui/package.json +++ b/sdk/python/feast/ui/package.json @@ -6,7 +6,7 @@ "@elastic/datemath": "^5.0.3", "@elastic/eui": "^55.0.1", "@emotion/react": "^11.9.0", - "@feast-dev/feast-ui": "latest", + "@feast-dev/feast-ui": "0.25.1", "@testing-library/jest-dom": "^5.16.4", "@testing-library/react": "^13.2.0", "@testing-library/user-event": "^13.5.0", diff --git a/sdk/python/feast/ui/yarn.lock b/sdk/python/feast/ui/yarn.lock index 1b9cf5f067..af820b085a 100644 --- a/sdk/python/feast/ui/yarn.lock +++ b/sdk/python/feast/ui/yarn.lock @@ -1300,10 +1300,10 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@feast-dev/feast-ui@latest": - version "0.24.0" - resolved "https://registry.yarnpkg.com/@feast-dev/feast-ui/-/feast-ui-0.24.0.tgz#a52037247563290f92d0d993fcaf0d88e9741f36" - integrity sha512-Te27bSVFp7gCE7+p9bbCkCEQ7+nsRCzBtwWivNPBFRn8HC2ewBzmRzzasXlCHok1cXHDbh7Xj7y+2Hshp91LTg== +"@feast-dev/feast-ui@0.25.1": + version "0.25.1" + resolved "https://registry.yarnpkg.com/@feast-dev/feast-ui/-/feast-ui-0.25.1.tgz#c15e04dfdd4c616fcce254fc22f1474ba4c7b3fe" + integrity sha512-WKJEF2KwzJ9ydoDHlkaYDboHEud+Q/ij8ShGs9CxygNFMSXR00cc63QDdXPLNG4dCE0afSjlgqLtV4R3EJTBfg== dependencies: "@elastic/datemath" "^5.0.3" "@elastic/eui" "^55.0.1" From 4ce366a6d3320b7f7862d69fc1d44fde46566a55 Mon Sep 17 00:00:00 2001 From: Kevin Zhang Date: Wed, 5 Oct 2022 17:15:58 -0700 Subject: [PATCH 6/8] fix: Fix docker image for feature-server (#3272) * Fix Signed-off-by: Kevin Zhang * Fix Signed-off-by: Kevin Zhang Signed-off-by: Kevin Zhang --- .github/workflows/publish.yml | 2 +- sdk/python/feast/infra/feature_servers/multicloud/Dockerfile | 4 ++-- .../feast/infra/feature_servers/multicloud/Dockerfile.dev | 3 ++- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 9587044a84..039ab6a24e 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -46,7 +46,7 @@ jobs: build-publish-docker-images: runs-on: ubuntu-latest - needs: get-version + needs: [get-version, publish-python-sdk] strategy: matrix: component: [feature-server, feature-server-python-aws, feature-server-java, feature-transformation-server] diff --git a/sdk/python/feast/infra/feature_servers/multicloud/Dockerfile b/sdk/python/feast/infra/feature_servers/multicloud/Dockerfile index 990c1fd8f0..c95c515fb4 100644 --- a/sdk/python/feast/infra/feature_servers/multicloud/Dockerfile +++ b/sdk/python/feast/infra/feature_servers/multicloud/Dockerfile @@ -8,8 +8,8 @@ RUN apt update && \ build-essential RUN pip install pip --upgrade -COPY . . -RUN pip install ".[aws,gcp,snowflake,redis,go,mysql,postgres]" +RUN pip install "feast[aws,gcp,snowflake,redis,go,mysql,postgres]" + RUN apt update RUN apt install -y -V ca-certificates lsb-release wget diff --git a/sdk/python/feast/infra/feature_servers/multicloud/Dockerfile.dev b/sdk/python/feast/infra/feature_servers/multicloud/Dockerfile.dev index 990c1fd8f0..ecbc199a5b 100644 --- a/sdk/python/feast/infra/feature_servers/multicloud/Dockerfile.dev +++ b/sdk/python/feast/infra/feature_servers/multicloud/Dockerfile.dev @@ -9,7 +9,8 @@ RUN apt update && \ RUN pip install pip --upgrade COPY . . -RUN pip install ".[aws,gcp,snowflake,redis,go,mysql,postgres]" + +RUN pip install "feast[aws,gcp,snowflake,redis,go,mysql,postgres]" RUN apt update RUN apt install -y -V ca-certificates lsb-release wget From ae6f8af224083b5f2dd55edccfac0b49810460ba Mon Sep 17 00:00:00 2001 From: Danny Chiao Date: Thu, 6 Oct 2022 14:21:30 -0400 Subject: [PATCH 7/8] ci: Fix Feast UI tests (#3273) * ci: Fix Feast UI tests Signed-off-by: Danny Chiao * add test to workflow Signed-off-by: Danny Chiao * add test to workflow Signed-off-by: Danny Chiao * fix test suite in workflow Signed-off-by: Danny Chiao * fix README Signed-off-by: Danny Chiao * fix build Signed-off-by: Danny Chiao * fix test name Signed-off-by: Danny Chiao * upgrade caniuse Signed-off-by: Danny Chiao Signed-off-by: Danny Chiao --- .github/workflows/unit_tests.yml | 20 +++++++++++++++++ sdk/python/feast/ui/README.md | 15 ++++++++++++- ui/package.json | 6 ++++-- ui/src/FeastUISansProviders.test.tsx | 32 +++++++++++++--------------- ui/src/mocks/handlers.ts | 14 ++++++++---- ui/src/parsers/jsonType.ts | 11 ---------- ui/yarn.lock | 8 +++---- 7 files changed, 67 insertions(+), 39 deletions(-) delete mode 100644 ui/src/parsers/jsonType.ts diff --git a/.github/workflows/unit_tests.yml b/.github/workflows/unit_tests.yml index de6d98d140..ebc09f0080 100644 --- a/.github/workflows/unit_tests.yml +++ b/.github/workflows/unit_tests.yml @@ -108,3 +108,23 @@ jobs: sudo apt install -y -V libarrow-dev - name: Test run: make test-go + + unit-test-ui: + runs-on: ubuntu-latest + env: + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-node@v2 + with: + node-version: '17.x' + registry-url: 'https://registry.npmjs.org' + - name: Install yarn dependencies + working-directory: ./ui + run: yarn install + - name: Build yarn rollup + working-directory: ./ui + run: yarn build:lib + - name: Run yarn tests + working-directory: ./ui + run: yarn test --watchAll=false diff --git a/sdk/python/feast/ui/README.md b/sdk/python/feast/ui/README.md index 220f40a225..28290f0326 100644 --- a/sdk/python/feast/ui/README.md +++ b/sdk/python/feast/ui/README.md @@ -25,4 +25,17 @@ The `feast ui` command will generate the necessary `projects-list.json` file and **Note**: `yarn start` will not work on this because of the above dependency. ## Dev -To test, do `yarn link` in ui/ and then come here to do `yarn link @feast-dev/feast` \ No newline at end of file +To test with a locally built Feast UI package, do: +1. `yarn link` in ui/ +2. `yarn install` in ui/ +3. `yarn link` in ui/node_modules/react +4. `yarn link` in ui/node_modules/react-dom +5. and then come here to do: + ```bash + yarn link "@feast-dev/feast" + yarn link react + yarn link react-dom + yarn start + ``` + +See also https://github.com/facebook/react/issues/14257. \ No newline at end of file diff --git a/ui/package.json b/ui/package.json index 9fa8b58fb4..542d76aebb 100644 --- a/ui/package.json +++ b/ui/package.json @@ -25,7 +25,8 @@ "react-router-dom": "6", "react-scripts": "^5.0.0", "typescript": "^4.4.2", - "use-query-params": "^1.2.3" + "use-query-params": "^1.2.3", + "zod": "^3.11.6" }, "dependencies": { "@elastic/datemath": "^5.0.3", @@ -45,7 +46,8 @@ "react-query": "^3.34.12", "react-router-dom": "6", "react-scripts": "^5.0.0", - "use-query-params": "^1.2.3" + "use-query-params": "^1.2.3", + "zod": "^3.11.6" }, "scripts": { "start": "npm run generate-protos && react-scripts start", diff --git a/ui/src/FeastUISansProviders.test.tsx b/ui/src/FeastUISansProviders.test.tsx index 09985bc133..4670232809 100644 --- a/ui/src/FeastUISansProviders.test.tsx +++ b/ui/src/FeastUISansProviders.test.tsx @@ -15,13 +15,17 @@ import { creditHistoryRegistry, } from "./mocks/handlers"; -import registry from "../public/registry.json"; +import { readFileSync } from "fs"; +import { feast } from "./protos"; +import path from "path"; // declare which API requests to mock const server = setupServer( projectsListWithDefaultProject, creditHistoryRegistry ); +const registry = readFileSync(path.resolve(__dirname, "../public/registry.db")); +const parsedRegistry = feast.core.Registry.decode(registry); // establish API mocking before all tests beforeAll(() => server.listen()); @@ -50,7 +54,10 @@ test("full app rendering", async () => { // Explore Panel Should Appear expect(screen.getByText(/Explore this Project/i)).toBeInTheDocument(); - const projectNameRegExp = new RegExp(registry.project, "i"); + const projectNameRegExp = new RegExp( + parsedRegistry.projectMetadata[0].project!, + "i" + ); // It should load the default project, which is credit_scoring_aws await waitFor(() => { @@ -95,9 +102,9 @@ test("routes are reachable", async () => { } }); - -const featureViewName = registry.featureViews[0].spec.name; -const featureName = registry.featureViews[0].spec.features[0].name; +const spec = parsedRegistry.featureViews[0].spec!; +const featureViewName = spec.name!; +const featureName = spec.features![0]!.name!; test("features are reachable", async () => { render(); @@ -106,10 +113,7 @@ test("features are reachable", async () => { await screen.findByText(/Explore this Project/i); const routeRegExp = new RegExp("Feature Views", "i"); - userEvent.click( - screen.getByRole("button", { name: routeRegExp }), - leftClick - ); + userEvent.click(screen.getByRole("button", { name: routeRegExp }), leftClick); screen.getByRole("heading", { name: "Feature Views", @@ -118,18 +122,12 @@ test("features are reachable", async () => { await screen.findAllByText(/Feature Views/i); const fvRegExp = new RegExp(featureViewName, "i"); - userEvent.click( - screen.getByRole("link", { name: fvRegExp }), - leftClick - ) + userEvent.click(screen.getByRole("link", { name: fvRegExp }), leftClick); await screen.findByText(featureName); const fRegExp = new RegExp(featureName, "i"); - userEvent.click( - screen.getByRole("link", { name: fRegExp }), - leftClick - ) + userEvent.click(screen.getByRole("link", { name: fRegExp }), leftClick); // Should land on a page with the heading // await screen.findByText("Feature: " + featureName); screen.getByRole("heading", { diff --git a/ui/src/mocks/handlers.ts b/ui/src/mocks/handlers.ts index e7b0040f0d..39f30b62a6 100644 --- a/ui/src/mocks/handlers.ts +++ b/ui/src/mocks/handlers.ts @@ -1,5 +1,8 @@ import { rest } from "msw"; -import registry from "../../public/registry.json"; +import {readFileSync} from 'fs'; +import path from "path"; + +const registry = readFileSync(path.resolve(__dirname, "../../public/registry.db")); const projectsListWithDefaultProject = rest.get( "/projects-list.json", @@ -14,7 +17,7 @@ const projectsListWithDefaultProject = rest.get( description: "Project for credit scoring team and associated models.", id: "credit_score_project", - registryPath: "/registry.json", + registryPath: "/registry.pb", }, ], }) @@ -22,8 +25,11 @@ const projectsListWithDefaultProject = rest.get( } ); -const creditHistoryRegistry = rest.get("/registry.json", (req, res, ctx) => { - return res(ctx.status(200), ctx.json(registry)); +const creditHistoryRegistry = rest.get("/registry.pb", (req, res, ctx) => { + return res( + ctx.status(200), + ctx.set('Content-Type', 'application/octet-stream'), + ctx.body(registry)); }); export { projectsListWithDefaultProject, creditHistoryRegistry }; diff --git a/ui/src/parsers/jsonType.ts b/ui/src/parsers/jsonType.ts deleted file mode 100644 index be484b5477..0000000000 --- a/ui/src/parsers/jsonType.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { z } from "zod"; - -// Taken from the zod documentation code - accepts any JSON object. -const literalSchema = z.union([z.string(), z.number(), z.boolean(), z.null()]); -type Literal = z.infer; -type Json = Literal | { [key: string]: Json } | Json[]; -const jsonSchema: z.ZodType = z.lazy(() => - z.union([literalSchema, z.array(jsonSchema), z.record(jsonSchema)]) -); - -export { jsonSchema }; diff --git a/ui/yarn.lock b/ui/yarn.lock index e056cad617..948eb78796 100644 --- a/ui/yarn.lock +++ b/ui/yarn.lock @@ -3559,9 +3559,9 @@ caniuse-api@^3.0.0: lodash.uniq "^4.5.0" caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001286, caniuse-lite@^1.0.30001297, caniuse-lite@^1.0.30001299: - version "1.0.30001303" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001303.tgz#9b168e4f43ccfc372b86f4bc5a551d9b909c95c9" - integrity sha512-/Mqc1oESndUNszJP0kx0UaQU9kEv9nNtJ7Kn8AdA0mNnH8eR1cj0kG+NbNuC1Wq/b21eA8prhKRA3bbkjONegQ== + version "1.0.30001416" + resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001416.tgz" + integrity sha512-06wzzdAkCPZO+Qm4e/eNghZBDfVNDsCgw33T27OwBH9unE9S478OYw//Q2L7Npf/zBzs7rjZOszIFQkwQKAEqA== case-sensitive-paths-webpack-plugin@^2.4.0: version "2.4.0" @@ -11342,7 +11342,7 @@ yocto-queue@^0.1.0: resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== -zod@^3.19.1: +zod@^3.11.6: version "3.19.1" resolved "https://registry.yarnpkg.com/zod/-/zod-3.19.1.tgz#112f074a97b50bfc4772d4ad1576814bd8ac4473" integrity sha512-LYjZsEDhCdYET9ikFu6dVPGp2YH9DegXjdJToSzD9rO6fy4qiRYFoyEYwps88OseJlPyl2NOe2iJuhEhL7IpEA== From de8334f0406acbc95e3953f3225965684b91d908 Mon Sep 17 00:00:00 2001 From: feast-ci-bot Date: Thu, 6 Oct 2022 18:39:47 +0000 Subject: [PATCH 8/8] chore(release): release 0.25.2 ## [0.25.2](https://github.com/feast-dev/feast/compare/v0.25.1...v0.25.2) (2022-10-06) ### Bug Fixes * Fix docker image for feature-server ([#3272](https://github.com/feast-dev/feast/issues/3272)) ([4ce366a](https://github.com/feast-dev/feast/commit/4ce366a6d3320b7f7862d69fc1d44fde46566a55)) * Fix Feast UI release process to update the feast-ui package ([#3267](https://github.com/feast-dev/feast/issues/3267)) ([d118fe4](https://github.com/feast-dev/feast/commit/d118fe43756e16fbe912a31ed121be7c8e15b9da)) * Stream feature view meta undefined created_timestamp issue ([#3266](https://github.com/feast-dev/feast/issues/3266)) ([efbd4b0](https://github.com/feast-dev/feast/commit/efbd4b040deb96eef86eb45cd420bfe5b64ffa96)) * Udf in stream feature view UI shows pickled data ([#3268](https://github.com/feast-dev/feast/issues/3268)) ([f4a83a7](https://github.com/feast-dev/feast/commit/f4a83a7762ac0105b75b20e19822304cce97181c)) * Updated quickstart notebook to patch an incorrect reference to an outdated featureview name ([#3271](https://github.com/feast-dev/feast/issues/3271)) ([7fa4bbf](https://github.com/feast-dev/feast/commit/7fa4bbf2be98847fa2b795fe0d7dc77d5e45b2fb)) --- CHANGELOG.md | 11 +++ infra/charts/feast-feature-server/Chart.yaml | 2 +- infra/charts/feast-feature-server/README.md | 4 +- infra/charts/feast-feature-server/values.yaml | 2 +- infra/charts/feast-python-server/Chart.yaml | 2 +- infra/charts/feast-python-server/README.md | 2 +- infra/charts/feast/Chart.yaml | 2 +- infra/charts/feast/README.md | 6 +- .../feast/charts/feature-server/Chart.yaml | 4 +- .../feast/charts/feature-server/README.md | 4 +- .../feast/charts/feature-server/values.yaml | 2 +- .../charts/transformation-service/Chart.yaml | 4 +- .../charts/transformation-service/README.md | 4 +- .../charts/transformation-service/values.yaml | 2 +- infra/charts/feast/requirements.yaml | 4 +- java/pom.xml | 2 +- sdk/python/feast/ui/package.json | 2 +- sdk/python/feast/ui/yarn.lock | 90 ++++++++++++++++++- ui/package.json | 2 +- 19 files changed, 122 insertions(+), 29 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 41512e4a49..7a8fd81055 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,16 @@ # Changelog +## [0.25.2](https://github.com/feast-dev/feast/compare/v0.25.1...v0.25.2) (2022-10-06) + + +### Bug Fixes + +* Fix docker image for feature-server ([#3272](https://github.com/feast-dev/feast/issues/3272)) ([4ce366a](https://github.com/feast-dev/feast/commit/4ce366a6d3320b7f7862d69fc1d44fde46566a55)) +* Fix Feast UI release process to update the feast-ui package ([#3267](https://github.com/feast-dev/feast/issues/3267)) ([d118fe4](https://github.com/feast-dev/feast/commit/d118fe43756e16fbe912a31ed121be7c8e15b9da)) +* Stream feature view meta undefined created_timestamp issue ([#3266](https://github.com/feast-dev/feast/issues/3266)) ([efbd4b0](https://github.com/feast-dev/feast/commit/efbd4b040deb96eef86eb45cd420bfe5b64ffa96)) +* Udf in stream feature view UI shows pickled data ([#3268](https://github.com/feast-dev/feast/issues/3268)) ([f4a83a7](https://github.com/feast-dev/feast/commit/f4a83a7762ac0105b75b20e19822304cce97181c)) +* Updated quickstart notebook to patch an incorrect reference to an outdated featureview name ([#3271](https://github.com/feast-dev/feast/issues/3271)) ([7fa4bbf](https://github.com/feast-dev/feast/commit/7fa4bbf2be98847fa2b795fe0d7dc77d5e45b2fb)) + ## [0.25.1](https://github.com/feast-dev/feast/compare/v0.25.0...v0.25.1) (2022-09-30) diff --git a/infra/charts/feast-feature-server/Chart.yaml b/infra/charts/feast-feature-server/Chart.yaml index 6d8744dca2..bbab077b28 100644 --- a/infra/charts/feast-feature-server/Chart.yaml +++ b/infra/charts/feast-feature-server/Chart.yaml @@ -2,7 +2,7 @@ apiVersion: v2 name: feast-feature-server description: Feast Feature Server in Go or Python type: application -version: 0.25.1 +version: 0.25.2 keywords: - machine learning - big data diff --git a/infra/charts/feast-feature-server/README.md b/infra/charts/feast-feature-server/README.md index 41fd4c6237..ce6f32919f 100644 --- a/infra/charts/feast-feature-server/README.md +++ b/infra/charts/feast-feature-server/README.md @@ -1,6 +1,6 @@ # Feast Python / Go Feature Server Helm Charts -Current chart version is `0.25.1` +Current chart version is `0.25.2` ## Installation @@ -30,7 +30,7 @@ See [here](https://github.com/feast-dev/feast/tree/master/examples/python-helm-d | fullnameOverride | string | `""` | | | image.pullPolicy | string | `"IfNotPresent"` | | | image.repository | string | `"feastdev/feature-server"` | Docker image for Feature Server repository | -| image.tag | string | `"0.25.1"` | The Docker image tag (can be overwritten if custom feature server deps are needed for on demand transforms) | +| image.tag | string | `"0.25.2"` | The Docker image tag (can be overwritten if custom feature server deps are needed for on demand transforms) | | imagePullSecrets | list | `[]` | | | livenessProbe.initialDelaySeconds | int | `30` | | | livenessProbe.periodSeconds | int | `30` | | diff --git a/infra/charts/feast-feature-server/values.yaml b/infra/charts/feast-feature-server/values.yaml index 782d219630..90a216a54c 100644 --- a/infra/charts/feast-feature-server/values.yaml +++ b/infra/charts/feast-feature-server/values.yaml @@ -9,7 +9,7 @@ image: repository: feastdev/feature-server pullPolicy: IfNotPresent # image.tag -- The Docker image tag (can be overwritten if custom feature server deps are needed for on demand transforms) - tag: 0.25.1 + tag: 0.25.2 imagePullSecrets: [] nameOverride: "" diff --git a/infra/charts/feast-python-server/Chart.yaml b/infra/charts/feast-python-server/Chart.yaml index 7e1be9ceb1..67ef3ca0a7 100644 --- a/infra/charts/feast-python-server/Chart.yaml +++ b/infra/charts/feast-python-server/Chart.yaml @@ -2,7 +2,7 @@ apiVersion: v2 name: feast-python-server description: Feast Feature Server in Python type: application -version: 0.25.1 +version: 0.25.2 keywords: - machine learning - big data diff --git a/infra/charts/feast-python-server/README.md b/infra/charts/feast-python-server/README.md index 20829e6d78..a86a950634 100644 --- a/infra/charts/feast-python-server/README.md +++ b/infra/charts/feast-python-server/README.md @@ -2,7 +2,7 @@ > Note: this helm chart is deprecated in favor of [feast-feature-server](../feast-feature-server/README.md) -Current chart version is `0.25.1` +Current chart version is `0.25.2` ## Installation Docker repository and tag are required. Helm install example: diff --git a/infra/charts/feast/Chart.yaml b/infra/charts/feast/Chart.yaml index 2bd45f334f..ec6795897b 100644 --- a/infra/charts/feast/Chart.yaml +++ b/infra/charts/feast/Chart.yaml @@ -1,7 +1,7 @@ apiVersion: v1 description: Feature store for machine learning name: feast -version: 0.25.1 +version: 0.25.2 keywords: - machine learning - big data diff --git a/infra/charts/feast/README.md b/infra/charts/feast/README.md index 592d5f053f..f679ea3476 100644 --- a/infra/charts/feast/README.md +++ b/infra/charts/feast/README.md @@ -8,7 +8,7 @@ This repo contains Helm charts for Feast Java components that are being installe ## Chart: Feast -Feature store for machine learning Current chart version is `0.25.1` +Feature store for machine learning Current chart version is `0.25.2` ## Installation @@ -65,8 +65,8 @@ See [here](https://github.com/feast-dev/feast/tree/master/examples/java-demo) fo | Repository | Name | Version | |------------|------|---------| | https://charts.helm.sh/stable | redis | 10.5.6 | -| https://feast-helm-charts.storage.googleapis.com | feature-server(feature-server) | 0.25.1 | -| https://feast-helm-charts.storage.googleapis.com | transformation-service(transformation-service) | 0.25.1 | +| https://feast-helm-charts.storage.googleapis.com | feature-server(feature-server) | 0.25.2 | +| https://feast-helm-charts.storage.googleapis.com | transformation-service(transformation-service) | 0.25.2 | ## Values diff --git a/infra/charts/feast/charts/feature-server/Chart.yaml b/infra/charts/feast/charts/feature-server/Chart.yaml index fcb4444b81..796461ffba 100644 --- a/infra/charts/feast/charts/feature-server/Chart.yaml +++ b/infra/charts/feast/charts/feature-server/Chart.yaml @@ -1,8 +1,8 @@ apiVersion: v1 description: "Feast Feature Server: Online feature serving service for Feast" name: feature-server -version: 0.25.1 -appVersion: v0.25.1 +version: 0.25.2 +appVersion: v0.25.2 keywords: - machine learning - big data diff --git a/infra/charts/feast/charts/feature-server/README.md b/infra/charts/feast/charts/feature-server/README.md index c4703c3a17..b31311ab09 100644 --- a/infra/charts/feast/charts/feature-server/README.md +++ b/infra/charts/feast/charts/feature-server/README.md @@ -1,6 +1,6 @@ # feature-server -![Version: 0.25.1](https://img.shields.io/badge/Version-0.25.1-informational?style=flat-square) ![AppVersion: v0.25.1](https://img.shields.io/badge/AppVersion-v0.25.1-informational?style=flat-square) +![Version: 0.25.2](https://img.shields.io/badge/Version-0.25.2-informational?style=flat-square) ![AppVersion: v0.25.2](https://img.shields.io/badge/AppVersion-v0.25.2-informational?style=flat-square) Feast Feature Server: Online feature serving service for Feast @@ -17,7 +17,7 @@ Feast Feature Server: Online feature serving service for Feast | envOverrides | object | `{}` | Extra environment variables to set | | image.pullPolicy | string | `"IfNotPresent"` | Image pull policy | | image.repository | string | `"feastdev/feature-server-java"` | Docker image for Feature Server repository | -| image.tag | string | `"0.25.1"` | Image tag | +| image.tag | string | `"0.25.2"` | Image tag | | ingress.grpc.annotations | object | `{}` | Extra annotations for the ingress | | ingress.grpc.auth.enabled | bool | `false` | Flag to enable auth | | ingress.grpc.class | string | `"nginx"` | Which ingress controller to use | diff --git a/infra/charts/feast/charts/feature-server/values.yaml b/infra/charts/feast/charts/feature-server/values.yaml index 35380787bc..617ecf3445 100644 --- a/infra/charts/feast/charts/feature-server/values.yaml +++ b/infra/charts/feast/charts/feature-server/values.yaml @@ -5,7 +5,7 @@ image: # image.repository -- Docker image for Feature Server repository repository: feastdev/feature-server-java # image.tag -- Image tag - tag: 0.25.1 + tag: 0.25.2 # image.pullPolicy -- Image pull policy pullPolicy: IfNotPresent diff --git a/infra/charts/feast/charts/transformation-service/Chart.yaml b/infra/charts/feast/charts/transformation-service/Chart.yaml index 878ed7e038..b6b5c00139 100644 --- a/infra/charts/feast/charts/transformation-service/Chart.yaml +++ b/infra/charts/feast/charts/transformation-service/Chart.yaml @@ -1,8 +1,8 @@ apiVersion: v1 description: "Transformation service: to compute on-demand features" name: transformation-service -version: 0.25.1 -appVersion: v0.25.1 +version: 0.25.2 +appVersion: v0.25.2 keywords: - machine learning - big data diff --git a/infra/charts/feast/charts/transformation-service/README.md b/infra/charts/feast/charts/transformation-service/README.md index fea87a55e0..8fdc8292af 100644 --- a/infra/charts/feast/charts/transformation-service/README.md +++ b/infra/charts/feast/charts/transformation-service/README.md @@ -1,6 +1,6 @@ # transformation-service -![Version: 0.25.1](https://img.shields.io/badge/Version-0.25.1-informational?style=flat-square) ![AppVersion: v0.25.1](https://img.shields.io/badge/AppVersion-v0.25.1-informational?style=flat-square) +![Version: 0.25.2](https://img.shields.io/badge/Version-0.25.2-informational?style=flat-square) ![AppVersion: v0.25.2](https://img.shields.io/badge/AppVersion-v0.25.2-informational?style=flat-square) Transformation service: to compute on-demand features @@ -13,7 +13,7 @@ Transformation service: to compute on-demand features | envOverrides | object | `{}` | Extra environment variables to set | | image.pullPolicy | string | `"IfNotPresent"` | Image pull policy | | image.repository | string | `"feastdev/feature-transformation-server"` | Docker image for Transformation Server repository | -| image.tag | string | `"0.25.1"` | Image tag | +| image.tag | string | `"0.25.2"` | Image tag | | nodeSelector | object | `{}` | Node labels for pod assignment | | podLabels | object | `{}` | Labels to be added to Feast Serving pods | | replicaCount | int | `1` | Number of pods that will be created | diff --git a/infra/charts/feast/charts/transformation-service/values.yaml b/infra/charts/feast/charts/transformation-service/values.yaml index 1bf259ec18..72e335130b 100644 --- a/infra/charts/feast/charts/transformation-service/values.yaml +++ b/infra/charts/feast/charts/transformation-service/values.yaml @@ -5,7 +5,7 @@ image: # image.repository -- Docker image for Transformation Server repository repository: feastdev/feature-transformation-server # image.tag -- Image tag - tag: 0.25.1 + tag: 0.25.2 # image.pullPolicy -- Image pull policy pullPolicy: IfNotPresent diff --git a/infra/charts/feast/requirements.yaml b/infra/charts/feast/requirements.yaml index 20d89e3669..bda09b020a 100644 --- a/infra/charts/feast/requirements.yaml +++ b/infra/charts/feast/requirements.yaml @@ -1,12 +1,12 @@ dependencies: - name: feature-server alias: feature-server - version: 0.25.1 + version: 0.25.2 condition: feature-server.enabled repository: https://feast-helm-charts.storage.googleapis.com - name: transformation-service alias: transformation-service - version: 0.25.1 + version: 0.25.2 condition: transformation-service.enabled repository: https://feast-helm-charts.storage.googleapis.com - name: redis diff --git a/java/pom.xml b/java/pom.xml index aa6157a14f..8568e3bb98 100644 --- a/java/pom.xml +++ b/java/pom.xml @@ -35,7 +35,7 @@ - 0.25.1 + 0.25.2 https://github.com/feast-dev/feast UTF-8 diff --git a/sdk/python/feast/ui/package.json b/sdk/python/feast/ui/package.json index 5854f20570..a75d7be1ff 100644 --- a/sdk/python/feast/ui/package.json +++ b/sdk/python/feast/ui/package.json @@ -6,7 +6,7 @@ "@elastic/datemath": "^5.0.3", "@elastic/eui": "^55.0.1", "@emotion/react": "^11.9.0", - "@feast-dev/feast-ui": "0.25.1", + "@feast-dev/feast-ui": "0.25.2", "@testing-library/jest-dom": "^5.16.4", "@testing-library/react": "^13.2.0", "@testing-library/user-event": "^13.5.0", diff --git a/sdk/python/feast/ui/yarn.lock b/sdk/python/feast/ui/yarn.lock index af820b085a..0793fed1c5 100644 --- a/sdk/python/feast/ui/yarn.lock +++ b/sdk/python/feast/ui/yarn.lock @@ -1300,10 +1300,10 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@feast-dev/feast-ui@0.25.1": - version "0.25.1" - resolved "https://registry.yarnpkg.com/@feast-dev/feast-ui/-/feast-ui-0.25.1.tgz#c15e04dfdd4c616fcce254fc22f1474ba4c7b3fe" - integrity sha512-WKJEF2KwzJ9ydoDHlkaYDboHEud+Q/ij8ShGs9CxygNFMSXR00cc63QDdXPLNG4dCE0afSjlgqLtV4R3EJTBfg== +"@feast-dev/feast-ui@0.25.2": + version "0.25.2" + resolved "https://registry.yarnpkg.com/@feast-dev/feast-ui/-/feast-ui-0.25.2.tgz#7dfd132f86d7ee31cc52ade1a3c44ea8ece060b1" + integrity sha512-0qFhgpJqh2HDl79oFp26HWq+iI0kNYzSaQ0fgwWmt7MxCxz6HMzEZxn1mZh0mQ8iOPKYUpxHA5QO2cUjgimk9g== dependencies: "@elastic/datemath" "^5.0.3" "@elastic/eui" "^55.0.1" @@ -1317,6 +1317,7 @@ inter-ui "^3.19.3" moment "^2.29.1" prop-types "^15.8.1" + protobufjs "^7.1.1" query-string "^7.1.1" react-query "^3.34.12" react-router-dom "6" @@ -1665,6 +1666,59 @@ schema-utils "^3.0.0" source-map "^0.7.3" +"@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf" + integrity sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ== + +"@protobufjs/base64@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/base64/-/base64-1.1.2.tgz#4c85730e59b9a1f1f349047dbf24296034bb2735" + integrity sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg== + +"@protobufjs/codegen@^2.0.4": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@protobufjs/codegen/-/codegen-2.0.4.tgz#7ef37f0d010fb028ad1ad59722e506d9262815cb" + integrity sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg== + +"@protobufjs/eventemitter@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz#355cbc98bafad5978f9ed095f397621f1d066b70" + integrity sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q== + +"@protobufjs/fetch@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/fetch/-/fetch-1.1.0.tgz#ba99fb598614af65700c1619ff06d454b0d84c45" + integrity sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ== + dependencies: + "@protobufjs/aspromise" "^1.1.1" + "@protobufjs/inquire" "^1.1.0" + +"@protobufjs/float@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@protobufjs/float/-/float-1.0.2.tgz#5e9e1abdcb73fc0a7cb8b291df78c8cbd97b87d1" + integrity sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ== + +"@protobufjs/inquire@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/inquire/-/inquire-1.1.0.tgz#ff200e3e7cf2429e2dcafc1140828e8cc638f089" + integrity sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q== + +"@protobufjs/path@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/path/-/path-1.1.2.tgz#6cc2b20c5c9ad6ad0dccfd21ca7673d8d7fbf68d" + integrity sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA== + +"@protobufjs/pool@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/pool/-/pool-1.1.0.tgz#09fd15f2d6d3abfa9b65bc366506d6ad7846ff54" + integrity sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw== + +"@protobufjs/utf8@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570" + integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw== + "@rollup/plugin-babel@^5.2.0": version "5.3.1" resolved "https://registry.yarnpkg.com/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz#04bc0608f4aa4b2e4b1aebf284344d0f68fda283" @@ -2328,6 +2382,11 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.32.tgz#51d59d7a90ef2d0ae961791e0900cad2393a0149" integrity sha512-eAIcfAvhf/BkHcf4pkLJ7ECpBAhh9kcxRBpip9cTiO+hf+aJrsxYxBeS6OXvOd9WqNAJmavXVpZvY1rBjNsXmw== +"@types/node@>=13.7.0": + version "18.8.3" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.8.3.tgz#ce750ab4017effa51aed6a7230651778d54e327c" + integrity sha512-0os9vz6BpGwxGe9LOhgP/ncvYN5Tx1fNcd2TM3rD/aCGBkysb+ZWpXEocG24h6ZzOi13+VB8HndAQFezsSOw1w== + "@types/node@^16.7.13": version "16.11.34" resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.34.tgz#520224e4be4448c279ecad09639ab460cc441a50" @@ -6902,6 +6961,11 @@ lodash@^4.17.15, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.7.0: resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== +long@^5.0.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/long/-/long-5.2.0.tgz#2696dadf4b4da2ce3f6f6b89186085d94d52fd61" + integrity sha512-9RTUNjK60eJbx3uz+TEGF7fUr29ZDxR5QzXcyDpeSfeH28S9ycINflOgOlppit5U+4kNTe83KQnMEerw7GmE8w== + loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" @@ -8207,6 +8271,24 @@ property-information@^5.0.0, property-information@^5.3.0: dependencies: xtend "^4.0.0" +protobufjs@^7.1.1: + version "7.1.2" + resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.1.2.tgz#a0cf6aeaf82f5625bffcf5a38b7cd2a7de05890c" + integrity sha512-4ZPTPkXCdel3+L81yw3dG6+Kq3umdWKh7Dc7GW/CpNk4SX3hK58iPCWeCyhVTDrbkNeKrYNZ7EojM5WDaEWTLQ== + dependencies: + "@protobufjs/aspromise" "^1.1.2" + "@protobufjs/base64" "^1.1.2" + "@protobufjs/codegen" "^2.0.4" + "@protobufjs/eventemitter" "^1.1.0" + "@protobufjs/fetch" "^1.1.0" + "@protobufjs/float" "^1.0.2" + "@protobufjs/inquire" "^1.1.0" + "@protobufjs/path" "^1.1.2" + "@protobufjs/pool" "^1.1.0" + "@protobufjs/utf8" "^1.1.0" + "@types/node" ">=13.7.0" + long "^5.0.0" + proxy-addr@~2.0.7: version "2.0.7" resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" diff --git a/ui/package.json b/ui/package.json index 542d76aebb..24895f970e 100644 --- a/ui/package.json +++ b/ui/package.json @@ -1,6 +1,6 @@ { "name": "@feast-dev/feast-ui", - "version": "0.25.1", + "version": "0.25.2", "private": false, "files": [ "dist"