diff --git a/package-lock.json b/package-lock.json index 923ba0b9806..59f1a5cb0b7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4123,8 +4123,9 @@ }, "node_modules/@isaacs/cliui": { "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", "dev": true, - "license": "ISC", "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", @@ -4138,9 +4139,10 @@ } }, "node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.0.1", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", "dev": true, - "license": "MIT", "engines": { "node": ">=12" }, @@ -4150,8 +4152,9 @@ }, "node_modules/@isaacs/cliui/node_modules/strip-ansi": { "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dev": true, - "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" }, @@ -4772,8 +4775,9 @@ }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", "dev": true, - "license": "MIT", "optional": true, "engines": { "node": ">=14" @@ -7360,42 +7364,6 @@ "undici-types": "~5.26.4" } }, - "node_modules/@storybook/core-common/node_modules/foreground-child": { - "version": "3.1.1", - "dev": true, - "license": "ISC", - "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@storybook/core-common/node_modules/glob": { - "version": "10.3.10", - "dev": true, - "license": "ISC", - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^2.3.5", - "minimatch": "^9.0.1", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", - "path-scurry": "^1.10.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/@storybook/core-common/node_modules/resolve-from": { "version": "5.0.0", "dev": true, @@ -7404,17 +7372,6 @@ "node": ">=8" } }, - "node_modules/@storybook/core-common/node_modules/signal-exit": { - "version": "4.1.0", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/@storybook/core-events": { "version": "7.6.17", "resolved": "https://registry.npmjs.org/@storybook/core-events/-/core-events-7.6.17.tgz", @@ -16535,6 +16492,34 @@ "dev": true, "license": "MIT" }, + "node_modules/foreground-child": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", + "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/foreground-child/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/fork-ts-checker-webpack-plugin": { "version": "6.5.3", "dev": true, @@ -17022,6 +17007,26 @@ "dev": true, "license": "ISC" }, + "node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/glob-parent": { "version": "6.0.2", "dev": true, @@ -17038,6 +17043,15 @@ "dev": true, "license": "BSD-2-Clause" }, + "node_modules/glob/node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, "node_modules/global-dirs": { "version": "3.0.1", "dev": true, @@ -19039,15 +19053,13 @@ } }, "node_modules/jackspeak": { - "version": "2.3.6", + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", "dev": true, - "license": "BlueOak-1.0.0", "dependencies": { "@isaacs/cliui": "^8.0.2" }, - "engines": { - "node": ">=14" - }, "funding": { "url": "https://github.com/sponsors/isaacs" }, @@ -24484,9 +24496,9 @@ } }, "node_modules/package-json-from-dist": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz", - "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", "dev": true }, "node_modules/pad": { @@ -28847,8 +28859,9 @@ "node_modules/string-width-cjs": { "name": "string-width", "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, - "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -28860,8 +28873,9 @@ }, "node_modules/string-width-cjs/node_modules/emoji-regex": { "version": "8.0.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true }, "node_modules/string-width/node_modules/ansi-regex": { "version": "6.0.1", @@ -28970,8 +28984,9 @@ "node_modules/strip-ansi-cjs": { "name": "strip-ansi", "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, - "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" }, @@ -29166,53 +29181,6 @@ "node": ">= 6" } }, - "node_modules/sucrase/node_modules/foreground-child": { - "version": "3.1.1", - "dev": true, - "license": "ISC", - "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/sucrase/node_modules/glob": { - "version": "10.3.10", - "dev": true, - "license": "ISC", - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^2.3.5", - "minimatch": "^9.0.1", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", - "path-scurry": "^1.10.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/sucrase/node_modules/signal-exit": { - "version": "4.1.0", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/superagent": { "version": "7.1.5", "dev": true, @@ -31193,6 +31161,46 @@ "dev": true, "license": "Apache-2.0" }, + "node_modules/ts-json-schema-generator": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/ts-json-schema-generator/-/ts-json-schema-generator-2.3.0.tgz", + "integrity": "sha512-t4lBQAwZc0sOJq9LJt3NgbznIcslVnm0JeEMFq8qIRklpMRY8jlYD0YmnRWbqBKANxkby91P1XanSSlSOFpUmg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.15", + "commander": "^12.0.0", + "glob": "^10.3.12", + "json5": "^2.2.3", + "normalize-path": "^3.0.0", + "safe-stable-stringify": "^2.4.3", + "tslib": "^2.6.2", + "typescript": "^5.4.5" + }, + "bin": { + "ts-json-schema-generator": "bin/ts-json-schema-generator.js" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/ts-json-schema-generator/node_modules/commander": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", + "dev": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/ts-json-schema-generator/node_modules/safe-stable-stringify": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", + "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, "node_modules/ts-toolbelt": { "version": "9.6.0", "resolved": "https://registry.npmjs.org/ts-toolbelt/-/ts-toolbelt-9.6.0.tgz", @@ -34172,8 +34180,9 @@ "node_modules/wrap-ansi-cjs": { "name": "wrap-ansi", "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, - "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -34188,13 +34197,15 @@ }, "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { "version": "8.0.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true }, "node_modules/wrap-ansi-cjs/node_modules/string-width": { "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, - "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -35488,15 +35499,6 @@ "node": ">= 16" } }, - "web-common/node_modules/commander": { - "version": "12.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", - "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", - "dev": true, - "engines": { - "node": ">=18" - } - }, "web-common/node_modules/deep-eql": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", @@ -35512,22 +35514,6 @@ "dev": true, "license": "(MPL-2.0 OR Apache-2.0)" }, - "web-common/node_modules/foreground-child": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", - "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "web-common/node_modules/fs-extra": { "version": "10.1.0", "dev": true, @@ -35541,41 +35527,6 @@ "node": ">=12" } }, - "web-common/node_modules/glob": { - "version": "10.4.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", - "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", - "dev": true, - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^1.11.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "web-common/node_modules/jackspeak": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", - "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", - "dev": true, - "dependencies": { - "@isaacs/cliui": "^8.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" - } - }, "web-common/node_modules/json-schema-traverse": { "version": "1.0.0", "dev": true, @@ -35609,15 +35560,6 @@ "node": ">= 18" } }, - "web-common/node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", - "dev": true, - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, "web-common/node_modules/orval": { "version": "6.12.0", "dev": true, @@ -35657,27 +35599,6 @@ "node": ">= 14.16" } }, - "web-common/node_modules/safe-stable-stringify": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", - "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "web-common/node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "web-common/node_modules/svelte-preprocess": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/svelte-preprocess/-/svelte-preprocess-6.0.3.tgz", @@ -35768,28 +35689,6 @@ "node": ">=14.0.0" } }, - "web-common/node_modules/ts-json-schema-generator": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/ts-json-schema-generator/-/ts-json-schema-generator-2.3.0.tgz", - "integrity": "sha512-t4lBQAwZc0sOJq9LJt3NgbznIcslVnm0JeEMFq8qIRklpMRY8jlYD0YmnRWbqBKANxkby91P1XanSSlSOFpUmg==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.15", - "commander": "^12.0.0", - "glob": "^10.3.12", - "json5": "^2.2.3", - "normalize-path": "^3.0.0", - "safe-stable-stringify": "^2.4.3", - "tslib": "^2.6.2", - "typescript": "^5.4.5" - }, - "bin": { - "ts-json-schema-generator": "bin/ts-json-schema-generator.js" - }, - "engines": { - "node": ">=18.0.0" - } - }, "web-common/node_modules/vega-expression": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/vega-expression/-/vega-expression-5.1.1.tgz", diff --git a/proto/gen/rill/runtime/v1/queries.pb.go b/proto/gen/rill/runtime/v1/queries.pb.go index d8961601eeb..f42f790fe95 100644 --- a/proto/gen/rill/runtime/v1/queries.pb.go +++ b/proto/gen/rill/runtime/v1/queries.pb.go @@ -4348,7 +4348,7 @@ type ResolveComponentRequest struct { InstanceId string `protobuf:"bytes,1,opt,name=instance_id,json=instanceId,proto3" json:"instance_id,omitempty"` // Component name Component string `protobuf:"bytes,2,opt,name=component,proto3" json:"component,omitempty"` - // Optional args to pass to the data resolver and for resolving templating in the renderer properties + // Optional args for resolving templating in the renderer properties Args *structpb.Struct `protobuf:"bytes,3,opt,name=args,proto3" json:"args,omitempty"` } @@ -4413,12 +4413,8 @@ type ResolveComponentResponse struct { // Show property with templating resolved for the provided args. // If it resolves to false, the other fields are not set. Show bool `protobuf:"varint,1,opt,name=show,proto3" json:"show,omitempty"` - // Schema of the resolved component data - Schema *StructType `protobuf:"bytes,2,opt,name=schema,proto3" json:"schema,omitempty"` - // Resolved component data - Data []*structpb.Struct `protobuf:"bytes,3,rep,name=data,proto3" json:"data,omitempty"` // Renderer properties with templating resolved for the provided args - RendererProperties *structpb.Struct `protobuf:"bytes,4,opt,name=renderer_properties,json=rendererProperties,proto3" json:"renderer_properties,omitempty"` + RendererProperties *structpb.Struct `protobuf:"bytes,2,opt,name=renderer_properties,json=rendererProperties,proto3" json:"renderer_properties,omitempty"` } func (x *ResolveComponentResponse) Reset() { @@ -4460,20 +4456,6 @@ func (x *ResolveComponentResponse) GetShow() bool { return false } -func (x *ResolveComponentResponse) GetSchema() *StructType { - if x != nil { - return x.Schema - } - return nil -} - -func (x *ResolveComponentResponse) GetData() []*structpb.Struct { - if x != nil { - return x.Data - } - return nil -} - func (x *ResolveComponentResponse) GetRendererProperties() *structpb.Struct { if x != nil { return x.RendererProperties @@ -8599,22 +8581,183 @@ var file_rill_runtime_v1_queries_proto_rawDesc = []byte{ 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x12, 0x2b, 0x0a, 0x04, 0x61, 0x72, 0x67, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, - 0x04, 0x61, 0x72, 0x67, 0x73, 0x22, 0xda, 0x01, 0x0a, 0x18, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, - 0x65, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x68, 0x6f, 0x77, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x04, 0x73, 0x68, 0x6f, 0x77, 0x12, 0x33, 0x0a, 0x06, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, - 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x54, - 0x79, 0x70, 0x65, 0x52, 0x06, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x2b, 0x0a, 0x04, 0x64, - 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, - 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, - 0x63, 0x74, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x48, 0x0a, 0x13, 0x72, 0x65, 0x6e, 0x64, - 0x65, 0x72, 0x65, 0x72, 0x5f, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x12, - 0x72, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, - 0x65, 0x73, 0x22, 0x8f, 0x02, 0x0a, 0x1b, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x52, 0x6f, 0x6c, - 0x6c, 0x75, 0x70, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x04, 0x61, 0x72, 0x67, 0x73, 0x22, 0x78, 0x0a, 0x18, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, + 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x68, 0x6f, 0x77, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x04, 0x73, 0x68, 0x6f, 0x77, 0x12, 0x48, 0x0a, 0x13, 0x72, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x65, + 0x72, 0x5f, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x12, 0x72, 0x65, 0x6e, + 0x64, 0x65, 0x72, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x22, + 0x8f, 0x02, 0x0a, 0x1b, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x52, 0x6f, 0x6c, 0x6c, 0x75, 0x70, + 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, + 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x1a, + 0x0a, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x64, 0x61, + 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x18, 0x07, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, 0x63, 0x68, + 0x65, 0x6d, 0x61, 0x12, 0x26, 0x0a, 0x0a, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, + 0x52, 0x09, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x28, 0x0a, 0x0b, 0x63, + 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x0a, 0x63, 0x6f, 0x6c, 0x75, 0x6d, + 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, + 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, + 0x79, 0x22, 0xb6, 0x01, 0x0a, 0x1c, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x52, 0x6f, 0x6c, 0x6c, + 0x75, 0x70, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x30, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x05, 0x73, + 0x74, 0x61, 0x72, 0x74, 0x12, 0x2c, 0x0a, 0x03, 0x65, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x03, 0x65, + 0x6e, 0x64, 0x12, 0x36, 0x0a, 0x08, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, + 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x47, 0x72, 0x61, 0x69, 0x6e, + 0x52, 0x08, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x22, 0xa5, 0x02, 0x0a, 0x11, 0x43, + 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x6f, 0x70, 0x4b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, + 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x07, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, + 0x1a, 0x0a, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x64, + 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x18, 0x09, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, 0x63, + 0x68, 0x65, 0x6d, 0x61, 0x12, 0x26, 0x0a, 0x0a, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, + 0x01, 0x52, 0x09, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x28, 0x0a, 0x0b, + 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x0a, 0x63, 0x6f, 0x6c, 0x75, + 0x6d, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x67, 0x67, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x03, 0x61, 0x67, 0x67, 0x12, 0x0c, 0x0a, 0x01, 0x6b, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x05, 0x52, 0x01, 0x6b, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, + 0x74, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, + 0x74, 0x79, 0x22, 0x6a, 0x0a, 0x12, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x6f, 0x70, 0x4b, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x54, 0x0a, 0x13, 0x63, 0x61, 0x74, 0x65, + 0x67, 0x6f, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x5f, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, + 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x69, + 0x63, 0x61, 0x6c, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x52, 0x12, 0x63, 0x61, 0x74, 0x65, + 0x67, 0x6f, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x22, 0x6e, + 0x0a, 0x12, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x53, 0x75, 0x6d, + 0x6d, 0x61, 0x72, 0x79, 0x12, 0x2c, 0x0a, 0x05, 0x74, 0x6f, 0x70, 0x5f, 0x6b, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, + 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x6f, 0x70, 0x4b, 0x48, 0x00, 0x52, 0x04, 0x74, 0x6f, + 0x70, 0x4b, 0x12, 0x22, 0x0a, 0x0b, 0x63, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, + 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x48, 0x00, 0x52, 0x0b, 0x63, 0x61, 0x72, 0x64, 0x69, + 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x42, 0x06, 0x0a, 0x04, 0x63, 0x61, 0x73, 0x65, 0x22, 0x8a, + 0x01, 0x0a, 0x04, 0x54, 0x6f, 0x70, 0x4b, 0x12, 0x35, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, + 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, + 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x6f, 0x70, 0x4b, 0x2e, + 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x1a, 0x4b, + 0x0a, 0x05, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x2c, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x01, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x8a, 0x02, 0x0a, 0x16, + 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x4e, 0x75, 0x6c, 0x6c, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, + 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x73, + 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, + 0x63, 0x74, 0x6f, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x6e, + 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, + 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, + 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x73, 0x63, + 0x68, 0x65, 0x6d, 0x61, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x64, 0x61, 0x74, 0x61, + 0x62, 0x61, 0x73, 0x65, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x26, 0x0a, 0x0a, 0x74, 0x61, + 0x62, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, + 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x09, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x4e, 0x61, + 0x6d, 0x65, 0x12, 0x28, 0x0a, 0x0b, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, + 0x52, 0x0a, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, + 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, + 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x22, 0x2f, 0x0a, 0x17, 0x43, 0x6f, 0x6c, 0x75, + 0x6d, 0x6e, 0x4e, 0x75, 0x6c, 0x6c, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x01, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x96, 0x02, 0x0a, 0x22, 0x43, 0x6f, + 0x6c, 0x75, 0x6d, 0x6e, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x76, 0x65, 0x53, + 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, + 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, + 0x1a, 0x0a, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x64, + 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x18, 0x07, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, 0x63, + 0x68, 0x65, 0x6d, 0x61, 0x12, 0x26, 0x0a, 0x0a, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, + 0x01, 0x52, 0x09, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x28, 0x0a, 0x0b, + 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x0a, 0x63, 0x6f, 0x6c, 0x75, + 0x6d, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, + 0x74, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, + 0x74, 0x79, 0x22, 0x6f, 0x0a, 0x23, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x44, 0x65, 0x73, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x69, 0x76, 0x65, 0x53, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, + 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x48, 0x0a, 0x0f, 0x6e, 0x75, 0x6d, + 0x65, 0x72, 0x69, 0x63, 0x5f, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, + 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x53, 0x75, 0x6d, 0x6d, + 0x61, 0x72, 0x79, 0x52, 0x0e, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x53, 0x75, 0x6d, 0x6d, + 0x61, 0x72, 0x79, 0x22, 0x9b, 0x02, 0x0a, 0x0e, 0x4e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x53, + 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x12, 0x5d, 0x0a, 0x16, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, + 0x63, 0x5f, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x5f, 0x62, 0x69, 0x6e, 0x73, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, + 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, + 0x48, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x42, 0x69, 0x6e, 0x73, 0x48, 0x00, 0x52, + 0x14, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, + 0x6d, 0x42, 0x69, 0x6e, 0x73, 0x12, 0x53, 0x0a, 0x12, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, + 0x5f, 0x73, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x22, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, + 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x53, 0x74, 0x61, 0x74, 0x69, + 0x73, 0x74, 0x69, 0x63, 0x73, 0x48, 0x00, 0x52, 0x11, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, + 0x53, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x12, 0x4d, 0x0a, 0x10, 0x6e, 0x75, + 0x6d, 0x65, 0x72, 0x69, 0x63, 0x5f, 0x6f, 0x75, 0x74, 0x6c, 0x69, 0x65, 0x72, 0x73, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, + 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x4f, 0x75, + 0x74, 0x6c, 0x69, 0x65, 0x72, 0x73, 0x48, 0x00, 0x52, 0x0f, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, + 0x63, 0x4f, 0x75, 0x74, 0x6c, 0x69, 0x65, 0x72, 0x73, 0x42, 0x06, 0x0a, 0x04, 0x63, 0x61, 0x73, + 0x65, 0x22, 0xcc, 0x01, 0x0a, 0x14, 0x4e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x48, 0x69, 0x73, + 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x42, 0x69, 0x6e, 0x73, 0x12, 0x3d, 0x0a, 0x04, 0x62, 0x69, + 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, + 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x75, 0x6d, 0x65, 0x72, + 0x69, 0x63, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x42, 0x69, 0x6e, 0x73, 0x2e, + 0x42, 0x69, 0x6e, 0x52, 0x04, 0x62, 0x69, 0x6e, 0x73, 0x1a, 0x75, 0x0a, 0x03, 0x42, 0x69, 0x6e, + 0x12, 0x16, 0x0a, 0x06, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x06, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x6c, 0x6f, 0x77, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x01, 0x52, 0x03, 0x6c, 0x6f, 0x77, 0x12, 0x1a, 0x0a, 0x08, 0x6d, 0x69, + 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x01, 0x52, 0x08, 0x6d, 0x69, + 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x69, 0x67, 0x68, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x01, 0x52, 0x04, 0x68, 0x69, 0x67, 0x68, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, + 0x75, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x01, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, + 0x22, 0x91, 0x01, 0x0a, 0x11, 0x4e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x53, 0x74, 0x61, 0x74, + 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x69, 0x6e, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x01, 0x52, 0x03, 0x6d, 0x69, 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x61, 0x78, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x01, 0x52, 0x03, 0x6d, 0x61, 0x78, 0x12, 0x12, 0x0a, 0x04, 0x6d, 0x65, + 0x61, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x01, 0x52, 0x04, 0x6d, 0x65, 0x61, 0x6e, 0x12, 0x10, + 0x0a, 0x03, 0x71, 0x32, 0x35, 0x18, 0x04, 0x20, 0x01, 0x28, 0x01, 0x52, 0x03, 0x71, 0x32, 0x35, + 0x12, 0x10, 0x0a, 0x03, 0x71, 0x35, 0x30, 0x18, 0x05, 0x20, 0x01, 0x28, 0x01, 0x52, 0x03, 0x71, + 0x35, 0x30, 0x12, 0x10, 0x0a, 0x03, 0x71, 0x37, 0x35, 0x18, 0x06, 0x20, 0x01, 0x28, 0x01, 0x52, + 0x03, 0x71, 0x37, 0x35, 0x12, 0x0e, 0x0a, 0x02, 0x73, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x01, + 0x52, 0x02, 0x73, 0x64, 0x22, 0xd0, 0x01, 0x0a, 0x0f, 0x4e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, + 0x4f, 0x75, 0x74, 0x6c, 0x69, 0x65, 0x72, 0x73, 0x12, 0x44, 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x6c, + 0x69, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x72, 0x69, 0x6c, + 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x75, 0x6d, + 0x65, 0x72, 0x69, 0x63, 0x4f, 0x75, 0x74, 0x6c, 0x69, 0x65, 0x72, 0x73, 0x2e, 0x4f, 0x75, 0x74, + 0x6c, 0x69, 0x65, 0x72, 0x52, 0x08, 0x6f, 0x75, 0x74, 0x6c, 0x69, 0x65, 0x72, 0x73, 0x1a, 0x77, + 0x0a, 0x07, 0x4f, 0x75, 0x74, 0x6c, 0x69, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x62, 0x75, 0x63, + 0x6b, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x62, 0x75, 0x63, 0x6b, 0x65, + 0x74, 0x12, 0x10, 0x0a, 0x03, 0x6c, 0x6f, 0x77, 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x52, 0x03, + 0x6c, 0x6f, 0x77, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x69, 0x67, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x01, 0x52, 0x04, 0x68, 0x69, 0x67, 0x68, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x72, 0x65, 0x73, 0x65, + 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, + 0x74, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x8a, 0x02, 0x0a, 0x16, 0x43, 0x6f, 0x6c, 0x75, + 0x6d, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x47, 0x72, 0x61, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, @@ -8630,158 +8773,42 @@ var file_rill_runtime_v1_queries_proto_rawDesc = []byte{ 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x0a, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x72, 0x69, 0x6f, - 0x72, 0x69, 0x74, 0x79, 0x22, 0xb6, 0x01, 0x0a, 0x1c, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x52, - 0x6f, 0x6c, 0x6c, 0x75, 0x70, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x30, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, - 0x52, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x12, 0x2c, 0x0a, 0x03, 0x65, 0x6e, 0x64, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, - 0x52, 0x03, 0x65, 0x6e, 0x64, 0x12, 0x36, 0x0a, 0x08, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, - 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, - 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x47, 0x72, - 0x61, 0x69, 0x6e, 0x52, 0x08, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x22, 0xa5, 0x02, - 0x0a, 0x11, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x6f, 0x70, 0x4b, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, - 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, - 0x63, 0x65, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, - 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, - 0x6f, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x18, 0x08, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x12, 0x27, - 0x0a, 0x0f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, - 0x61, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, - 0x65, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x26, 0x0a, 0x0a, 0x74, 0x61, 0x62, 0x6c, 0x65, - 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, - 0x72, 0x02, 0x10, 0x01, 0x52, 0x09, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, - 0x28, 0x0a, 0x0b, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x0a, 0x63, - 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x67, 0x67, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x61, 0x67, 0x67, 0x12, 0x0c, 0x0a, 0x01, 0x6b, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x01, 0x6b, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x69, - 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x72, 0x69, - 0x6f, 0x72, 0x69, 0x74, 0x79, 0x22, 0x6a, 0x0a, 0x12, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, - 0x6f, 0x70, 0x4b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x54, 0x0a, 0x13, 0x63, - 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x5f, 0x73, 0x75, 0x6d, 0x6d, 0x61, - 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, - 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x61, 0x74, 0x65, 0x67, - 0x6f, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x52, 0x12, 0x63, - 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, - 0x79, 0x22, 0x6e, 0x0a, 0x12, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x69, 0x63, 0x61, 0x6c, - 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x12, 0x2c, 0x0a, 0x05, 0x74, 0x6f, 0x70, 0x5f, 0x6b, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, - 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x6f, 0x70, 0x4b, 0x48, 0x00, 0x52, - 0x04, 0x74, 0x6f, 0x70, 0x4b, 0x12, 0x22, 0x0a, 0x0b, 0x63, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x61, - 0x6c, 0x69, 0x74, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x48, 0x00, 0x52, 0x0b, 0x63, 0x61, - 0x72, 0x64, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x42, 0x06, 0x0a, 0x04, 0x63, 0x61, 0x73, - 0x65, 0x22, 0x8a, 0x01, 0x0a, 0x04, 0x54, 0x6f, 0x70, 0x4b, 0x12, 0x35, 0x0a, 0x07, 0x65, 0x6e, - 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x72, 0x69, - 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x6f, - 0x70, 0x4b, 0x2e, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, - 0x73, 0x1a, 0x4b, 0x0a, 0x05, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x2c, 0x0a, 0x05, 0x76, 0x61, - 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, - 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x56, 0x61, 0x6c, 0x75, - 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, - 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x8a, - 0x02, 0x0a, 0x16, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x4e, 0x75, 0x6c, 0x6c, 0x43, 0x6f, 0x75, - 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x73, - 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, - 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6f, - 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, - 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x61, 0x74, 0x61, - 0x62, 0x61, 0x73, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x61, 0x74, 0x61, - 0x62, 0x61, 0x73, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, - 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x64, - 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x26, 0x0a, - 0x0a, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x09, 0x74, 0x61, 0x62, 0x6c, - 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x28, 0x0a, 0x0b, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x5f, - 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, - 0x02, 0x10, 0x01, 0x52, 0x0a, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x12, - 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x05, 0x52, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x22, 0x2f, 0x0a, 0x17, 0x43, - 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x4e, 0x75, 0x6c, 0x6c, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x01, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x96, 0x02, 0x0a, - 0x22, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, - 0x76, 0x65, 0x53, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, - 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, - 0x63, 0x65, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, - 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, - 0x6f, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x18, 0x06, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x12, 0x27, - 0x0a, 0x0f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, - 0x61, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, - 0x65, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x26, 0x0a, 0x0a, 0x74, 0x61, 0x62, 0x6c, 0x65, - 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, - 0x72, 0x02, 0x10, 0x01, 0x52, 0x09, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, - 0x28, 0x0a, 0x0b, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x0a, 0x63, - 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x69, - 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x72, 0x69, - 0x6f, 0x72, 0x69, 0x74, 0x79, 0x22, 0x6f, 0x0a, 0x23, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x44, - 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x76, 0x65, 0x53, 0x74, 0x61, 0x74, 0x69, 0x73, - 0x74, 0x69, 0x63, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x48, 0x0a, 0x0f, - 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x5f, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, - 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x53, - 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x52, 0x0e, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x53, - 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x22, 0x9b, 0x02, 0x0a, 0x0e, 0x4e, 0x75, 0x6d, 0x65, 0x72, - 0x69, 0x63, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x12, 0x5d, 0x0a, 0x16, 0x6e, 0x75, 0x6d, - 0x65, 0x72, 0x69, 0x63, 0x5f, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x5f, 0x62, - 0x69, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x72, 0x69, 0x6c, 0x6c, - 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x75, 0x6d, 0x65, - 0x72, 0x69, 0x63, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x42, 0x69, 0x6e, 0x73, - 0x48, 0x00, 0x52, 0x14, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x48, 0x69, 0x73, 0x74, 0x6f, - 0x67, 0x72, 0x61, 0x6d, 0x42, 0x69, 0x6e, 0x73, 0x12, 0x53, 0x0a, 0x12, 0x6e, 0x75, 0x6d, 0x65, - 0x72, 0x69, 0x63, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, - 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x53, 0x74, - 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x48, 0x00, 0x52, 0x11, 0x6e, 0x75, 0x6d, 0x65, - 0x72, 0x69, 0x63, 0x53, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x12, 0x4d, 0x0a, - 0x10, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x5f, 0x6f, 0x75, 0x74, 0x6c, 0x69, 0x65, 0x72, - 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, - 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x75, 0x6d, 0x65, 0x72, 0x69, - 0x63, 0x4f, 0x75, 0x74, 0x6c, 0x69, 0x65, 0x72, 0x73, 0x48, 0x00, 0x52, 0x0f, 0x6e, 0x75, 0x6d, - 0x65, 0x72, 0x69, 0x63, 0x4f, 0x75, 0x74, 0x6c, 0x69, 0x65, 0x72, 0x73, 0x42, 0x06, 0x0a, 0x04, - 0x63, 0x61, 0x73, 0x65, 0x22, 0xcc, 0x01, 0x0a, 0x14, 0x4e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, - 0x48, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x42, 0x69, 0x6e, 0x73, 0x12, 0x3d, 0x0a, - 0x04, 0x62, 0x69, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x72, 0x69, - 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x75, - 0x6d, 0x65, 0x72, 0x69, 0x63, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x42, 0x69, - 0x6e, 0x73, 0x2e, 0x42, 0x69, 0x6e, 0x52, 0x04, 0x62, 0x69, 0x6e, 0x73, 0x1a, 0x75, 0x0a, 0x03, - 0x42, 0x69, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x05, 0x52, 0x06, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x6c, - 0x6f, 0x77, 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x52, 0x03, 0x6c, 0x6f, 0x77, 0x12, 0x1a, 0x0a, - 0x08, 0x6d, 0x69, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x01, 0x52, - 0x08, 0x6d, 0x69, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x69, 0x67, - 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x01, 0x52, 0x04, 0x68, 0x69, 0x67, 0x68, 0x12, 0x14, 0x0a, - 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x01, 0x52, 0x05, 0x63, 0x6f, - 0x75, 0x6e, 0x74, 0x22, 0x91, 0x01, 0x0a, 0x11, 0x4e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x53, - 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x69, 0x6e, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x01, 0x52, 0x03, 0x6d, 0x69, 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x6d, - 0x61, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x52, 0x03, 0x6d, 0x61, 0x78, 0x12, 0x12, 0x0a, - 0x04, 0x6d, 0x65, 0x61, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x01, 0x52, 0x04, 0x6d, 0x65, 0x61, - 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x71, 0x32, 0x35, 0x18, 0x04, 0x20, 0x01, 0x28, 0x01, 0x52, 0x03, - 0x71, 0x32, 0x35, 0x12, 0x10, 0x0a, 0x03, 0x71, 0x35, 0x30, 0x18, 0x05, 0x20, 0x01, 0x28, 0x01, - 0x52, 0x03, 0x71, 0x35, 0x30, 0x12, 0x10, 0x0a, 0x03, 0x71, 0x37, 0x35, 0x18, 0x06, 0x20, 0x01, - 0x28, 0x01, 0x52, 0x03, 0x71, 0x37, 0x35, 0x12, 0x0e, 0x0a, 0x02, 0x73, 0x64, 0x18, 0x07, 0x20, - 0x01, 0x28, 0x01, 0x52, 0x02, 0x73, 0x64, 0x22, 0xd0, 0x01, 0x0a, 0x0f, 0x4e, 0x75, 0x6d, 0x65, - 0x72, 0x69, 0x63, 0x4f, 0x75, 0x74, 0x6c, 0x69, 0x65, 0x72, 0x73, 0x12, 0x44, 0x0a, 0x08, 0x6f, - 0x75, 0x74, 0x6c, 0x69, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28, 0x2e, - 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, - 0x4e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x4f, 0x75, 0x74, 0x6c, 0x69, 0x65, 0x72, 0x73, 0x2e, - 0x4f, 0x75, 0x74, 0x6c, 0x69, 0x65, 0x72, 0x52, 0x08, 0x6f, 0x75, 0x74, 0x6c, 0x69, 0x65, 0x72, - 0x73, 0x1a, 0x77, 0x0a, 0x07, 0x4f, 0x75, 0x74, 0x6c, 0x69, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, - 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x62, 0x75, - 0x63, 0x6b, 0x65, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x6c, 0x6f, 0x77, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x01, 0x52, 0x03, 0x6c, 0x6f, 0x77, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x69, 0x67, 0x68, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x01, 0x52, 0x04, 0x68, 0x69, 0x67, 0x68, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x72, - 0x65, 0x73, 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x70, 0x72, 0x65, - 0x73, 0x65, 0x6e, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x05, 0x20, - 0x01, 0x28, 0x05, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x8a, 0x02, 0x0a, 0x16, 0x43, - 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x47, 0x72, 0x61, 0x69, 0x6e, 0x52, 0x65, + 0x72, 0x69, 0x74, 0x79, 0x22, 0x54, 0x0a, 0x17, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x69, + 0x6d, 0x65, 0x47, 0x72, 0x61, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x39, 0x0a, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x67, 0x72, 0x61, 0x69, 0x6e, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, + 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x47, 0x72, 0x61, 0x69, 0x6e, 0x52, + 0x09, 0x74, 0x69, 0x6d, 0x65, 0x47, 0x72, 0x61, 0x69, 0x6e, 0x22, 0xde, 0x02, 0x0a, 0x1d, 0x43, + 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x4e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x48, 0x69, 0x73, 0x74, + 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, + 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x12, 0x1c, 0x0a, + 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x64, + 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, + 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x64, 0x61, 0x74, 0x61, 0x62, + 0x61, 0x73, 0x65, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, + 0x12, 0x26, 0x0a, 0x0a, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x09, 0x74, + 0x61, 0x62, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x28, 0x0a, 0x0b, 0x63, 0x6f, 0x6c, 0x75, + 0x6d, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, + 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x0a, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x4e, 0x61, + 0x6d, 0x65, 0x12, 0x4b, 0x0a, 0x10, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x5f, + 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x20, 0x2e, 0x72, + 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x48, + 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x52, 0x0f, + 0x68, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, + 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x05, 0x52, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x22, 0x6a, 0x0a, 0x1e, 0x43, + 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x4e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x48, 0x69, 0x73, 0x74, + 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x48, 0x0a, + 0x0f, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x5f, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, + 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, + 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x52, 0x0e, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, + 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x22, 0x8d, 0x02, 0x0a, 0x19, 0x43, 0x6f, 0x6c, 0x75, + 0x6d, 0x6e, 0x52, 0x75, 0x67, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, @@ -8797,661 +8824,610 @@ var file_rill_runtime_v1_queries_proto_rawDesc = []byte{ 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x0a, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, - 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x22, 0x54, 0x0a, 0x17, 0x43, 0x6f, 0x6c, 0x75, 0x6d, - 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x47, 0x72, 0x61, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x39, 0x0a, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x67, 0x72, 0x61, 0x69, 0x6e, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, - 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x47, 0x72, 0x61, - 0x69, 0x6e, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x47, 0x72, 0x61, 0x69, 0x6e, 0x22, 0xde, 0x02, - 0x0a, 0x1d, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x4e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x48, - 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x22, 0x66, 0x0a, 0x1a, 0x43, 0x6f, 0x6c, 0x75, 0x6d, + 0x6e, 0x52, 0x75, 0x67, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x48, 0x0a, 0x0f, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, + 0x5f, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, + 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, + 0x2e, 0x4e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x52, + 0x0e, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x22, + 0x8a, 0x02, 0x0a, 0x16, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x61, + 0x6e, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, + 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x63, + 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, + 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x61, 0x74, + 0x61, 0x62, 0x61, 0x73, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x61, 0x74, + 0x61, 0x62, 0x61, 0x73, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, + 0x65, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, + 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x26, + 0x0a, 0x0a, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x09, 0x74, 0x61, 0x62, + 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x28, 0x0a, 0x0b, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, + 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, + 0x72, 0x02, 0x10, 0x01, 0x52, 0x0a, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x4e, 0x61, 0x6d, 0x65, + 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x05, 0x52, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x22, 0x6a, 0x0a, 0x17, + 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4f, 0x0a, 0x12, 0x74, 0x69, 0x6d, 0x65, 0x5f, + 0x72, 0x61, 0x6e, 0x67, 0x65, 0x5f, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, + 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x53, + 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x52, 0x10, 0x74, 0x69, 0x6d, 0x65, 0x52, 0x61, 0x6e, 0x67, + 0x65, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x22, 0x86, 0x02, 0x0a, 0x10, 0x54, 0x69, 0x6d, + 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x12, 0x2c, 0x0a, + 0x03, 0x6d, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, + 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x03, 0x6d, 0x69, 0x6e, 0x12, 0x2c, 0x0a, 0x03, 0x6d, + 0x61, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, + 0x74, 0x61, 0x6d, 0x70, 0x52, 0x03, 0x6d, 0x61, 0x78, 0x12, 0x46, 0x0a, 0x08, 0x69, 0x6e, 0x74, + 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x72, 0x69, + 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, + 0x6d, 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x2e, 0x49, + 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x52, 0x08, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, + 0x6c, 0x1a, 0x4e, 0x0a, 0x08, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x16, 0x0a, + 0x06, 0x6d, 0x6f, 0x6e, 0x74, 0x68, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x6d, + 0x6f, 0x6e, 0x74, 0x68, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x79, 0x73, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x05, 0x52, 0x04, 0x64, 0x61, 0x79, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x69, 0x63, + 0x72, 0x6f, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x6d, 0x69, 0x63, 0x72, 0x6f, + 0x73, 0x22, 0x8c, 0x02, 0x0a, 0x18, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x43, 0x61, 0x72, 0x64, + 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, + 0x0a, 0x0b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x12, + 0x1c, 0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x1a, 0x0a, + 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x64, 0x61, 0x74, + 0x61, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x18, 0x07, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, 0x63, 0x68, 0x65, + 0x6d, 0x61, 0x12, 0x26, 0x0a, 0x0a, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, + 0x09, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x28, 0x0a, 0x0b, 0x63, 0x6f, + 0x6c, 0x75, 0x6d, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, + 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x0a, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, + 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, + 0x22, 0x71, 0x0a, 0x19, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x43, 0x61, 0x72, 0x64, 0x69, 0x6e, + 0x61, 0x6c, 0x69, 0x74, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x54, 0x0a, + 0x13, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x5f, 0x73, 0x75, 0x6d, + 0x6d, 0x61, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x72, 0x69, 0x6c, + 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x61, 0x74, + 0x65, 0x67, 0x6f, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x52, + 0x12, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x53, 0x75, 0x6d, 0x6d, + 0x61, 0x72, 0x79, 0x22, 0x8c, 0x05, 0x0a, 0x17, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x69, + 0x6d, 0x65, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, - 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x06, 0x20, + 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x1a, - 0x0a, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, + 0x0a, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x64, 0x61, - 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x18, 0x08, 0x20, + 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x26, 0x0a, 0x0a, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, - 0x52, 0x09, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x28, 0x0a, 0x0b, 0x63, - 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, - 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x0a, 0x63, 0x6f, 0x6c, 0x75, 0x6d, - 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x4b, 0x0a, 0x10, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, - 0x61, 0x6d, 0x5f, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, - 0x20, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, - 0x31, 0x2e, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x4d, 0x65, 0x74, 0x68, 0x6f, - 0x64, 0x52, 0x0f, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x4d, 0x65, 0x74, 0x68, - 0x6f, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x05, - 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x22, 0x6a, - 0x0a, 0x1e, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x4e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x48, - 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x48, 0x0a, 0x0f, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x5f, 0x73, 0x75, 0x6d, 0x6d, - 0x61, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x72, 0x69, 0x6c, 0x6c, - 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x75, 0x6d, 0x65, - 0x72, 0x69, 0x63, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x52, 0x0e, 0x6e, 0x75, 0x6d, 0x65, - 0x72, 0x69, 0x63, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x22, 0x8d, 0x02, 0x0a, 0x19, 0x43, - 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x52, 0x75, 0x67, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, - 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x73, 0x74, - 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, - 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6f, 0x6e, - 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6f, - 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, - 0x61, 0x73, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, - 0x61, 0x73, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x5f, - 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x64, 0x61, - 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x26, 0x0a, 0x0a, - 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x09, 0x74, 0x61, 0x62, 0x6c, 0x65, - 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x28, 0x0a, 0x0b, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x5f, 0x6e, - 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, - 0x10, 0x01, 0x52, 0x0a, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1a, - 0x0a, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, - 0x52, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x22, 0x66, 0x0a, 0x1a, 0x43, 0x6f, - 0x6c, 0x75, 0x6d, 0x6e, 0x52, 0x75, 0x67, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x48, 0x0a, 0x0f, 0x6e, 0x75, 0x6d, 0x65, - 0x72, 0x69, 0x63, 0x5f, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x1f, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, - 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x53, 0x75, 0x6d, 0x6d, 0x61, - 0x72, 0x79, 0x52, 0x0e, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x53, 0x75, 0x6d, 0x6d, 0x61, - 0x72, 0x79, 0x22, 0x8a, 0x02, 0x0a, 0x16, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x69, 0x6d, - 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, - 0x0b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x12, 0x1c, - 0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x1a, 0x0a, 0x08, - 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, - 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x64, 0x61, 0x74, 0x61, - 0x62, 0x61, 0x73, 0x65, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x18, 0x07, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, 0x63, 0x68, 0x65, 0x6d, - 0x61, 0x12, 0x26, 0x0a, 0x0a, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x09, - 0x74, 0x61, 0x62, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x28, 0x0a, 0x0b, 0x63, 0x6f, 0x6c, - 0x75, 0x6d, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, - 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x0a, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x4e, - 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x22, - 0x6a, 0x0a, 0x17, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x61, 0x6e, - 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4f, 0x0a, 0x12, 0x74, 0x69, - 0x6d, 0x65, 0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x5f, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, - 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x61, 0x6e, - 0x67, 0x65, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x52, 0x10, 0x74, 0x69, 0x6d, 0x65, 0x52, - 0x61, 0x6e, 0x67, 0x65, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x22, 0x86, 0x02, 0x0a, 0x10, - 0x54, 0x69, 0x6d, 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, - 0x12, 0x2c, 0x0a, 0x03, 0x6d, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, - 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, - 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x03, 0x6d, 0x69, 0x6e, 0x12, 0x2c, - 0x0a, 0x03, 0x6d, 0x61, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, - 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x03, 0x6d, 0x61, 0x78, 0x12, 0x46, 0x0a, 0x08, - 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, + 0x52, 0x09, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x5b, 0x0a, 0x08, 0x6d, + 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x35, 0x2e, + 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, + 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x42, 0x61, 0x73, 0x69, 0x63, 0x4d, 0x65, 0x61, + 0x73, 0x75, 0x72, 0x65, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x92, 0x01, 0x02, 0x08, 0x01, 0x52, 0x08, + 0x6d, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x73, 0x12, 0x3b, 0x0a, 0x15, 0x74, 0x69, 0x6d, 0x65, + 0x73, 0x74, 0x61, 0x6d, 0x70, 0x5f, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, + 0x52, 0x13, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x43, 0x6f, 0x6c, 0x75, 0x6d, + 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x43, 0x0a, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x72, 0x61, + 0x6e, 0x67, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x72, 0x69, 0x6c, 0x6c, + 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, + 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, + 0x09, 0x74, 0x69, 0x6d, 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x1f, 0x0a, 0x06, 0x70, 0x69, + 0x78, 0x65, 0x6c, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x1a, + 0x02, 0x28, 0x00, 0x52, 0x06, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x73, 0x12, 0x28, 0x0a, 0x0b, 0x73, + 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x05, + 0x42, 0x07, 0xfa, 0x42, 0x04, 0x1a, 0x02, 0x28, 0x00, 0x52, 0x0a, 0x73, 0x61, 0x6d, 0x70, 0x6c, + 0x65, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, + 0x79, 0x18, 0x09, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, + 0x79, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x7a, 0x6f, 0x6e, 0x65, 0x18, 0x0a, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x69, 0x6d, 0x65, 0x5a, 0x6f, 0x6e, 0x65, 0x1a, 0x62, + 0x0a, 0x0c, 0x42, 0x61, 0x73, 0x69, 0x63, 0x4d, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x12, 0x0e, + 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x27, + 0x0a, 0x0a, 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x0a, 0x65, 0x78, 0x70, + 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x71, 0x6c, 0x5f, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x71, 0x6c, 0x4e, 0x61, + 0x6d, 0x65, 0x22, 0x57, 0x0a, 0x18, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x69, 0x6d, 0x65, + 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3b, + 0x0a, 0x06, 0x72, 0x6f, 0x6c, 0x6c, 0x75, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, - 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, - 0x79, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x52, 0x08, 0x69, 0x6e, 0x74, 0x65, - 0x72, 0x76, 0x61, 0x6c, 0x1a, 0x4e, 0x0a, 0x08, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, - 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x6f, 0x6e, 0x74, 0x68, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, - 0x52, 0x06, 0x6d, 0x6f, 0x6e, 0x74, 0x68, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x79, 0x73, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x64, 0x61, 0x79, 0x73, 0x12, 0x16, 0x0a, 0x06, - 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x6d, 0x69, - 0x63, 0x72, 0x6f, 0x73, 0x22, 0x8c, 0x02, 0x0a, 0x18, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x43, - 0x61, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, - 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, - 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, - 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x18, 0x06, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x12, 0x27, 0x0a, 0x0f, - 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x18, - 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, - 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x26, 0x0a, 0x0a, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6e, - 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, - 0x10, 0x01, 0x52, 0x09, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x28, 0x0a, - 0x0b, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x0a, 0x63, 0x6f, 0x6c, - 0x75, 0x6d, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, - 0x69, 0x74, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, - 0x69, 0x74, 0x79, 0x22, 0x71, 0x0a, 0x19, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x43, 0x61, 0x72, - 0x64, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x54, 0x0a, 0x13, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x5f, - 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, + 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x52, 0x06, 0x72, 0x6f, 0x6c, 0x6c, 0x75, 0x70, 0x22, 0xb7, 0x01, 0x0a, 0x13, + 0x54, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x61, + 0x6e, 0x67, 0x65, 0x12, 0x30, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x05, + 0x73, 0x74, 0x61, 0x72, 0x74, 0x12, 0x2c, 0x0a, 0x03, 0x65, 0x6e, 0x64, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x03, + 0x65, 0x6e, 0x64, 0x12, 0x40, 0x0a, 0x08, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, + 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x47, 0x72, 0x61, 0x69, + 0x6e, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x08, 0x69, 0x6e, 0x74, + 0x65, 0x72, 0x76, 0x61, 0x6c, 0x22, 0xa9, 0x01, 0x0a, 0x12, 0x54, 0x69, 0x6d, 0x65, 0x53, 0x65, + 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3a, 0x0a, 0x07, + 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, - 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x53, 0x75, 0x6d, 0x6d, 0x61, - 0x72, 0x79, 0x52, 0x12, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x53, - 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x22, 0x8c, 0x05, 0x0a, 0x17, 0x43, 0x6f, 0x6c, 0x75, 0x6d, - 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x54, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, + 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x36, 0x0a, 0x05, 0x73, 0x70, 0x61, 0x72, + 0x6b, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, + 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x53, 0x65, + 0x72, 0x69, 0x65, 0x73, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x73, 0x70, 0x61, 0x72, 0x6b, + 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x53, 0x69, 0x7a, + 0x65, 0x22, 0x82, 0x01, 0x0a, 0x0f, 0x54, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, + 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x2a, 0x0a, 0x02, 0x74, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x02, 0x74, + 0x73, 0x12, 0x10, 0x0a, 0x03, 0x62, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x52, 0x03, + 0x62, 0x69, 0x6e, 0x12, 0x31, 0x0a, 0x07, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x07, 0x72, + 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x22, 0xe1, 0x01, 0x0a, 0x17, 0x54, 0x61, 0x62, 0x6c, 0x65, + 0x43, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, - 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, - 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x18, 0x0c, 0x20, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, + 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, - 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, + 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x26, 0x0a, 0x0a, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, - 0x02, 0x10, 0x01, 0x52, 0x09, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x5b, - 0x0a, 0x08, 0x6d, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x35, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, - 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x72, - 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x42, 0x61, 0x73, 0x69, 0x63, - 0x4d, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x92, 0x01, 0x02, 0x08, - 0x01, 0x52, 0x08, 0x6d, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x73, 0x12, 0x3b, 0x0a, 0x15, 0x74, - 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x5f, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x5f, - 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, - 0x02, 0x10, 0x01, 0x52, 0x13, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x43, 0x6f, - 0x6c, 0x75, 0x6d, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x43, 0x0a, 0x0a, 0x74, 0x69, 0x6d, 0x65, - 0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x72, - 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, - 0x69, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x61, 0x6e, - 0x67, 0x65, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x1f, 0x0a, - 0x06, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x42, 0x07, 0xfa, - 0x42, 0x04, 0x1a, 0x02, 0x28, 0x00, 0x52, 0x06, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x73, 0x12, 0x28, - 0x0a, 0x0b, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x08, 0x20, - 0x01, 0x28, 0x05, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x1a, 0x02, 0x28, 0x00, 0x52, 0x0a, 0x73, 0x61, - 0x6d, 0x70, 0x6c, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x69, 0x6f, - 0x72, 0x69, 0x74, 0x79, 0x18, 0x09, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x72, 0x69, 0x6f, - 0x72, 0x69, 0x74, 0x79, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x7a, 0x6f, 0x6e, - 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x69, 0x6d, 0x65, 0x5a, 0x6f, 0x6e, - 0x65, 0x1a, 0x62, 0x0a, 0x0c, 0x42, 0x61, 0x73, 0x69, 0x63, 0x4d, 0x65, 0x61, 0x73, 0x75, 0x72, - 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, - 0x64, 0x12, 0x27, 0x0a, 0x0a, 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x0a, - 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x71, - 0x6c, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x71, - 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x57, 0x0a, 0x18, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, - 0x69, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x3b, 0x0a, 0x06, 0x72, 0x6f, 0x6c, 0x6c, 0x75, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x23, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, - 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x06, 0x72, 0x6f, 0x6c, 0x6c, 0x75, 0x70, 0x22, 0xb7, - 0x01, 0x0a, 0x13, 0x54, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x54, 0x69, 0x6d, - 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x30, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, - 0x70, 0x52, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x12, 0x2c, 0x0a, 0x03, 0x65, 0x6e, 0x64, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, - 0x70, 0x52, 0x03, 0x65, 0x6e, 0x64, 0x12, 0x40, 0x0a, 0x08, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, - 0x61, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, - 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x47, - 0x72, 0x61, 0x69, 0x6e, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x08, - 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x22, 0xa9, 0x01, 0x0a, 0x12, 0x54, 0x69, 0x6d, - 0x65, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x3a, 0x0a, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x20, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, - 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x56, 0x61, 0x6c, - 0x75, 0x65, 0x52, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x36, 0x0a, 0x05, 0x73, - 0x70, 0x61, 0x72, 0x6b, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x72, 0x69, 0x6c, - 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, - 0x65, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x73, 0x70, - 0x61, 0x72, 0x6b, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x5f, 0x73, 0x69, - 0x7a, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, - 0x53, 0x69, 0x7a, 0x65, 0x22, 0x82, 0x01, 0x0a, 0x0f, 0x54, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x72, - 0x69, 0x65, 0x73, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x2a, 0x0a, 0x02, 0x74, 0x73, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, - 0x52, 0x02, 0x74, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x62, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x01, 0x52, 0x03, 0x62, 0x69, 0x6e, 0x12, 0x31, 0x0a, 0x07, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, - 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, - 0x52, 0x07, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x22, 0xe1, 0x01, 0x0a, 0x17, 0x54, 0x61, + 0x02, 0x10, 0x01, 0x52, 0x09, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1a, + 0x0a, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x22, 0x3c, 0x0a, 0x18, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, - 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x74, - 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, - 0x74, 0x6f, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, - 0x63, 0x74, 0x6f, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, - 0x12, 0x27, 0x0a, 0x0f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x73, 0x63, 0x68, - 0x65, 0x6d, 0x61, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x64, 0x61, 0x74, 0x61, 0x62, - 0x61, 0x73, 0x65, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x26, 0x0a, 0x0a, 0x74, 0x61, 0x62, - 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, - 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x09, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x4e, 0x61, 0x6d, - 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x22, 0x3c, 0x0a, - 0x18, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, - 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x61, 0x72, - 0x64, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, - 0x63, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x22, 0xdd, 0x01, 0x0a, 0x13, - 0x54, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x61, 0x72, 0x64, 0x69, 0x6e, + 0x61, 0x6c, 0x69, 0x74, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x63, 0x61, 0x72, + 0x64, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x22, 0xdd, 0x01, 0x0a, 0x13, 0x54, 0x61, 0x62, + 0x6c, 0x65, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, + 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, + 0x1a, 0x0a, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x64, + 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, 0x63, + 0x68, 0x65, 0x6d, 0x61, 0x12, 0x26, 0x0a, 0x0a, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, + 0x01, 0x52, 0x09, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, + 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, + 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x22, 0x96, 0x02, 0x0a, 0x14, 0x54, 0x61, 0x62, + 0x6c, 0x65, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x47, 0x0a, 0x0f, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x63, 0x6f, 0x6c, + 0x75, 0x6d, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x72, 0x69, 0x6c, + 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, + 0x66, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x52, 0x0e, 0x70, 0x72, 0x6f, 0x66, + 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x12, 0x6e, 0x0a, 0x13, 0x75, 0x6e, + 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x5f, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, + 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3d, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, + 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x43, + 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x55, + 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, + 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x12, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, + 0x74, 0x65, 0x64, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x1a, 0x45, 0x0a, 0x17, 0x55, 0x6e, + 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, + 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, + 0x01, 0x22, 0x6b, 0x0a, 0x0d, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x6c, 0x75, + 0x6d, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x32, 0x0a, 0x15, 0x6c, 0x61, + 0x72, 0x67, 0x65, 0x73, 0x74, 0x5f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x5f, 0x6c, 0x65, 0x6e, + 0x67, 0x74, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x13, 0x6c, 0x61, 0x72, 0x67, 0x65, + 0x73, 0x74, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x22, 0xf9, + 0x01, 0x0a, 0x10, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x6f, 0x77, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, - 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, - 0x6f, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x18, 0x05, + 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, + 0x6f, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, - 0x61, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, + 0x61, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x26, 0x0a, 0x0a, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x09, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, - 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x05, 0x52, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x22, 0x96, 0x02, 0x0a, 0x14, - 0x54, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x47, 0x0a, 0x0f, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x5f, - 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, - 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, - 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x52, 0x0e, 0x70, - 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x12, 0x6e, 0x0a, - 0x13, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x5f, 0x63, 0x6f, 0x6c, - 0x75, 0x6d, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3d, 0x2e, 0x72, 0x69, 0x6c, - 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x61, 0x62, - 0x6c, 0x65, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x2e, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x43, 0x6f, 0x6c, - 0x75, 0x6d, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x12, 0x75, 0x6e, 0x73, 0x75, 0x70, - 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x1a, 0x45, 0x0a, - 0x17, 0x55, 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x43, 0x6f, 0x6c, 0x75, - 0x6d, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, - 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, - 0x3a, 0x02, 0x38, 0x01, 0x22, 0x6b, 0x0a, 0x0d, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x43, - 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x32, 0x0a, - 0x15, 0x6c, 0x61, 0x72, 0x67, 0x65, 0x73, 0x74, 0x5f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x5f, - 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x13, 0x6c, 0x61, - 0x72, 0x67, 0x65, 0x73, 0x74, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x4c, 0x65, 0x6e, 0x67, 0x74, - 0x68, 0x22, 0xf9, 0x01, 0x0a, 0x10, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x6f, 0x77, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, - 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x73, - 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x6e, 0x65, - 0x63, 0x74, 0x6f, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x6e, - 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, - 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, - 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x73, 0x63, - 0x68, 0x65, 0x6d, 0x61, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x64, 0x61, 0x74, 0x61, - 0x62, 0x61, 0x73, 0x65, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x26, 0x0a, 0x0a, 0x74, 0x61, - 0x62, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, - 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x09, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x4e, 0x61, - 0x6d, 0x65, 0x12, 0x1d, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x05, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x1a, 0x02, 0x28, 0x00, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, - 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x22, 0x40, 0x0a, - 0x11, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x6f, 0x77, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x2b, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x2a, - 0x70, 0x0a, 0x0e, 0x42, 0x75, 0x69, 0x6c, 0x74, 0x69, 0x6e, 0x4d, 0x65, 0x61, 0x73, 0x75, 0x72, - 0x65, 0x12, 0x1f, 0x0a, 0x1b, 0x42, 0x55, 0x49, 0x4c, 0x54, 0x49, 0x4e, 0x5f, 0x4d, 0x45, 0x41, - 0x53, 0x55, 0x52, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, - 0x10, 0x00, 0x12, 0x19, 0x0a, 0x15, 0x42, 0x55, 0x49, 0x4c, 0x54, 0x49, 0x4e, 0x5f, 0x4d, 0x45, - 0x41, 0x53, 0x55, 0x52, 0x45, 0x5f, 0x43, 0x4f, 0x55, 0x4e, 0x54, 0x10, 0x01, 0x12, 0x22, 0x0a, - 0x1e, 0x42, 0x55, 0x49, 0x4c, 0x54, 0x49, 0x4e, 0x5f, 0x4d, 0x45, 0x41, 0x53, 0x55, 0x52, 0x45, - 0x5f, 0x43, 0x4f, 0x55, 0x4e, 0x54, 0x5f, 0x44, 0x49, 0x53, 0x54, 0x49, 0x4e, 0x43, 0x54, 0x10, - 0x02, 0x2a, 0x9e, 0x02, 0x0a, 0x1d, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, - 0x77, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x69, 0x73, 0x6f, 0x6e, 0x53, 0x6f, 0x72, 0x74, 0x54, - 0x79, 0x70, 0x65, 0x12, 0x31, 0x0a, 0x2d, 0x4d, 0x45, 0x54, 0x52, 0x49, 0x43, 0x53, 0x5f, 0x56, - 0x49, 0x45, 0x57, 0x5f, 0x43, 0x4f, 0x4d, 0x50, 0x41, 0x52, 0x49, 0x53, 0x4f, 0x4e, 0x5f, 0x53, - 0x4f, 0x52, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, - 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x30, 0x0a, 0x2c, 0x4d, 0x45, 0x54, 0x52, 0x49, 0x43, - 0x53, 0x5f, 0x56, 0x49, 0x45, 0x57, 0x5f, 0x43, 0x4f, 0x4d, 0x50, 0x41, 0x52, 0x49, 0x53, 0x4f, - 0x4e, 0x5f, 0x53, 0x4f, 0x52, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x42, 0x41, 0x53, 0x45, - 0x5f, 0x56, 0x41, 0x4c, 0x55, 0x45, 0x10, 0x01, 0x12, 0x36, 0x0a, 0x32, 0x4d, 0x45, 0x54, 0x52, - 0x49, 0x43, 0x53, 0x5f, 0x56, 0x49, 0x45, 0x57, 0x5f, 0x43, 0x4f, 0x4d, 0x50, 0x41, 0x52, 0x49, - 0x53, 0x4f, 0x4e, 0x5f, 0x53, 0x4f, 0x52, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x43, 0x4f, - 0x4d, 0x50, 0x41, 0x52, 0x49, 0x53, 0x4f, 0x4e, 0x5f, 0x56, 0x41, 0x4c, 0x55, 0x45, 0x10, 0x02, - 0x12, 0x2f, 0x0a, 0x2b, 0x4d, 0x45, 0x54, 0x52, 0x49, 0x43, 0x53, 0x5f, 0x56, 0x49, 0x45, 0x57, + 0x1d, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x42, 0x07, + 0xfa, 0x42, 0x04, 0x1a, 0x02, 0x28, 0x00, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x1a, + 0x0a, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x08, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x22, 0x40, 0x0a, 0x11, 0x54, 0x61, + 0x62, 0x6c, 0x65, 0x52, 0x6f, 0x77, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x2b, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x2a, 0x70, 0x0a, 0x0e, + 0x42, 0x75, 0x69, 0x6c, 0x74, 0x69, 0x6e, 0x4d, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x12, 0x1f, + 0x0a, 0x1b, 0x42, 0x55, 0x49, 0x4c, 0x54, 0x49, 0x4e, 0x5f, 0x4d, 0x45, 0x41, 0x53, 0x55, 0x52, + 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, + 0x19, 0x0a, 0x15, 0x42, 0x55, 0x49, 0x4c, 0x54, 0x49, 0x4e, 0x5f, 0x4d, 0x45, 0x41, 0x53, 0x55, + 0x52, 0x45, 0x5f, 0x43, 0x4f, 0x55, 0x4e, 0x54, 0x10, 0x01, 0x12, 0x22, 0x0a, 0x1e, 0x42, 0x55, + 0x49, 0x4c, 0x54, 0x49, 0x4e, 0x5f, 0x4d, 0x45, 0x41, 0x53, 0x55, 0x52, 0x45, 0x5f, 0x43, 0x4f, + 0x55, 0x4e, 0x54, 0x5f, 0x44, 0x49, 0x53, 0x54, 0x49, 0x4e, 0x43, 0x54, 0x10, 0x02, 0x2a, 0x9e, + 0x02, 0x0a, 0x1d, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x43, 0x6f, + 0x6d, 0x70, 0x61, 0x72, 0x69, 0x73, 0x6f, 0x6e, 0x53, 0x6f, 0x72, 0x74, 0x54, 0x79, 0x70, 0x65, + 0x12, 0x31, 0x0a, 0x2d, 0x4d, 0x45, 0x54, 0x52, 0x49, 0x43, 0x53, 0x5f, 0x56, 0x49, 0x45, 0x57, 0x5f, 0x43, 0x4f, 0x4d, 0x50, 0x41, 0x52, 0x49, 0x53, 0x4f, 0x4e, 0x5f, 0x53, 0x4f, 0x52, 0x54, - 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x41, 0x42, 0x53, 0x5f, 0x44, 0x45, 0x4c, 0x54, 0x41, 0x10, - 0x03, 0x12, 0x2f, 0x0a, 0x2b, 0x4d, 0x45, 0x54, 0x52, 0x49, 0x43, 0x53, 0x5f, 0x56, 0x49, 0x45, - 0x57, 0x5f, 0x43, 0x4f, 0x4d, 0x50, 0x41, 0x52, 0x49, 0x53, 0x4f, 0x4e, 0x5f, 0x53, 0x4f, 0x52, - 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x52, 0x45, 0x4c, 0x5f, 0x44, 0x45, 0x4c, 0x54, 0x41, - 0x10, 0x04, 0x2a, 0xb0, 0x02, 0x0a, 0x20, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, - 0x65, 0x77, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x69, 0x73, 0x6f, 0x6e, 0x4d, 0x65, 0x61, 0x73, - 0x75, 0x72, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x34, 0x0a, 0x30, 0x4d, 0x45, 0x54, 0x52, 0x49, - 0x43, 0x53, 0x5f, 0x56, 0x49, 0x45, 0x57, 0x5f, 0x43, 0x4f, 0x4d, 0x50, 0x41, 0x52, 0x49, 0x53, - 0x4f, 0x4e, 0x5f, 0x4d, 0x45, 0x41, 0x53, 0x55, 0x52, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, - 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x33, 0x0a, - 0x2f, 0x4d, 0x45, 0x54, 0x52, 0x49, 0x43, 0x53, 0x5f, 0x56, 0x49, 0x45, 0x57, 0x5f, 0x43, 0x4f, - 0x4d, 0x50, 0x41, 0x52, 0x49, 0x53, 0x4f, 0x4e, 0x5f, 0x4d, 0x45, 0x41, 0x53, 0x55, 0x52, 0x45, - 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x42, 0x41, 0x53, 0x45, 0x5f, 0x56, 0x41, 0x4c, 0x55, 0x45, - 0x10, 0x01, 0x12, 0x39, 0x0a, 0x35, 0x4d, 0x45, 0x54, 0x52, 0x49, 0x43, 0x53, 0x5f, 0x56, 0x49, - 0x45, 0x57, 0x5f, 0x43, 0x4f, 0x4d, 0x50, 0x41, 0x52, 0x49, 0x53, 0x4f, 0x4e, 0x5f, 0x4d, 0x45, - 0x41, 0x53, 0x55, 0x52, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x43, 0x4f, 0x4d, 0x50, 0x41, - 0x52, 0x49, 0x53, 0x4f, 0x4e, 0x5f, 0x56, 0x41, 0x4c, 0x55, 0x45, 0x10, 0x02, 0x12, 0x32, 0x0a, - 0x2e, 0x4d, 0x45, 0x54, 0x52, 0x49, 0x43, 0x53, 0x5f, 0x56, 0x49, 0x45, 0x57, 0x5f, 0x43, 0x4f, - 0x4d, 0x50, 0x41, 0x52, 0x49, 0x53, 0x4f, 0x4e, 0x5f, 0x4d, 0x45, 0x41, 0x53, 0x55, 0x52, 0x45, - 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x41, 0x42, 0x53, 0x5f, 0x44, 0x45, 0x4c, 0x54, 0x41, 0x10, - 0x03, 0x12, 0x32, 0x0a, 0x2e, 0x4d, 0x45, 0x54, 0x52, 0x49, 0x43, 0x53, 0x5f, 0x56, 0x49, 0x45, - 0x57, 0x5f, 0x43, 0x4f, 0x4d, 0x50, 0x41, 0x52, 0x49, 0x53, 0x4f, 0x4e, 0x5f, 0x4d, 0x45, 0x41, - 0x53, 0x55, 0x52, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x52, 0x45, 0x4c, 0x5f, 0x44, 0x45, - 0x4c, 0x54, 0x41, 0x10, 0x04, 0x2a, 0x6d, 0x0a, 0x0f, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, - 0x61, 0x6d, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x20, 0x0a, 0x1c, 0x48, 0x49, 0x53, 0x54, - 0x4f, 0x47, 0x52, 0x41, 0x4d, 0x5f, 0x4d, 0x45, 0x54, 0x48, 0x4f, 0x44, 0x5f, 0x55, 0x4e, 0x53, - 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x17, 0x0a, 0x13, 0x48, 0x49, - 0x53, 0x54, 0x4f, 0x47, 0x52, 0x41, 0x4d, 0x5f, 0x4d, 0x45, 0x54, 0x48, 0x4f, 0x44, 0x5f, 0x46, - 0x44, 0x10, 0x01, 0x12, 0x1f, 0x0a, 0x1b, 0x48, 0x49, 0x53, 0x54, 0x4f, 0x47, 0x52, 0x41, 0x4d, - 0x5f, 0x4d, 0x45, 0x54, 0x48, 0x4f, 0x44, 0x5f, 0x44, 0x49, 0x41, 0x47, 0x4e, 0x4f, 0x53, 0x54, - 0x49, 0x43, 0x10, 0x02, 0x32, 0xab, 0x27, 0x0a, 0x0c, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x74, 0x0a, 0x05, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x1d, - 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, - 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, - 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, - 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2c, 0x82, - 0xd3, 0xe4, 0x93, 0x02, 0x26, 0x3a, 0x01, 0x2a, 0x22, 0x21, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, - 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, - 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x12, 0x8b, 0x01, 0x0a, 0x0a, - 0x51, 0x75, 0x65, 0x72, 0x79, 0x42, 0x61, 0x74, 0x63, 0x68, 0x12, 0x22, 0x2e, 0x72, 0x69, 0x6c, + 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, + 0x44, 0x10, 0x00, 0x12, 0x30, 0x0a, 0x2c, 0x4d, 0x45, 0x54, 0x52, 0x49, 0x43, 0x53, 0x5f, 0x56, + 0x49, 0x45, 0x57, 0x5f, 0x43, 0x4f, 0x4d, 0x50, 0x41, 0x52, 0x49, 0x53, 0x4f, 0x4e, 0x5f, 0x53, + 0x4f, 0x52, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x42, 0x41, 0x53, 0x45, 0x5f, 0x56, 0x41, + 0x4c, 0x55, 0x45, 0x10, 0x01, 0x12, 0x36, 0x0a, 0x32, 0x4d, 0x45, 0x54, 0x52, 0x49, 0x43, 0x53, + 0x5f, 0x56, 0x49, 0x45, 0x57, 0x5f, 0x43, 0x4f, 0x4d, 0x50, 0x41, 0x52, 0x49, 0x53, 0x4f, 0x4e, + 0x5f, 0x53, 0x4f, 0x52, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x43, 0x4f, 0x4d, 0x50, 0x41, + 0x52, 0x49, 0x53, 0x4f, 0x4e, 0x5f, 0x56, 0x41, 0x4c, 0x55, 0x45, 0x10, 0x02, 0x12, 0x2f, 0x0a, + 0x2b, 0x4d, 0x45, 0x54, 0x52, 0x49, 0x43, 0x53, 0x5f, 0x56, 0x49, 0x45, 0x57, 0x5f, 0x43, 0x4f, + 0x4d, 0x50, 0x41, 0x52, 0x49, 0x53, 0x4f, 0x4e, 0x5f, 0x53, 0x4f, 0x52, 0x54, 0x5f, 0x54, 0x59, + 0x50, 0x45, 0x5f, 0x41, 0x42, 0x53, 0x5f, 0x44, 0x45, 0x4c, 0x54, 0x41, 0x10, 0x03, 0x12, 0x2f, + 0x0a, 0x2b, 0x4d, 0x45, 0x54, 0x52, 0x49, 0x43, 0x53, 0x5f, 0x56, 0x49, 0x45, 0x57, 0x5f, 0x43, + 0x4f, 0x4d, 0x50, 0x41, 0x52, 0x49, 0x53, 0x4f, 0x4e, 0x5f, 0x53, 0x4f, 0x52, 0x54, 0x5f, 0x54, + 0x59, 0x50, 0x45, 0x5f, 0x52, 0x45, 0x4c, 0x5f, 0x44, 0x45, 0x4c, 0x54, 0x41, 0x10, 0x04, 0x2a, + 0xb0, 0x02, 0x0a, 0x20, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x43, + 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x69, 0x73, 0x6f, 0x6e, 0x4d, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, + 0x54, 0x79, 0x70, 0x65, 0x12, 0x34, 0x0a, 0x30, 0x4d, 0x45, 0x54, 0x52, 0x49, 0x43, 0x53, 0x5f, + 0x56, 0x49, 0x45, 0x57, 0x5f, 0x43, 0x4f, 0x4d, 0x50, 0x41, 0x52, 0x49, 0x53, 0x4f, 0x4e, 0x5f, + 0x4d, 0x45, 0x41, 0x53, 0x55, 0x52, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, + 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x33, 0x0a, 0x2f, 0x4d, 0x45, + 0x54, 0x52, 0x49, 0x43, 0x53, 0x5f, 0x56, 0x49, 0x45, 0x57, 0x5f, 0x43, 0x4f, 0x4d, 0x50, 0x41, + 0x52, 0x49, 0x53, 0x4f, 0x4e, 0x5f, 0x4d, 0x45, 0x41, 0x53, 0x55, 0x52, 0x45, 0x5f, 0x54, 0x59, + 0x50, 0x45, 0x5f, 0x42, 0x41, 0x53, 0x45, 0x5f, 0x56, 0x41, 0x4c, 0x55, 0x45, 0x10, 0x01, 0x12, + 0x39, 0x0a, 0x35, 0x4d, 0x45, 0x54, 0x52, 0x49, 0x43, 0x53, 0x5f, 0x56, 0x49, 0x45, 0x57, 0x5f, + 0x43, 0x4f, 0x4d, 0x50, 0x41, 0x52, 0x49, 0x53, 0x4f, 0x4e, 0x5f, 0x4d, 0x45, 0x41, 0x53, 0x55, + 0x52, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x43, 0x4f, 0x4d, 0x50, 0x41, 0x52, 0x49, 0x53, + 0x4f, 0x4e, 0x5f, 0x56, 0x41, 0x4c, 0x55, 0x45, 0x10, 0x02, 0x12, 0x32, 0x0a, 0x2e, 0x4d, 0x45, + 0x54, 0x52, 0x49, 0x43, 0x53, 0x5f, 0x56, 0x49, 0x45, 0x57, 0x5f, 0x43, 0x4f, 0x4d, 0x50, 0x41, + 0x52, 0x49, 0x53, 0x4f, 0x4e, 0x5f, 0x4d, 0x45, 0x41, 0x53, 0x55, 0x52, 0x45, 0x5f, 0x54, 0x59, + 0x50, 0x45, 0x5f, 0x41, 0x42, 0x53, 0x5f, 0x44, 0x45, 0x4c, 0x54, 0x41, 0x10, 0x03, 0x12, 0x32, + 0x0a, 0x2e, 0x4d, 0x45, 0x54, 0x52, 0x49, 0x43, 0x53, 0x5f, 0x56, 0x49, 0x45, 0x57, 0x5f, 0x43, + 0x4f, 0x4d, 0x50, 0x41, 0x52, 0x49, 0x53, 0x4f, 0x4e, 0x5f, 0x4d, 0x45, 0x41, 0x53, 0x55, 0x52, + 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x52, 0x45, 0x4c, 0x5f, 0x44, 0x45, 0x4c, 0x54, 0x41, + 0x10, 0x04, 0x2a, 0x6d, 0x0a, 0x0f, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x4d, + 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x20, 0x0a, 0x1c, 0x48, 0x49, 0x53, 0x54, 0x4f, 0x47, 0x52, + 0x41, 0x4d, 0x5f, 0x4d, 0x45, 0x54, 0x48, 0x4f, 0x44, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, + 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x17, 0x0a, 0x13, 0x48, 0x49, 0x53, 0x54, 0x4f, + 0x47, 0x52, 0x41, 0x4d, 0x5f, 0x4d, 0x45, 0x54, 0x48, 0x4f, 0x44, 0x5f, 0x46, 0x44, 0x10, 0x01, + 0x12, 0x1f, 0x0a, 0x1b, 0x48, 0x49, 0x53, 0x54, 0x4f, 0x47, 0x52, 0x41, 0x4d, 0x5f, 0x4d, 0x45, + 0x54, 0x48, 0x4f, 0x44, 0x5f, 0x44, 0x49, 0x41, 0x47, 0x4e, 0x4f, 0x53, 0x54, 0x49, 0x43, 0x10, + 0x02, 0x32, 0xab, 0x27, 0x0a, 0x0c, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x12, 0x74, 0x0a, 0x05, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x1d, 0x2e, 0x72, 0x69, + 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x51, 0x75, + 0x65, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x51, 0x75, 0x65, - 0x72, 0x79, 0x42, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, - 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, - 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x42, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x32, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2c, 0x3a, 0x01, 0x2a, 0x22, 0x27, - 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, - 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, - 0x79, 0x2f, 0x62, 0x61, 0x74, 0x63, 0x68, 0x30, 0x01, 0x12, 0x80, 0x01, 0x0a, 0x06, 0x45, 0x78, - 0x70, 0x6f, 0x72, 0x74, 0x12, 0x1e, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, - 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, - 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x35, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2f, 0x3a, 0x01, 0x2a, - 0x22, 0x2a, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, - 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x71, 0x75, - 0x65, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x9b, 0x01, 0x0a, - 0x0c, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x24, 0x2e, - 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, - 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, - 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x70, 0x6f, - 0x72, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x3e, 0x82, 0xd3, 0xe4, 0x93, - 0x02, 0x38, 0x3a, 0x01, 0x2a, 0x22, 0x33, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, + 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2c, 0x82, 0xd3, 0xe4, 0x93, + 0x02, 0x26, 0x3a, 0x01, 0x2a, 0x22, 0x21, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, - 0x64, 0x7d, 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x2f, 0x7b, 0x72, 0x65, 0x70, 0x6f, - 0x72, 0x74, 0x7d, 0x2f, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x12, 0xd2, 0x01, 0x0a, 0x16, 0x4d, - 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2e, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, - 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, - 0x69, 0x65, 0x77, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, - 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, - 0x69, 0x65, 0x77, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x57, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x51, 0x3a, 0x01, - 0x2a, 0x22, 0x4c, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, - 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x71, - 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2d, 0x76, - 0x69, 0x65, 0x77, 0x73, 0x2f, 0x7b, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x76, 0x69, - 0x65, 0x77, 0x7d, 0x2f, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, - 0xc7, 0x01, 0x0a, 0x12, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x54, - 0x6f, 0x70, 0x6c, 0x69, 0x73, 0x74, 0x12, 0x2a, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, - 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, - 0x56, 0x69, 0x65, 0x77, 0x54, 0x6f, 0x70, 0x6c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, + 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x12, 0x8b, 0x01, 0x0a, 0x0a, 0x51, 0x75, 0x65, + 0x72, 0x79, 0x42, 0x61, 0x74, 0x63, 0x68, 0x12, 0x22, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, + 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x42, + 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x72, 0x69, + 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x51, 0x75, + 0x65, 0x72, 0x79, 0x42, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x32, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2c, 0x3a, 0x01, 0x2a, 0x22, 0x27, 0x2f, 0x76, 0x31, + 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, + 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2f, 0x62, + 0x61, 0x74, 0x63, 0x68, 0x30, 0x01, 0x12, 0x80, 0x01, 0x0a, 0x06, 0x45, 0x78, 0x70, 0x6f, 0x72, + 0x74, 0x12, 0x1e, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, + 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x1f, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, + 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x35, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2f, 0x3a, 0x01, 0x2a, 0x22, 0x2a, 0x2f, + 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e, + 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x69, + 0x65, 0x73, 0x2f, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x9b, 0x01, 0x0a, 0x0c, 0x45, 0x78, + 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x24, 0x2e, 0x72, 0x69, 0x6c, + 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, + 0x6f, 0x72, 0x74, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x25, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, + 0x76, 0x31, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x3e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x38, 0x3a, + 0x01, 0x2a, 0x22, 0x33, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, + 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, + 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x2f, 0x7b, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x7d, + 0x2f, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x12, 0xd2, 0x01, 0x0a, 0x16, 0x4d, 0x65, 0x74, 0x72, + 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x12, 0x2e, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, - 0x54, 0x6f, 0x70, 0x6c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x58, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x52, 0x3a, 0x01, 0x2a, 0x22, 0x4d, 0x2f, 0x76, 0x31, 0x2f, + 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, + 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, + 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x57, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x51, 0x3a, 0x01, 0x2a, 0x22, 0x4c, + 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, + 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, + 0x69, 0x65, 0x73, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2d, 0x76, 0x69, 0x65, 0x77, + 0x73, 0x2f, 0x7b, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x76, 0x69, 0x65, 0x77, 0x7d, + 0x2f, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0xc7, 0x01, 0x0a, + 0x12, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x54, 0x6f, 0x70, 0x6c, + 0x69, 0x73, 0x74, 0x12, 0x2a, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, + 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, + 0x77, 0x54, 0x6f, 0x70, 0x6c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x2b, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, + 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x54, 0x6f, 0x70, + 0x6c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x58, 0x82, 0xd3, + 0xe4, 0x93, 0x02, 0x52, 0x3a, 0x01, 0x2a, 0x22, 0x4d, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, + 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, + 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x6d, 0x65, 0x74, + 0x72, 0x69, 0x63, 0x73, 0x2d, 0x76, 0x69, 0x65, 0x77, 0x73, 0x2f, 0x7b, 0x6d, 0x65, 0x74, 0x72, + 0x69, 0x63, 0x73, 0x5f, 0x76, 0x69, 0x65, 0x77, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x74, + 0x6f, 0x70, 0x6c, 0x69, 0x73, 0x74, 0x12, 0xd8, 0x01, 0x0a, 0x15, 0x4d, 0x65, 0x74, 0x72, 0x69, + 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x69, 0x73, 0x6f, 0x6e, + 0x12, 0x2d, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, + 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x43, 0x6f, + 0x6d, 0x70, 0x61, 0x72, 0x69, 0x73, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x2e, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, + 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x43, 0x6f, 0x6d, + 0x70, 0x61, 0x72, 0x69, 0x73, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x60, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x5a, 0x3a, 0x01, 0x2a, 0x22, 0x55, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2d, 0x76, 0x69, 0x65, 0x77, 0x73, 0x2f, 0x7b, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x76, 0x69, 0x65, 0x77, 0x5f, 0x6e, 0x61, 0x6d, 0x65, - 0x7d, 0x2f, 0x74, 0x6f, 0x70, 0x6c, 0x69, 0x73, 0x74, 0x12, 0xd8, 0x01, 0x0a, 0x15, 0x4d, 0x65, - 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x69, - 0x73, 0x6f, 0x6e, 0x12, 0x2d, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, - 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, - 0x77, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x69, 0x73, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, - 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, - 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x69, 0x73, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x22, 0x60, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x5a, 0x3a, 0x01, 0x2a, 0x22, 0x55, 0x2f, - 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e, - 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x69, - 0x65, 0x73, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2d, 0x76, 0x69, 0x65, 0x77, 0x73, - 0x2f, 0x7b, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x76, 0x69, 0x65, 0x77, 0x5f, 0x6e, - 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x65, 0x2d, 0x74, 0x6f, 0x70, - 0x6c, 0x69, 0x73, 0x74, 0x12, 0xd3, 0x01, 0x0a, 0x15, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, - 0x56, 0x69, 0x65, 0x77, 0x54, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x12, 0x2d, - 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, - 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x54, 0x69, 0x6d, 0x65, - 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, - 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, - 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x54, 0x69, 0x6d, 0x65, 0x53, - 0x65, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x5b, 0x82, - 0xd3, 0xe4, 0x93, 0x02, 0x55, 0x3a, 0x01, 0x2a, 0x22, 0x50, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, - 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, - 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x6d, 0x65, - 0x74, 0x72, 0x69, 0x63, 0x73, 0x2d, 0x76, 0x69, 0x65, 0x77, 0x73, 0x2f, 0x7b, 0x6d, 0x65, 0x74, - 0x72, 0x69, 0x63, 0x73, 0x5f, 0x76, 0x69, 0x65, 0x77, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, - 0x74, 0x69, 0x6d, 0x65, 0x73, 0x65, 0x72, 0x69, 0x65, 0x73, 0x12, 0xc3, 0x01, 0x0a, 0x11, 0x4d, - 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x73, - 0x12, 0x29, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, - 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x54, 0x6f, - 0x74, 0x61, 0x6c, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x72, 0x69, + 0x7d, 0x2f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x65, 0x2d, 0x74, 0x6f, 0x70, 0x6c, 0x69, 0x73, + 0x74, 0x12, 0xd3, 0x01, 0x0a, 0x15, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, + 0x77, 0x54, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x12, 0x2d, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, - 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x73, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x57, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x51, 0x3a, - 0x01, 0x2a, 0x22, 0x4c, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, - 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, - 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2d, - 0x76, 0x69, 0x65, 0x77, 0x73, 0x2f, 0x7b, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x76, - 0x69, 0x65, 0x77, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x73, - 0x12, 0xbb, 0x01, 0x0a, 0x0f, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, - 0x52, 0x6f, 0x77, 0x73, 0x12, 0x27, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, - 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, - 0x65, 0x77, 0x52, 0x6f, 0x77, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, + 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x54, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x72, + 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x72, 0x69, 0x6c, + 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, + 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x54, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x69, + 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x5b, 0x82, 0xd3, 0xe4, 0x93, + 0x02, 0x55, 0x3a, 0x01, 0x2a, 0x22, 0x50, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, + 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, + 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, + 0x63, 0x73, 0x2d, 0x76, 0x69, 0x65, 0x77, 0x73, 0x2f, 0x7b, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, + 0x73, 0x5f, 0x76, 0x69, 0x65, 0x77, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x74, 0x69, 0x6d, + 0x65, 0x73, 0x65, 0x72, 0x69, 0x65, 0x73, 0x12, 0xc3, 0x01, 0x0a, 0x11, 0x4d, 0x65, 0x74, 0x72, + 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x73, 0x12, 0x29, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, - 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x52, 0x6f, 0x77, 0x73, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x55, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x4f, 0x3a, - 0x01, 0x2a, 0x22, 0x4a, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, - 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, - 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2d, - 0x76, 0x69, 0x65, 0x77, 0x73, 0x2f, 0x7b, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x76, - 0x69, 0x65, 0x77, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x72, 0x6f, 0x77, 0x73, 0x12, 0xd8, - 0x01, 0x0a, 0x14, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x54, 0x69, - 0x6d, 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x2c, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, - 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, - 0x73, 0x56, 0x69, 0x65, 0x77, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2d, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, - 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, - 0x69, 0x65, 0x77, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x63, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x5d, 0x3a, 0x01, 0x2a, 0x22, - 0x58, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, + 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x54, 0x6f, 0x74, 0x61, 0x6c, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, + 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, + 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x57, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x51, 0x3a, 0x01, 0x2a, 0x22, + 0x4c, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2d, 0x76, 0x69, 0x65, 0x77, 0x73, 0x2f, 0x7b, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x76, 0x69, 0x65, 0x77, - 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x2d, 0x72, 0x61, 0x6e, 0x67, - 0x65, 0x2d, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x12, 0xc0, 0x01, 0x0a, 0x11, 0x4d, 0x65, - 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, - 0x29, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, - 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x53, 0x63, 0x68, - 0x65, 0x6d, 0x61, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x72, 0x69, 0x6c, + 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x73, 0x12, 0xbb, 0x01, + 0x0a, 0x0f, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x52, 0x6f, 0x77, + 0x73, 0x12, 0x27, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, + 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x52, + 0x6f, 0x77, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, - 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x54, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x4e, 0x12, 0x4c, - 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, - 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, - 0x69, 0x65, 0x73, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2d, 0x76, 0x69, 0x65, 0x77, - 0x73, 0x2f, 0x7b, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x76, 0x69, 0x65, 0x77, 0x5f, - 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0xc3, 0x01, 0x0a, - 0x11, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x53, 0x65, 0x61, 0x72, - 0x63, 0x68, 0x12, 0x29, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, - 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, - 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, - 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, - 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x53, 0x65, 0x61, 0x72, 0x63, - 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x57, 0x82, 0xd3, 0xe4, 0x93, 0x02, - 0x51, 0x3a, 0x01, 0x2a, 0x22, 0x4c, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, - 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, - 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, - 0x73, 0x2d, 0x76, 0x69, 0x65, 0x77, 0x73, 0x2f, 0x7b, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, - 0x5f, 0x76, 0x69, 0x65, 0x77, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x73, 0x65, 0x61, 0x72, - 0x63, 0x68, 0x12, 0xb6, 0x01, 0x0a, 0x10, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x43, 0x6f, - 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x12, 0x28, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, - 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, - 0x65, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x29, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, - 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x43, 0x6f, 0x6d, 0x70, 0x6f, - 0x6e, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x4d, 0x82, 0xd3, - 0xe4, 0x93, 0x02, 0x47, 0x3a, 0x01, 0x2a, 0x22, 0x42, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, - 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, - 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x63, 0x6f, 0x6d, - 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x73, 0x2f, 0x7b, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, - 0x6e, 0x74, 0x7d, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x12, 0xc7, 0x01, 0x0a, 0x14, - 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x52, 0x6f, 0x6c, 0x6c, 0x75, 0x70, 0x49, 0x6e, 0x74, 0x65, - 0x72, 0x76, 0x61, 0x6c, 0x12, 0x2c, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, - 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x52, 0x6f, 0x6c, - 0x6c, 0x75, 0x70, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x52, 0x6f, 0x77, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x55, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x4f, 0x3a, 0x01, 0x2a, 0x22, + 0x4a, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, + 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, + 0x72, 0x69, 0x65, 0x73, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2d, 0x76, 0x69, 0x65, + 0x77, 0x73, 0x2f, 0x7b, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x76, 0x69, 0x65, 0x77, + 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x72, 0x6f, 0x77, 0x73, 0x12, 0xd8, 0x01, 0x0a, 0x14, + 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x54, 0x69, 0x6d, 0x65, 0x52, + 0x61, 0x6e, 0x67, 0x65, 0x12, 0x2c, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, + 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, + 0x65, 0x77, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2d, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, - 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x52, 0x6f, 0x6c, 0x6c, 0x75, - 0x70, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x22, 0x52, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x4c, 0x3a, 0x01, 0x2a, 0x22, 0x47, 0x2f, 0x76, - 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x73, - 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, - 0x73, 0x2f, 0x72, 0x6f, 0x6c, 0x6c, 0x75, 0x70, 0x2d, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, - 0x6c, 0x2f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x2f, 0x7b, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, - 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x12, 0x9e, 0x01, 0x0a, 0x0a, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, - 0x54, 0x6f, 0x70, 0x4b, 0x12, 0x22, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, - 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x6f, 0x70, - 0x4b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, - 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6c, 0x75, 0x6d, - 0x6e, 0x54, 0x6f, 0x70, 0x4b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x47, 0x82, - 0xd3, 0xe4, 0x93, 0x02, 0x41, 0x3a, 0x01, 0x2a, 0x22, 0x3c, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, - 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, - 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x74, 0x6f, - 0x70, 0x6b, 0x2f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x2f, 0x7b, 0x74, 0x61, 0x62, 0x6c, 0x65, - 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x12, 0xb0, 0x01, 0x0a, 0x0f, 0x43, 0x6f, 0x6c, 0x75, 0x6d, - 0x6e, 0x4e, 0x75, 0x6c, 0x6c, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x27, 0x2e, 0x72, 0x69, 0x6c, - 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6c, - 0x75, 0x6d, 0x6e, 0x4e, 0x75, 0x6c, 0x6c, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, - 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x4e, 0x75, 0x6c, 0x6c, - 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x4a, 0x82, - 0xd3, 0xe4, 0x93, 0x02, 0x44, 0x12, 0x42, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, - 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, - 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x6e, 0x75, 0x6c, 0x6c, 0x2d, - 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x2f, 0x7b, 0x74, 0x61, - 0x62, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x12, 0xe0, 0x01, 0x0a, 0x1b, 0x43, 0x6f, - 0x6c, 0x75, 0x6d, 0x6e, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x76, 0x65, 0x53, - 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x12, 0x33, 0x2e, 0x72, 0x69, 0x6c, 0x6c, - 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6c, 0x75, - 0x6d, 0x6e, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x76, 0x65, 0x53, 0x74, 0x61, - 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x34, - 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, - 0x2e, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, - 0x76, 0x65, 0x53, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x56, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x50, 0x12, 0x4e, 0x2f, 0x76, + 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, + 0x54, 0x69, 0x6d, 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x63, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x5d, 0x3a, 0x01, 0x2a, 0x22, 0x58, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, - 0x73, 0x2f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x76, 0x65, 0x2d, 0x73, 0x74, - 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x2f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x2f, - 0x7b, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x12, 0xb9, 0x01, 0x0a, - 0x0f, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x47, 0x72, 0x61, 0x69, 0x6e, - 0x12, 0x27, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, - 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x47, 0x72, 0x61, - 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x72, 0x69, 0x6c, 0x6c, - 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6c, 0x75, - 0x6d, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x47, 0x72, 0x61, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x53, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x4d, 0x12, 0x4b, 0x2f, 0x76, 0x31, + 0x73, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2d, 0x76, 0x69, 0x65, 0x77, 0x73, 0x2f, + 0x7b, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x76, 0x69, 0x65, 0x77, 0x5f, 0x6e, 0x61, + 0x6d, 0x65, 0x7d, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x2d, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x2d, 0x73, + 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x12, 0xc0, 0x01, 0x0a, 0x11, 0x4d, 0x65, 0x74, 0x72, 0x69, + 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x29, 0x2e, 0x72, + 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, + 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, + 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, + 0x73, 0x56, 0x69, 0x65, 0x77, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x54, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x4e, 0x12, 0x4c, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, - 0x2f, 0x73, 0x6d, 0x61, 0x6c, 0x6c, 0x65, 0x73, 0x74, 0x2d, 0x74, 0x69, 0x6d, 0x65, 0x2d, 0x67, - 0x72, 0x61, 0x69, 0x6e, 0x2f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x2f, 0x7b, 0x74, 0x61, 0x62, - 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x12, 0xcc, 0x01, 0x0a, 0x16, 0x43, 0x6f, 0x6c, - 0x75, 0x6d, 0x6e, 0x4e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x67, - 0x72, 0x61, 0x6d, 0x12, 0x2e, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, - 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x4e, 0x75, 0x6d, 0x65, - 0x72, 0x69, 0x63, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, - 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x4e, 0x75, 0x6d, 0x65, - 0x72, 0x69, 0x63, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x51, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x4b, 0x12, 0x49, 0x2f, 0x76, - 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x73, - 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, - 0x73, 0x2f, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x2d, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x67, - 0x72, 0x61, 0x6d, 0x2f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x2f, 0x7b, 0x74, 0x61, 0x62, 0x6c, - 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x12, 0xbc, 0x01, 0x0a, 0x12, 0x43, 0x6f, 0x6c, 0x75, - 0x6d, 0x6e, 0x52, 0x75, 0x67, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x12, 0x2a, + 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2d, 0x76, 0x69, 0x65, 0x77, 0x73, 0x2f, 0x7b, + 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x76, 0x69, 0x65, 0x77, 0x5f, 0x6e, 0x61, 0x6d, + 0x65, 0x7d, 0x2f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0xc3, 0x01, 0x0a, 0x11, 0x4d, 0x65, + 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, + 0x29, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, + 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x53, 0x65, 0x61, + 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x72, 0x69, 0x6c, + 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, + 0x72, 0x69, 0x63, 0x73, 0x56, 0x69, 0x65, 0x77, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x57, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x51, 0x3a, 0x01, + 0x2a, 0x22, 0x4c, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, + 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x71, + 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2d, 0x76, + 0x69, 0x65, 0x77, 0x73, 0x2f, 0x7b, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x76, 0x69, + 0x65, 0x77, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, + 0xb6, 0x01, 0x0a, 0x10, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x43, 0x6f, 0x6d, 0x70, 0x6f, + 0x6e, 0x65, 0x6e, 0x74, 0x12, 0x28, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, + 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x43, 0x6f, + 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, - 0x2e, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x52, 0x75, 0x67, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x67, - 0x72, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x72, 0x69, 0x6c, - 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6c, - 0x75, 0x6d, 0x6e, 0x52, 0x75, 0x67, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x4d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x47, 0x12, - 0x45, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, - 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, - 0x72, 0x69, 0x65, 0x73, 0x2f, 0x72, 0x75, 0x67, 0x2d, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, - 0x61, 0x6d, 0x2f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x2f, 0x7b, 0x74, 0x61, 0x62, 0x6c, 0x65, - 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x12, 0xb8, 0x01, 0x0a, 0x0f, 0x43, 0x6f, 0x6c, 0x75, 0x6d, - 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x27, 0x2e, 0x72, 0x69, 0x6c, - 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6c, - 0x75, 0x6d, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, - 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x69, 0x6d, 0x65, - 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x52, 0x82, - 0xd3, 0xe4, 0x93, 0x02, 0x4c, 0x12, 0x4a, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, + 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, + 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x4d, 0x82, 0xd3, 0xe4, 0x93, 0x02, + 0x47, 0x3a, 0x01, 0x2a, 0x22, 0x42, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, + 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, + 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, + 0x65, 0x6e, 0x74, 0x73, 0x2f, 0x7b, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x7d, + 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x12, 0xc7, 0x01, 0x0a, 0x14, 0x43, 0x6f, 0x6c, + 0x75, 0x6d, 0x6e, 0x52, 0x6f, 0x6c, 0x6c, 0x75, 0x70, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, + 0x6c, 0x12, 0x2c, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, + 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x52, 0x6f, 0x6c, 0x6c, 0x75, 0x70, + 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x2d, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, + 0x31, 0x2e, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x52, 0x6f, 0x6c, 0x6c, 0x75, 0x70, 0x49, 0x6e, + 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x52, + 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x4c, 0x3a, 0x01, 0x2a, 0x22, 0x47, 0x2f, 0x76, 0x31, 0x2f, 0x69, + 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, + 0x63, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x72, + 0x6f, 0x6c, 0x6c, 0x75, 0x70, 0x2d, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x2f, 0x74, + 0x61, 0x62, 0x6c, 0x65, 0x73, 0x2f, 0x7b, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, + 0x65, 0x7d, 0x12, 0x9e, 0x01, 0x0a, 0x0a, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x6f, 0x70, + 0x4b, 0x12, 0x22, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, + 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x6f, 0x70, 0x4b, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, + 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x6f, + 0x70, 0x4b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x47, 0x82, 0xd3, 0xe4, 0x93, + 0x02, 0x41, 0x3a, 0x01, 0x2a, 0x22, 0x3c, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, - 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x2d, - 0x72, 0x61, 0x6e, 0x67, 0x65, 0x2d, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x2f, 0x74, 0x61, - 0x62, 0x6c, 0x65, 0x73, 0x2f, 0x7b, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, - 0x7d, 0x12, 0xbe, 0x01, 0x0a, 0x11, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x43, 0x61, 0x72, 0x64, - 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x12, 0x29, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, + 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x74, 0x6f, 0x70, 0x6b, 0x2f, + 0x74, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x2f, 0x7b, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6e, 0x61, + 0x6d, 0x65, 0x7d, 0x12, 0xb0, 0x01, 0x0a, 0x0f, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x4e, 0x75, + 0x6c, 0x6c, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x27, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, - 0x43, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, - 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x43, 0x61, 0x72, 0x64, 0x69, - 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x52, - 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x4c, 0x12, 0x4a, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, - 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, - 0x69, 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x63, 0x6f, 0x6c, 0x75, - 0x6d, 0x6e, 0x2d, 0x63, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x2f, 0x74, - 0x61, 0x62, 0x6c, 0x65, 0x73, 0x2f, 0x7b, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, - 0x65, 0x7d, 0x12, 0xb6, 0x01, 0x0a, 0x10, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x69, 0x6d, - 0x65, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x12, 0x28, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, + 0x4e, 0x75, 0x6c, 0x6c, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x28, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, + 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x4e, 0x75, 0x6c, 0x6c, 0x43, 0x6f, 0x75, + 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x4a, 0x82, 0xd3, 0xe4, 0x93, + 0x02, 0x44, 0x12, 0x42, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, + 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, + 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x6e, 0x75, 0x6c, 0x6c, 0x2d, 0x63, 0x6f, 0x75, + 0x6e, 0x74, 0x2f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x2f, 0x7b, 0x74, 0x61, 0x62, 0x6c, 0x65, + 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x12, 0xe0, 0x01, 0x0a, 0x1b, 0x43, 0x6f, 0x6c, 0x75, 0x6d, + 0x6e, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x76, 0x65, 0x53, 0x74, 0x61, 0x74, + 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x12, 0x33, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, + 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x44, + 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x76, 0x65, 0x53, 0x74, 0x61, 0x74, 0x69, 0x73, + 0x74, 0x69, 0x63, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x34, 0x2e, 0x72, 0x69, + 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, + 0x6c, 0x75, 0x6d, 0x6e, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x76, 0x65, 0x53, + 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x56, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x50, 0x12, 0x4e, 0x2f, 0x76, 0x31, 0x2f, 0x69, + 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, + 0x63, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x64, + 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x76, 0x65, 0x2d, 0x73, 0x74, 0x61, 0x74, 0x69, + 0x73, 0x74, 0x69, 0x63, 0x73, 0x2f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x2f, 0x7b, 0x74, 0x61, + 0x62, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x12, 0xb9, 0x01, 0x0a, 0x0f, 0x43, 0x6f, + 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x47, 0x72, 0x61, 0x69, 0x6e, 0x12, 0x27, 0x2e, + 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, + 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x47, 0x72, 0x61, 0x69, 0x6e, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, + 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, + 0x69, 0x6d, 0x65, 0x47, 0x72, 0x61, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x53, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x4d, 0x12, 0x4b, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, + 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, + 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x73, 0x6d, + 0x61, 0x6c, 0x6c, 0x65, 0x73, 0x74, 0x2d, 0x74, 0x69, 0x6d, 0x65, 0x2d, 0x67, 0x72, 0x61, 0x69, + 0x6e, 0x2f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x2f, 0x7b, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, + 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x12, 0xcc, 0x01, 0x0a, 0x16, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, + 0x4e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, + 0x12, 0x2e, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, + 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x4e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, + 0x48, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x2f, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, + 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x4e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, + 0x48, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x51, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x4b, 0x12, 0x49, 0x2f, 0x76, 0x31, 0x2f, 0x69, + 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, + 0x63, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x6e, + 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x2d, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, + 0x2f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x2f, 0x7b, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6e, + 0x61, 0x6d, 0x65, 0x7d, 0x12, 0xbc, 0x01, 0x0a, 0x12, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x52, + 0x75, 0x67, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x12, 0x2a, 0x2e, 0x72, 0x69, + 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, + 0x6c, 0x75, 0x6d, 0x6e, 0x52, 0x75, 0x67, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, - 0x54, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x29, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, - 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x53, 0x65, - 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x4d, 0x82, 0xd3, - 0xe4, 0x93, 0x02, 0x47, 0x3a, 0x01, 0x2a, 0x22, 0x42, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, - 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, - 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x74, 0x69, 0x6d, - 0x65, 0x73, 0x65, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x2f, 0x7b, - 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x12, 0xba, 0x01, 0x0a, 0x10, + 0x52, 0x75, 0x67, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x4d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x47, 0x12, 0x45, 0x2f, 0x76, + 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x73, + 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, + 0x73, 0x2f, 0x72, 0x75, 0x67, 0x2d, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x2f, + 0x74, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x2f, 0x7b, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6e, 0x61, + 0x6d, 0x65, 0x7d, 0x12, 0xb8, 0x01, 0x0a, 0x0f, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x69, + 0x6d, 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x27, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, + 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, + 0x54, 0x69, 0x6d, 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x28, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, + 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x61, 0x6e, + 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x52, 0x82, 0xd3, 0xe4, 0x93, + 0x02, 0x4c, 0x12, 0x4a, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, + 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, + 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x2d, 0x72, 0x61, 0x6e, + 0x67, 0x65, 0x2d, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x2f, 0x74, 0x61, 0x62, 0x6c, 0x65, + 0x73, 0x2f, 0x7b, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x12, 0xbe, + 0x01, 0x0a, 0x11, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x43, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x61, + 0x6c, 0x69, 0x74, 0x79, 0x12, 0x29, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, + 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x43, 0x61, 0x72, + 0x64, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x2a, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, + 0x31, 0x2e, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x43, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x6c, + 0x69, 0x74, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x52, 0x82, 0xd3, 0xe4, + 0x93, 0x02, 0x4c, 0x12, 0x4a, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, + 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x7d, + 0x2f, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x2d, + 0x63, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x2f, 0x74, 0x61, 0x62, 0x6c, + 0x65, 0x73, 0x2f, 0x7b, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x12, + 0xb6, 0x01, 0x0a, 0x10, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x53, 0x65, + 0x72, 0x69, 0x65, 0x73, 0x12, 0x28, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, + 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x69, 0x6d, + 0x65, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, + 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, + 0x2e, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x69, 0x65, + 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x4d, 0x82, 0xd3, 0xe4, 0x93, 0x02, + 0x47, 0x3a, 0x01, 0x2a, 0x22, 0x42, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, + 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, + 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x65, + 0x72, 0x69, 0x65, 0x73, 0x2f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x2f, 0x7b, 0x74, 0x61, 0x62, + 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x12, 0xba, 0x01, 0x0a, 0x10, 0x54, 0x61, 0x62, + 0x6c, 0x65, 0x43, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x12, 0x28, 0x2e, + 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, - 0x12, 0x28, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, - 0x76, 0x31, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x6c, - 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x72, 0x69, 0x6c, - 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x61, 0x62, - 0x6c, 0x65, 0x43, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x51, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x4b, 0x12, 0x49, 0x2f, - 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e, - 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x69, - 0x65, 0x73, 0x2f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x2d, 0x63, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x61, - 0x6c, 0x69, 0x74, 0x79, 0x2f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x2f, 0x7b, 0x74, 0x61, 0x62, - 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x12, 0xac, 0x01, 0x0a, 0x0c, 0x54, 0x61, 0x62, - 0x6c, 0x65, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x12, 0x24, 0x2e, 0x72, 0x69, 0x6c, 0x6c, - 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x61, 0x62, 0x6c, - 0x65, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x25, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, - 0x31, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x4f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x49, 0x22, 0x47, - 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, - 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, - 0x69, 0x65, 0x73, 0x2f, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x2d, 0x70, 0x72, 0x6f, 0x66, - 0x69, 0x6c, 0x65, 0x2f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x2f, 0x7b, 0x74, 0x61, 0x62, 0x6c, - 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x12, 0x98, 0x01, 0x0a, 0x09, 0x54, 0x61, 0x62, 0x6c, - 0x65, 0x52, 0x6f, 0x77, 0x73, 0x12, 0x21, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, + 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x43, + 0x61, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x51, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x4b, 0x12, 0x49, 0x2f, 0x76, 0x31, 0x2f, + 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, + 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x2f, + 0x74, 0x61, 0x62, 0x6c, 0x65, 0x2d, 0x63, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, + 0x79, 0x2f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x2f, 0x7b, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, + 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x12, 0xac, 0x01, 0x0a, 0x0c, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x43, + 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x12, 0x24, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, + 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x6f, + 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x72, + 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, + 0x61, 0x62, 0x6c, 0x65, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x4f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x49, 0x22, 0x47, 0x2f, 0x76, 0x31, + 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, + 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, + 0x2f, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x2d, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, + 0x2f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x2f, 0x7b, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6e, + 0x61, 0x6d, 0x65, 0x7d, 0x12, 0x98, 0x01, 0x0a, 0x09, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x6f, + 0x77, 0x73, 0x12, 0x21, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, + 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x6f, 0x77, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x6f, 0x77, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, - 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, - 0x52, 0x6f, 0x77, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x44, 0x82, 0xd3, - 0xe4, 0x93, 0x02, 0x3e, 0x12, 0x3c, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, - 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, - 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x72, 0x6f, 0x77, 0x73, 0x2f, 0x74, - 0x61, 0x62, 0x6c, 0x65, 0x73, 0x2f, 0x7b, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, - 0x65, 0x7d, 0x42, 0xbf, 0x01, 0x0a, 0x13, 0x63, 0x6f, 0x6d, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, - 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x42, 0x0c, 0x51, 0x75, 0x65, 0x72, - 0x69, 0x65, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x3c, 0x67, 0x69, 0x74, 0x68, - 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x69, 0x6c, 0x6c, 0x64, 0x61, 0x74, 0x61, 0x2f, - 0x72, 0x69, 0x6c, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x72, - 0x69, 0x6c, 0x6c, 0x2f, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2f, 0x76, 0x31, 0x3b, 0x72, - 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x52, 0x52, 0x58, 0xaa, 0x02, - 0x0f, 0x52, 0x69, 0x6c, 0x6c, 0x2e, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x56, 0x31, - 0xca, 0x02, 0x0f, 0x52, 0x69, 0x6c, 0x6c, 0x5c, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x5c, - 0x56, 0x31, 0xe2, 0x02, 0x1b, 0x52, 0x69, 0x6c, 0x6c, 0x5c, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, - 0x65, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, - 0xea, 0x02, 0x11, 0x52, 0x69, 0x6c, 0x6c, 0x3a, 0x3a, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, - 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x44, 0x82, 0xd3, 0xe4, 0x93, 0x02, + 0x3e, 0x12, 0x3c, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, + 0x2f, 0x7b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x71, + 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x72, 0x6f, 0x77, 0x73, 0x2f, 0x74, 0x61, 0x62, 0x6c, + 0x65, 0x73, 0x2f, 0x7b, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x42, + 0xbf, 0x01, 0x0a, 0x13, 0x63, 0x6f, 0x6d, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, + 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x42, 0x0c, 0x51, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, + 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x3c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x69, 0x6c, 0x6c, 0x64, 0x61, 0x74, 0x61, 0x2f, 0x72, 0x69, 0x6c, + 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x72, 0x69, 0x6c, 0x6c, + 0x2f, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2f, 0x76, 0x31, 0x3b, 0x72, 0x75, 0x6e, 0x74, + 0x69, 0x6d, 0x65, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x52, 0x52, 0x58, 0xaa, 0x02, 0x0f, 0x52, 0x69, + 0x6c, 0x6c, 0x2e, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x0f, + 0x52, 0x69, 0x6c, 0x6c, 0x5c, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x5c, 0x56, 0x31, 0xe2, + 0x02, 0x1b, 0x52, 0x69, 0x6c, 0x6c, 0x5c, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x5c, 0x56, + 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x11, + 0x52, 0x69, 0x6c, 0x6c, 0x3a, 0x3a, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x3a, 0x3a, 0x56, + 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -9708,105 +9684,103 @@ var file_rill_runtime_v1_queries_proto_depIdxs = []int32{ 103, // 129: rill.runtime.v1.MetricsViewSearchRequest.having:type_name -> rill.runtime.v1.Expression 91, // 130: rill.runtime.v1.MetricsViewSearchResponse.results:type_name -> rill.runtime.v1.MetricsViewSearchResponse.SearchResult 100, // 131: rill.runtime.v1.ResolveComponentRequest.args:type_name -> google.protobuf.Struct - 99, // 132: rill.runtime.v1.ResolveComponentResponse.schema:type_name -> rill.runtime.v1.StructType - 100, // 133: rill.runtime.v1.ResolveComponentResponse.data:type_name -> google.protobuf.Struct - 100, // 134: rill.runtime.v1.ResolveComponentResponse.renderer_properties:type_name -> google.protobuf.Struct - 102, // 135: rill.runtime.v1.ColumnRollupIntervalResponse.start:type_name -> google.protobuf.Timestamp - 102, // 136: rill.runtime.v1.ColumnRollupIntervalResponse.end:type_name -> google.protobuf.Timestamp - 104, // 137: rill.runtime.v1.ColumnRollupIntervalResponse.interval:type_name -> rill.runtime.v1.TimeGrain - 57, // 138: rill.runtime.v1.ColumnTopKResponse.categorical_summary:type_name -> rill.runtime.v1.CategoricalSummary - 58, // 139: rill.runtime.v1.CategoricalSummary.top_k:type_name -> rill.runtime.v1.TopK - 92, // 140: rill.runtime.v1.TopK.entries:type_name -> rill.runtime.v1.TopK.Entry - 63, // 141: rill.runtime.v1.ColumnDescriptiveStatisticsResponse.numeric_summary:type_name -> rill.runtime.v1.NumericSummary - 64, // 142: rill.runtime.v1.NumericSummary.numeric_histogram_bins:type_name -> rill.runtime.v1.NumericHistogramBins - 65, // 143: rill.runtime.v1.NumericSummary.numeric_statistics:type_name -> rill.runtime.v1.NumericStatistics - 66, // 144: rill.runtime.v1.NumericSummary.numeric_outliers:type_name -> rill.runtime.v1.NumericOutliers - 93, // 145: rill.runtime.v1.NumericHistogramBins.bins:type_name -> rill.runtime.v1.NumericHistogramBins.Bin - 94, // 146: rill.runtime.v1.NumericOutliers.outliers:type_name -> rill.runtime.v1.NumericOutliers.Outlier - 104, // 147: rill.runtime.v1.ColumnTimeGrainResponse.time_grain:type_name -> rill.runtime.v1.TimeGrain - 3, // 148: rill.runtime.v1.ColumnNumericHistogramRequest.histogram_method:type_name -> rill.runtime.v1.HistogramMethod - 63, // 149: rill.runtime.v1.ColumnNumericHistogramResponse.numeric_summary:type_name -> rill.runtime.v1.NumericSummary - 63, // 150: rill.runtime.v1.ColumnRugHistogramResponse.numeric_summary:type_name -> rill.runtime.v1.NumericSummary - 75, // 151: rill.runtime.v1.ColumnTimeRangeResponse.time_range_summary:type_name -> rill.runtime.v1.TimeRangeSummary - 102, // 152: rill.runtime.v1.TimeRangeSummary.min:type_name -> google.protobuf.Timestamp - 102, // 153: rill.runtime.v1.TimeRangeSummary.max:type_name -> google.protobuf.Timestamp - 95, // 154: rill.runtime.v1.TimeRangeSummary.interval:type_name -> rill.runtime.v1.TimeRangeSummary.Interval - 57, // 155: rill.runtime.v1.ColumnCardinalityResponse.categorical_summary:type_name -> rill.runtime.v1.CategoricalSummary - 96, // 156: rill.runtime.v1.ColumnTimeSeriesRequest.measures:type_name -> rill.runtime.v1.ColumnTimeSeriesRequest.BasicMeasure - 80, // 157: rill.runtime.v1.ColumnTimeSeriesRequest.time_range:type_name -> rill.runtime.v1.TimeSeriesTimeRange - 81, // 158: rill.runtime.v1.ColumnTimeSeriesResponse.rollup:type_name -> rill.runtime.v1.TimeSeriesResponse - 102, // 159: rill.runtime.v1.TimeSeriesTimeRange.start:type_name -> google.protobuf.Timestamp - 102, // 160: rill.runtime.v1.TimeSeriesTimeRange.end:type_name -> google.protobuf.Timestamp - 104, // 161: rill.runtime.v1.TimeSeriesTimeRange.interval:type_name -> rill.runtime.v1.TimeGrain - 82, // 162: rill.runtime.v1.TimeSeriesResponse.results:type_name -> rill.runtime.v1.TimeSeriesValue - 82, // 163: rill.runtime.v1.TimeSeriesResponse.spark:type_name -> rill.runtime.v1.TimeSeriesValue - 102, // 164: rill.runtime.v1.TimeSeriesValue.ts:type_name -> google.protobuf.Timestamp - 100, // 165: rill.runtime.v1.TimeSeriesValue.records:type_name -> google.protobuf.Struct - 87, // 166: rill.runtime.v1.TableColumnsResponse.profile_columns:type_name -> rill.runtime.v1.ProfileColumn - 97, // 167: rill.runtime.v1.TableColumnsResponse.unsupported_columns:type_name -> rill.runtime.v1.TableColumnsResponse.UnsupportedColumnsEntry - 100, // 168: rill.runtime.v1.TableRowsResponse.data:type_name -> google.protobuf.Struct - 98, // 169: rill.runtime.v1.MetricsViewFilter.Cond.in:type_name -> google.protobuf.Value - 98, // 170: rill.runtime.v1.MetricsViewSearchResponse.SearchResult.value:type_name -> google.protobuf.Value - 98, // 171: rill.runtime.v1.TopK.Entry.value:type_name -> google.protobuf.Value - 4, // 172: rill.runtime.v1.QueryService.Query:input_type -> rill.runtime.v1.QueryRequest - 6, // 173: rill.runtime.v1.QueryService.QueryBatch:input_type -> rill.runtime.v1.QueryBatchRequest - 8, // 174: rill.runtime.v1.QueryService.Export:input_type -> rill.runtime.v1.ExportRequest - 10, // 175: rill.runtime.v1.QueryService.ExportReport:input_type -> rill.runtime.v1.ExportReportRequest - 14, // 176: rill.runtime.v1.QueryService.MetricsViewAggregation:input_type -> rill.runtime.v1.MetricsViewAggregationRequest - 26, // 177: rill.runtime.v1.QueryService.MetricsViewToplist:input_type -> rill.runtime.v1.MetricsViewToplistRequest - 28, // 178: rill.runtime.v1.QueryService.MetricsViewComparison:input_type -> rill.runtime.v1.MetricsViewComparisonRequest - 35, // 179: rill.runtime.v1.QueryService.MetricsViewTimeSeries:input_type -> rill.runtime.v1.MetricsViewTimeSeriesRequest - 37, // 180: rill.runtime.v1.QueryService.MetricsViewTotals:input_type -> rill.runtime.v1.MetricsViewTotalsRequest - 39, // 181: rill.runtime.v1.QueryService.MetricsViewRows:input_type -> rill.runtime.v1.MetricsViewRowsRequest - 45, // 182: rill.runtime.v1.QueryService.MetricsViewTimeRange:input_type -> rill.runtime.v1.MetricsViewTimeRangeRequest - 47, // 183: rill.runtime.v1.QueryService.MetricsViewSchema:input_type -> rill.runtime.v1.MetricsViewSchemaRequest - 49, // 184: rill.runtime.v1.QueryService.MetricsViewSearch:input_type -> rill.runtime.v1.MetricsViewSearchRequest - 51, // 185: rill.runtime.v1.QueryService.ResolveComponent:input_type -> rill.runtime.v1.ResolveComponentRequest - 53, // 186: rill.runtime.v1.QueryService.ColumnRollupInterval:input_type -> rill.runtime.v1.ColumnRollupIntervalRequest - 55, // 187: rill.runtime.v1.QueryService.ColumnTopK:input_type -> rill.runtime.v1.ColumnTopKRequest - 59, // 188: rill.runtime.v1.QueryService.ColumnNullCount:input_type -> rill.runtime.v1.ColumnNullCountRequest - 61, // 189: rill.runtime.v1.QueryService.ColumnDescriptiveStatistics:input_type -> rill.runtime.v1.ColumnDescriptiveStatisticsRequest - 67, // 190: rill.runtime.v1.QueryService.ColumnTimeGrain:input_type -> rill.runtime.v1.ColumnTimeGrainRequest - 69, // 191: rill.runtime.v1.QueryService.ColumnNumericHistogram:input_type -> rill.runtime.v1.ColumnNumericHistogramRequest - 71, // 192: rill.runtime.v1.QueryService.ColumnRugHistogram:input_type -> rill.runtime.v1.ColumnRugHistogramRequest - 73, // 193: rill.runtime.v1.QueryService.ColumnTimeRange:input_type -> rill.runtime.v1.ColumnTimeRangeRequest - 76, // 194: rill.runtime.v1.QueryService.ColumnCardinality:input_type -> rill.runtime.v1.ColumnCardinalityRequest - 78, // 195: rill.runtime.v1.QueryService.ColumnTimeSeries:input_type -> rill.runtime.v1.ColumnTimeSeriesRequest - 83, // 196: rill.runtime.v1.QueryService.TableCardinality:input_type -> rill.runtime.v1.TableCardinalityRequest - 85, // 197: rill.runtime.v1.QueryService.TableColumns:input_type -> rill.runtime.v1.TableColumnsRequest - 88, // 198: rill.runtime.v1.QueryService.TableRows:input_type -> rill.runtime.v1.TableRowsRequest - 5, // 199: rill.runtime.v1.QueryService.Query:output_type -> rill.runtime.v1.QueryResponse - 7, // 200: rill.runtime.v1.QueryService.QueryBatch:output_type -> rill.runtime.v1.QueryBatchResponse - 9, // 201: rill.runtime.v1.QueryService.Export:output_type -> rill.runtime.v1.ExportResponse - 11, // 202: rill.runtime.v1.QueryService.ExportReport:output_type -> rill.runtime.v1.ExportReportResponse - 15, // 203: rill.runtime.v1.QueryService.MetricsViewAggregation:output_type -> rill.runtime.v1.MetricsViewAggregationResponse - 27, // 204: rill.runtime.v1.QueryService.MetricsViewToplist:output_type -> rill.runtime.v1.MetricsViewToplistResponse - 29, // 205: rill.runtime.v1.QueryService.MetricsViewComparison:output_type -> rill.runtime.v1.MetricsViewComparisonResponse - 36, // 206: rill.runtime.v1.QueryService.MetricsViewTimeSeries:output_type -> rill.runtime.v1.MetricsViewTimeSeriesResponse - 38, // 207: rill.runtime.v1.QueryService.MetricsViewTotals:output_type -> rill.runtime.v1.MetricsViewTotalsResponse - 40, // 208: rill.runtime.v1.QueryService.MetricsViewRows:output_type -> rill.runtime.v1.MetricsViewRowsResponse - 46, // 209: rill.runtime.v1.QueryService.MetricsViewTimeRange:output_type -> rill.runtime.v1.MetricsViewTimeRangeResponse - 48, // 210: rill.runtime.v1.QueryService.MetricsViewSchema:output_type -> rill.runtime.v1.MetricsViewSchemaResponse - 50, // 211: rill.runtime.v1.QueryService.MetricsViewSearch:output_type -> rill.runtime.v1.MetricsViewSearchResponse - 52, // 212: rill.runtime.v1.QueryService.ResolveComponent:output_type -> rill.runtime.v1.ResolveComponentResponse - 54, // 213: rill.runtime.v1.QueryService.ColumnRollupInterval:output_type -> rill.runtime.v1.ColumnRollupIntervalResponse - 56, // 214: rill.runtime.v1.QueryService.ColumnTopK:output_type -> rill.runtime.v1.ColumnTopKResponse - 60, // 215: rill.runtime.v1.QueryService.ColumnNullCount:output_type -> rill.runtime.v1.ColumnNullCountResponse - 62, // 216: rill.runtime.v1.QueryService.ColumnDescriptiveStatistics:output_type -> rill.runtime.v1.ColumnDescriptiveStatisticsResponse - 68, // 217: rill.runtime.v1.QueryService.ColumnTimeGrain:output_type -> rill.runtime.v1.ColumnTimeGrainResponse - 70, // 218: rill.runtime.v1.QueryService.ColumnNumericHistogram:output_type -> rill.runtime.v1.ColumnNumericHistogramResponse - 72, // 219: rill.runtime.v1.QueryService.ColumnRugHistogram:output_type -> rill.runtime.v1.ColumnRugHistogramResponse - 74, // 220: rill.runtime.v1.QueryService.ColumnTimeRange:output_type -> rill.runtime.v1.ColumnTimeRangeResponse - 77, // 221: rill.runtime.v1.QueryService.ColumnCardinality:output_type -> rill.runtime.v1.ColumnCardinalityResponse - 79, // 222: rill.runtime.v1.QueryService.ColumnTimeSeries:output_type -> rill.runtime.v1.ColumnTimeSeriesResponse - 84, // 223: rill.runtime.v1.QueryService.TableCardinality:output_type -> rill.runtime.v1.TableCardinalityResponse - 86, // 224: rill.runtime.v1.QueryService.TableColumns:output_type -> rill.runtime.v1.TableColumnsResponse - 89, // 225: rill.runtime.v1.QueryService.TableRows:output_type -> rill.runtime.v1.TableRowsResponse - 199, // [199:226] is the sub-list for method output_type - 172, // [172:199] is the sub-list for method input_type - 172, // [172:172] is the sub-list for extension type_name - 172, // [172:172] is the sub-list for extension extendee - 0, // [0:172] is the sub-list for field type_name + 100, // 132: rill.runtime.v1.ResolveComponentResponse.renderer_properties:type_name -> google.protobuf.Struct + 102, // 133: rill.runtime.v1.ColumnRollupIntervalResponse.start:type_name -> google.protobuf.Timestamp + 102, // 134: rill.runtime.v1.ColumnRollupIntervalResponse.end:type_name -> google.protobuf.Timestamp + 104, // 135: rill.runtime.v1.ColumnRollupIntervalResponse.interval:type_name -> rill.runtime.v1.TimeGrain + 57, // 136: rill.runtime.v1.ColumnTopKResponse.categorical_summary:type_name -> rill.runtime.v1.CategoricalSummary + 58, // 137: rill.runtime.v1.CategoricalSummary.top_k:type_name -> rill.runtime.v1.TopK + 92, // 138: rill.runtime.v1.TopK.entries:type_name -> rill.runtime.v1.TopK.Entry + 63, // 139: rill.runtime.v1.ColumnDescriptiveStatisticsResponse.numeric_summary:type_name -> rill.runtime.v1.NumericSummary + 64, // 140: rill.runtime.v1.NumericSummary.numeric_histogram_bins:type_name -> rill.runtime.v1.NumericHistogramBins + 65, // 141: rill.runtime.v1.NumericSummary.numeric_statistics:type_name -> rill.runtime.v1.NumericStatistics + 66, // 142: rill.runtime.v1.NumericSummary.numeric_outliers:type_name -> rill.runtime.v1.NumericOutliers + 93, // 143: rill.runtime.v1.NumericHistogramBins.bins:type_name -> rill.runtime.v1.NumericHistogramBins.Bin + 94, // 144: rill.runtime.v1.NumericOutliers.outliers:type_name -> rill.runtime.v1.NumericOutliers.Outlier + 104, // 145: rill.runtime.v1.ColumnTimeGrainResponse.time_grain:type_name -> rill.runtime.v1.TimeGrain + 3, // 146: rill.runtime.v1.ColumnNumericHistogramRequest.histogram_method:type_name -> rill.runtime.v1.HistogramMethod + 63, // 147: rill.runtime.v1.ColumnNumericHistogramResponse.numeric_summary:type_name -> rill.runtime.v1.NumericSummary + 63, // 148: rill.runtime.v1.ColumnRugHistogramResponse.numeric_summary:type_name -> rill.runtime.v1.NumericSummary + 75, // 149: rill.runtime.v1.ColumnTimeRangeResponse.time_range_summary:type_name -> rill.runtime.v1.TimeRangeSummary + 102, // 150: rill.runtime.v1.TimeRangeSummary.min:type_name -> google.protobuf.Timestamp + 102, // 151: rill.runtime.v1.TimeRangeSummary.max:type_name -> google.protobuf.Timestamp + 95, // 152: rill.runtime.v1.TimeRangeSummary.interval:type_name -> rill.runtime.v1.TimeRangeSummary.Interval + 57, // 153: rill.runtime.v1.ColumnCardinalityResponse.categorical_summary:type_name -> rill.runtime.v1.CategoricalSummary + 96, // 154: rill.runtime.v1.ColumnTimeSeriesRequest.measures:type_name -> rill.runtime.v1.ColumnTimeSeriesRequest.BasicMeasure + 80, // 155: rill.runtime.v1.ColumnTimeSeriesRequest.time_range:type_name -> rill.runtime.v1.TimeSeriesTimeRange + 81, // 156: rill.runtime.v1.ColumnTimeSeriesResponse.rollup:type_name -> rill.runtime.v1.TimeSeriesResponse + 102, // 157: rill.runtime.v1.TimeSeriesTimeRange.start:type_name -> google.protobuf.Timestamp + 102, // 158: rill.runtime.v1.TimeSeriesTimeRange.end:type_name -> google.protobuf.Timestamp + 104, // 159: rill.runtime.v1.TimeSeriesTimeRange.interval:type_name -> rill.runtime.v1.TimeGrain + 82, // 160: rill.runtime.v1.TimeSeriesResponse.results:type_name -> rill.runtime.v1.TimeSeriesValue + 82, // 161: rill.runtime.v1.TimeSeriesResponse.spark:type_name -> rill.runtime.v1.TimeSeriesValue + 102, // 162: rill.runtime.v1.TimeSeriesValue.ts:type_name -> google.protobuf.Timestamp + 100, // 163: rill.runtime.v1.TimeSeriesValue.records:type_name -> google.protobuf.Struct + 87, // 164: rill.runtime.v1.TableColumnsResponse.profile_columns:type_name -> rill.runtime.v1.ProfileColumn + 97, // 165: rill.runtime.v1.TableColumnsResponse.unsupported_columns:type_name -> rill.runtime.v1.TableColumnsResponse.UnsupportedColumnsEntry + 100, // 166: rill.runtime.v1.TableRowsResponse.data:type_name -> google.protobuf.Struct + 98, // 167: rill.runtime.v1.MetricsViewFilter.Cond.in:type_name -> google.protobuf.Value + 98, // 168: rill.runtime.v1.MetricsViewSearchResponse.SearchResult.value:type_name -> google.protobuf.Value + 98, // 169: rill.runtime.v1.TopK.Entry.value:type_name -> google.protobuf.Value + 4, // 170: rill.runtime.v1.QueryService.Query:input_type -> rill.runtime.v1.QueryRequest + 6, // 171: rill.runtime.v1.QueryService.QueryBatch:input_type -> rill.runtime.v1.QueryBatchRequest + 8, // 172: rill.runtime.v1.QueryService.Export:input_type -> rill.runtime.v1.ExportRequest + 10, // 173: rill.runtime.v1.QueryService.ExportReport:input_type -> rill.runtime.v1.ExportReportRequest + 14, // 174: rill.runtime.v1.QueryService.MetricsViewAggregation:input_type -> rill.runtime.v1.MetricsViewAggregationRequest + 26, // 175: rill.runtime.v1.QueryService.MetricsViewToplist:input_type -> rill.runtime.v1.MetricsViewToplistRequest + 28, // 176: rill.runtime.v1.QueryService.MetricsViewComparison:input_type -> rill.runtime.v1.MetricsViewComparisonRequest + 35, // 177: rill.runtime.v1.QueryService.MetricsViewTimeSeries:input_type -> rill.runtime.v1.MetricsViewTimeSeriesRequest + 37, // 178: rill.runtime.v1.QueryService.MetricsViewTotals:input_type -> rill.runtime.v1.MetricsViewTotalsRequest + 39, // 179: rill.runtime.v1.QueryService.MetricsViewRows:input_type -> rill.runtime.v1.MetricsViewRowsRequest + 45, // 180: rill.runtime.v1.QueryService.MetricsViewTimeRange:input_type -> rill.runtime.v1.MetricsViewTimeRangeRequest + 47, // 181: rill.runtime.v1.QueryService.MetricsViewSchema:input_type -> rill.runtime.v1.MetricsViewSchemaRequest + 49, // 182: rill.runtime.v1.QueryService.MetricsViewSearch:input_type -> rill.runtime.v1.MetricsViewSearchRequest + 51, // 183: rill.runtime.v1.QueryService.ResolveComponent:input_type -> rill.runtime.v1.ResolveComponentRequest + 53, // 184: rill.runtime.v1.QueryService.ColumnRollupInterval:input_type -> rill.runtime.v1.ColumnRollupIntervalRequest + 55, // 185: rill.runtime.v1.QueryService.ColumnTopK:input_type -> rill.runtime.v1.ColumnTopKRequest + 59, // 186: rill.runtime.v1.QueryService.ColumnNullCount:input_type -> rill.runtime.v1.ColumnNullCountRequest + 61, // 187: rill.runtime.v1.QueryService.ColumnDescriptiveStatistics:input_type -> rill.runtime.v1.ColumnDescriptiveStatisticsRequest + 67, // 188: rill.runtime.v1.QueryService.ColumnTimeGrain:input_type -> rill.runtime.v1.ColumnTimeGrainRequest + 69, // 189: rill.runtime.v1.QueryService.ColumnNumericHistogram:input_type -> rill.runtime.v1.ColumnNumericHistogramRequest + 71, // 190: rill.runtime.v1.QueryService.ColumnRugHistogram:input_type -> rill.runtime.v1.ColumnRugHistogramRequest + 73, // 191: rill.runtime.v1.QueryService.ColumnTimeRange:input_type -> rill.runtime.v1.ColumnTimeRangeRequest + 76, // 192: rill.runtime.v1.QueryService.ColumnCardinality:input_type -> rill.runtime.v1.ColumnCardinalityRequest + 78, // 193: rill.runtime.v1.QueryService.ColumnTimeSeries:input_type -> rill.runtime.v1.ColumnTimeSeriesRequest + 83, // 194: rill.runtime.v1.QueryService.TableCardinality:input_type -> rill.runtime.v1.TableCardinalityRequest + 85, // 195: rill.runtime.v1.QueryService.TableColumns:input_type -> rill.runtime.v1.TableColumnsRequest + 88, // 196: rill.runtime.v1.QueryService.TableRows:input_type -> rill.runtime.v1.TableRowsRequest + 5, // 197: rill.runtime.v1.QueryService.Query:output_type -> rill.runtime.v1.QueryResponse + 7, // 198: rill.runtime.v1.QueryService.QueryBatch:output_type -> rill.runtime.v1.QueryBatchResponse + 9, // 199: rill.runtime.v1.QueryService.Export:output_type -> rill.runtime.v1.ExportResponse + 11, // 200: rill.runtime.v1.QueryService.ExportReport:output_type -> rill.runtime.v1.ExportReportResponse + 15, // 201: rill.runtime.v1.QueryService.MetricsViewAggregation:output_type -> rill.runtime.v1.MetricsViewAggregationResponse + 27, // 202: rill.runtime.v1.QueryService.MetricsViewToplist:output_type -> rill.runtime.v1.MetricsViewToplistResponse + 29, // 203: rill.runtime.v1.QueryService.MetricsViewComparison:output_type -> rill.runtime.v1.MetricsViewComparisonResponse + 36, // 204: rill.runtime.v1.QueryService.MetricsViewTimeSeries:output_type -> rill.runtime.v1.MetricsViewTimeSeriesResponse + 38, // 205: rill.runtime.v1.QueryService.MetricsViewTotals:output_type -> rill.runtime.v1.MetricsViewTotalsResponse + 40, // 206: rill.runtime.v1.QueryService.MetricsViewRows:output_type -> rill.runtime.v1.MetricsViewRowsResponse + 46, // 207: rill.runtime.v1.QueryService.MetricsViewTimeRange:output_type -> rill.runtime.v1.MetricsViewTimeRangeResponse + 48, // 208: rill.runtime.v1.QueryService.MetricsViewSchema:output_type -> rill.runtime.v1.MetricsViewSchemaResponse + 50, // 209: rill.runtime.v1.QueryService.MetricsViewSearch:output_type -> rill.runtime.v1.MetricsViewSearchResponse + 52, // 210: rill.runtime.v1.QueryService.ResolveComponent:output_type -> rill.runtime.v1.ResolveComponentResponse + 54, // 211: rill.runtime.v1.QueryService.ColumnRollupInterval:output_type -> rill.runtime.v1.ColumnRollupIntervalResponse + 56, // 212: rill.runtime.v1.QueryService.ColumnTopK:output_type -> rill.runtime.v1.ColumnTopKResponse + 60, // 213: rill.runtime.v1.QueryService.ColumnNullCount:output_type -> rill.runtime.v1.ColumnNullCountResponse + 62, // 214: rill.runtime.v1.QueryService.ColumnDescriptiveStatistics:output_type -> rill.runtime.v1.ColumnDescriptiveStatisticsResponse + 68, // 215: rill.runtime.v1.QueryService.ColumnTimeGrain:output_type -> rill.runtime.v1.ColumnTimeGrainResponse + 70, // 216: rill.runtime.v1.QueryService.ColumnNumericHistogram:output_type -> rill.runtime.v1.ColumnNumericHistogramResponse + 72, // 217: rill.runtime.v1.QueryService.ColumnRugHistogram:output_type -> rill.runtime.v1.ColumnRugHistogramResponse + 74, // 218: rill.runtime.v1.QueryService.ColumnTimeRange:output_type -> rill.runtime.v1.ColumnTimeRangeResponse + 77, // 219: rill.runtime.v1.QueryService.ColumnCardinality:output_type -> rill.runtime.v1.ColumnCardinalityResponse + 79, // 220: rill.runtime.v1.QueryService.ColumnTimeSeries:output_type -> rill.runtime.v1.ColumnTimeSeriesResponse + 84, // 221: rill.runtime.v1.QueryService.TableCardinality:output_type -> rill.runtime.v1.TableCardinalityResponse + 86, // 222: rill.runtime.v1.QueryService.TableColumns:output_type -> rill.runtime.v1.TableColumnsResponse + 89, // 223: rill.runtime.v1.QueryService.TableRows:output_type -> rill.runtime.v1.TableRowsResponse + 197, // [197:224] is the sub-list for method output_type + 170, // [170:197] is the sub-list for method input_type + 170, // [170:170] is the sub-list for extension type_name + 170, // [170:170] is the sub-list for extension extendee + 0, // [0:170] is the sub-list for field type_name } func init() { file_rill_runtime_v1_queries_proto_init() } diff --git a/proto/gen/rill/runtime/v1/queries.pb.validate.go b/proto/gen/rill/runtime/v1/queries.pb.validate.go index 21ec60d8e96..5ce1e8a07f5 100644 --- a/proto/gen/rill/runtime/v1/queries.pb.validate.go +++ b/proto/gen/rill/runtime/v1/queries.pb.validate.go @@ -9733,69 +9733,6 @@ func (m *ResolveComponentResponse) validate(all bool) error { // no validation rules for Show - if all { - switch v := interface{}(m.GetSchema()).(type) { - case interface{ ValidateAll() error }: - if err := v.ValidateAll(); err != nil { - errors = append(errors, ResolveComponentResponseValidationError{ - field: "Schema", - reason: "embedded message failed validation", - cause: err, - }) - } - case interface{ Validate() error }: - if err := v.Validate(); err != nil { - errors = append(errors, ResolveComponentResponseValidationError{ - field: "Schema", - reason: "embedded message failed validation", - cause: err, - }) - } - } - } else if v, ok := interface{}(m.GetSchema()).(interface{ Validate() error }); ok { - if err := v.Validate(); err != nil { - return ResolveComponentResponseValidationError{ - field: "Schema", - reason: "embedded message failed validation", - cause: err, - } - } - } - - for idx, item := range m.GetData() { - _, _ = idx, item - - if all { - switch v := interface{}(item).(type) { - case interface{ ValidateAll() error }: - if err := v.ValidateAll(); err != nil { - errors = append(errors, ResolveComponentResponseValidationError{ - field: fmt.Sprintf("Data[%v]", idx), - reason: "embedded message failed validation", - cause: err, - }) - } - case interface{ Validate() error }: - if err := v.Validate(); err != nil { - errors = append(errors, ResolveComponentResponseValidationError{ - field: fmt.Sprintf("Data[%v]", idx), - reason: "embedded message failed validation", - cause: err, - }) - } - } - } else if v, ok := interface{}(item).(interface{ Validate() error }); ok { - if err := v.Validate(); err != nil { - return ResolveComponentResponseValidationError{ - field: fmt.Sprintf("Data[%v]", idx), - reason: "embedded message failed validation", - cause: err, - } - } - } - - } - if all { switch v := interface{}(m.GetRendererProperties()).(type) { case interface{ ValidateAll() error }: diff --git a/proto/gen/rill/runtime/v1/resources.pb.go b/proto/gen/rill/runtime/v1/resources.pb.go index c0bbc96b3d2..a4446cba4a6 100644 --- a/proto/gen/rill/runtime/v1/resources.pb.go +++ b/proto/gen/rill/runtime/v1/resources.pb.go @@ -5088,8 +5088,6 @@ type ComponentSpec struct { DisplayName string `protobuf:"bytes,1,opt,name=display_name,json=displayName,proto3" json:"display_name,omitempty"` Description string `protobuf:"bytes,7,opt,name=description,proto3" json:"description,omitempty"` - Resolver string `protobuf:"bytes,2,opt,name=resolver,proto3" json:"resolver,omitempty"` - ResolverProperties *structpb.Struct `protobuf:"bytes,3,opt,name=resolver_properties,json=resolverProperties,proto3" json:"resolver_properties,omitempty"` Renderer string `protobuf:"bytes,4,opt,name=renderer,proto3" json:"renderer,omitempty"` RendererProperties *structpb.Struct `protobuf:"bytes,5,opt,name=renderer_properties,json=rendererProperties,proto3" json:"renderer_properties,omitempty"` Input []*ComponentVariable `protobuf:"bytes,8,rep,name=input,proto3" json:"input,omitempty"` @@ -5144,20 +5142,6 @@ func (x *ComponentSpec) GetDescription() string { return "" } -func (x *ComponentSpec) GetResolver() string { - if x != nil { - return x.Resolver - } - return "" -} - -func (x *ComponentSpec) GetResolverProperties() *structpb.Struct { - if x != nil { - return x.ResolverProperties - } - return nil -} - func (x *ComponentSpec) GetRenderer() string { if x != nil { return x.Renderer @@ -5371,8 +5355,9 @@ type CanvasSpec struct { unknownFields protoimpl.UnknownFields DisplayName string `protobuf:"bytes,1,opt,name=display_name,json=displayName,proto3" json:"display_name,omitempty"` - Columns uint32 `protobuf:"varint,2,opt,name=columns,proto3" json:"columns,omitempty"` - Gap uint32 `protobuf:"varint,3,opt,name=gap,proto3" json:"gap,omitempty"` + MaxWidth uint32 `protobuf:"varint,2,opt,name=max_width,json=maxWidth,proto3" json:"max_width,omitempty"` + Theme string `protobuf:"bytes,7,opt,name=theme,proto3" json:"theme,omitempty"` + EmbeddedTheme *ThemeSpec `protobuf:"bytes,8,opt,name=embedded_theme,json=embeddedTheme,proto3" json:"embedded_theme,omitempty"` Variables []*ComponentVariable `protobuf:"bytes,5,rep,name=variables,proto3" json:"variables,omitempty"` Items []*CanvasItem `protobuf:"bytes,4,rep,name=items,proto3" json:"items,omitempty"` SecurityRules []*SecurityRule `protobuf:"bytes,6,rep,name=security_rules,json=securityRules,proto3" json:"security_rules,omitempty"` @@ -5417,18 +5402,25 @@ func (x *CanvasSpec) GetDisplayName() string { return "" } -func (x *CanvasSpec) GetColumns() uint32 { +func (x *CanvasSpec) GetMaxWidth() uint32 { if x != nil { - return x.Columns + return x.MaxWidth } return 0 } -func (x *CanvasSpec) GetGap() uint32 { +func (x *CanvasSpec) GetTheme() string { if x != nil { - return x.Gap + return x.Theme } - return 0 + return "" +} + +func (x *CanvasSpec) GetEmbeddedTheme() *ThemeSpec { + if x != nil { + return x.EmbeddedTheme + } + return nil } func (x *CanvasSpec) GetVariables() []*ComponentVariable { @@ -7872,263 +7864,261 @@ var file_rill_runtime_v1_resources_proto_rawDesc = []byte{ 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, - 0x65, 0x22, 0xd6, 0x03, 0x0a, 0x0d, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x53, + 0x65, 0x22, 0xf0, 0x02, 0x0a, 0x0d, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x53, 0x70, 0x65, 0x63, 0x12, 0x21, 0x0a, 0x0c, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, - 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, - 0x6c, 0x76, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x73, 0x6f, - 0x6c, 0x76, 0x65, 0x72, 0x12, 0x48, 0x0a, 0x13, 0x72, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x72, - 0x5f, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x6e, 0x64, + 0x65, 0x72, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x6e, 0x64, + 0x65, 0x72, 0x65, 0x72, 0x12, 0x48, 0x0a, 0x13, 0x72, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x65, 0x72, + 0x5f, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x12, 0x72, 0x65, 0x73, 0x6f, - 0x6c, 0x76, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x12, 0x1a, - 0x0a, 0x08, 0x72, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x08, 0x72, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x65, 0x72, 0x12, 0x48, 0x0a, 0x13, 0x72, 0x65, - 0x6e, 0x64, 0x65, 0x72, 0x65, 0x72, 0x5f, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, - 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, - 0x52, 0x12, 0x72, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, - 0x74, 0x69, 0x65, 0x73, 0x12, 0x38, 0x0a, 0x05, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x18, 0x08, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, - 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x56, - 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x05, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x12, 0x3a, - 0x0a, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, - 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, - 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, - 0x6c, 0x65, 0x52, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x68, - 0x6f, 0x77, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x73, 0x68, 0x6f, 0x77, 0x12, 0x2a, - 0x0a, 0x11, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x5f, 0x69, 0x6e, 0x5f, 0x63, 0x61, 0x6e, - 0x76, 0x61, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x64, 0x65, 0x66, 0x69, 0x6e, - 0x65, 0x64, 0x49, 0x6e, 0x43, 0x61, 0x6e, 0x76, 0x61, 0x73, 0x22, 0x4f, 0x0a, 0x0e, 0x43, 0x6f, - 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x3d, 0x0a, 0x0a, - 0x76, 0x61, 0x6c, 0x69, 0x64, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x1e, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, - 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x53, 0x70, 0x65, 0x63, - 0x52, 0x09, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x53, 0x70, 0x65, 0x63, 0x22, 0x78, 0x0a, 0x11, 0x43, - 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, - 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, - 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x3b, 0x0a, 0x0d, 0x64, 0x65, 0x66, 0x61, - 0x75, 0x6c, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, - 0x66, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0c, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, - 0x56, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x6d, 0x0a, 0x06, 0x43, 0x61, 0x6e, 0x76, 0x61, 0x73, 0x12, - 0x2f, 0x0a, 0x04, 0x73, 0x70, 0x65, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, + 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x12, 0x72, 0x65, 0x6e, 0x64, + 0x65, 0x72, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x12, 0x38, + 0x0a, 0x05, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, - 0x43, 0x61, 0x6e, 0x76, 0x61, 0x73, 0x53, 0x70, 0x65, 0x63, 0x52, 0x04, 0x73, 0x70, 0x65, 0x63, - 0x12, 0x32, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x1c, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, - 0x31, 0x2e, 0x43, 0x61, 0x6e, 0x76, 0x61, 0x73, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, - 0x74, 0x61, 0x74, 0x65, 0x22, 0x96, 0x02, 0x0a, 0x0a, 0x43, 0x61, 0x6e, 0x76, 0x61, 0x73, 0x53, - 0x70, 0x65, 0x63, 0x12, 0x21, 0x0a, 0x0c, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x6e, - 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, - 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, - 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, - 0x12, 0x10, 0x0a, 0x03, 0x67, 0x61, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x67, - 0x61, 0x70, 0x12, 0x40, 0x0a, 0x09, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x18, - 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, - 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, - 0x74, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x09, 0x76, 0x61, 0x72, 0x69, 0x61, - 0x62, 0x6c, 0x65, 0x73, 0x12, 0x31, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x04, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, - 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x61, 0x6e, 0x76, 0x61, 0x73, 0x49, 0x74, 0x65, 0x6d, - 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x12, 0x44, 0x0a, 0x0e, 0x73, 0x65, 0x63, 0x75, 0x72, - 0x69, 0x74, 0x79, 0x5f, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x1d, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, - 0x31, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x0d, - 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x22, 0x49, 0x0a, - 0x0b, 0x43, 0x61, 0x6e, 0x76, 0x61, 0x73, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x3a, 0x0a, 0x0a, - 0x76, 0x61, 0x6c, 0x69, 0x64, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x1b, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, - 0x76, 0x31, 0x2e, 0x43, 0x61, 0x6e, 0x76, 0x61, 0x73, 0x53, 0x70, 0x65, 0x63, 0x52, 0x09, 0x76, - 0x61, 0x6c, 0x69, 0x64, 0x53, 0x70, 0x65, 0x63, 0x22, 0xd5, 0x01, 0x0a, 0x0a, 0x43, 0x61, 0x6e, - 0x76, 0x61, 0x73, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6f, 0x6d, 0x70, 0x6f, - 0x6e, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6f, 0x6d, 0x70, - 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x12, 0x2a, 0x0a, 0x11, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, - 0x5f, 0x69, 0x6e, 0x5f, 0x63, 0x61, 0x6e, 0x76, 0x61, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x0f, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x49, 0x6e, 0x43, 0x61, 0x6e, 0x76, 0x61, - 0x73, 0x12, 0x11, 0x0a, 0x01, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x48, 0x00, 0x52, 0x01, - 0x78, 0x88, 0x01, 0x01, 0x12, 0x11, 0x0a, 0x01, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x48, - 0x01, 0x52, 0x01, 0x79, 0x88, 0x01, 0x01, 0x12, 0x19, 0x0a, 0x05, 0x77, 0x69, 0x64, 0x74, 0x68, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x48, 0x02, 0x52, 0x05, 0x77, 0x69, 0x64, 0x74, 0x68, 0x88, - 0x01, 0x01, 0x12, 0x1b, 0x0a, 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x05, 0x20, 0x01, - 0x28, 0x0d, 0x48, 0x03, 0x52, 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x88, 0x01, 0x01, 0x42, - 0x04, 0x0a, 0x02, 0x5f, 0x78, 0x42, 0x04, 0x0a, 0x02, 0x5f, 0x79, 0x42, 0x08, 0x0a, 0x06, 0x5f, - 0x77, 0x69, 0x64, 0x74, 0x68, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, - 0x22, 0x64, 0x0a, 0x03, 0x41, 0x50, 0x49, 0x12, 0x2c, 0x0a, 0x04, 0x73, 0x70, 0x65, 0x63, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, - 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x50, 0x49, 0x53, 0x70, 0x65, 0x63, 0x52, - 0x04, 0x73, 0x70, 0x65, 0x63, 0x12, 0x2f, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, - 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x50, 0x49, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, - 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x22, 0xb1, 0x02, 0x0a, 0x07, 0x41, 0x50, 0x49, 0x53, 0x70, - 0x65, 0x63, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x72, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x72, 0x12, 0x48, - 0x0a, 0x13, 0x72, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x72, 0x5f, 0x70, 0x72, 0x6f, 0x70, 0x65, - 0x72, 0x74, 0x69, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, - 0x72, 0x75, 0x63, 0x74, 0x52, 0x12, 0x72, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x72, 0x50, 0x72, - 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x6f, 0x70, 0x65, 0x6e, - 0x61, 0x70, 0x69, 0x5f, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0e, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, - 0x79, 0x12, 0x46, 0x0a, 0x12, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x5f, 0x70, 0x61, 0x72, - 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, - 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, - 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x11, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x50, - 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x12, 0x4f, 0x0a, 0x17, 0x6f, 0x70, 0x65, - 0x6e, 0x61, 0x70, 0x69, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x5f, 0x73, 0x63, - 0x68, 0x65, 0x6d, 0x61, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, - 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, - 0x75, 0x63, 0x74, 0x52, 0x15, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x22, 0x0a, 0x0a, 0x08, 0x41, 0x50, - 0x49, 0x53, 0x74, 0x61, 0x74, 0x65, 0x22, 0x9b, 0x01, 0x0a, 0x08, 0x53, 0x63, 0x68, 0x65, 0x64, - 0x75, 0x6c, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x66, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, - 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x72, 0x65, 0x66, 0x55, 0x70, 0x64, 0x61, - 0x74, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x05, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x07, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, - 0x63, 0x72, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x63, 0x72, 0x6f, 0x6e, - 0x12, 0x25, 0x0a, 0x0e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x63, 0x6f, 0x6e, - 0x64, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0d, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x72, - 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x5f, - 0x7a, 0x6f, 0x6e, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x69, 0x6d, 0x65, - 0x5a, 0x6f, 0x6e, 0x65, 0x22, 0xa5, 0x01, 0x0a, 0x0a, 0x50, 0x61, 0x72, 0x73, 0x65, 0x45, 0x72, + 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, + 0x65, 0x52, 0x05, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x12, 0x3a, 0x0a, 0x06, 0x6f, 0x75, 0x74, 0x70, + 0x75, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, + 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x6f, + 0x6e, 0x65, 0x6e, 0x74, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x06, 0x6f, 0x75, + 0x74, 0x70, 0x75, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x68, 0x6f, 0x77, 0x18, 0x0a, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x73, 0x68, 0x6f, 0x77, 0x12, 0x2a, 0x0a, 0x11, 0x64, 0x65, 0x66, 0x69, + 0x6e, 0x65, 0x64, 0x5f, 0x69, 0x6e, 0x5f, 0x63, 0x61, 0x6e, 0x76, 0x61, 0x73, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x0f, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x49, 0x6e, 0x43, 0x61, + 0x6e, 0x76, 0x61, 0x73, 0x22, 0x4f, 0x0a, 0x0e, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, + 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x3d, 0x0a, 0x0a, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x5f, + 0x73, 0x70, 0x65, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x72, 0x69, 0x6c, + 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, + 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x53, 0x70, 0x65, 0x63, 0x52, 0x09, 0x76, 0x61, 0x6c, 0x69, + 0x64, 0x53, 0x70, 0x65, 0x63, 0x22, 0x78, 0x0a, 0x11, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, + 0x6e, 0x74, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, + 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, + 0x70, 0x65, 0x12, 0x3b, 0x0a, 0x0d, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x56, 0x61, 0x6c, 0x75, + 0x65, 0x52, 0x0c, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x22, + 0x6d, 0x0a, 0x06, 0x43, 0x61, 0x6e, 0x76, 0x61, 0x73, 0x12, 0x2f, 0x0a, 0x04, 0x73, 0x70, 0x65, + 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, + 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x61, 0x6e, 0x76, 0x61, 0x73, + 0x53, 0x70, 0x65, 0x63, 0x52, 0x04, 0x73, 0x70, 0x65, 0x63, 0x12, 0x32, 0x0a, 0x05, 0x73, 0x74, + 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x72, 0x69, 0x6c, 0x6c, + 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x61, 0x6e, 0x76, + 0x61, 0x73, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x22, 0xe0, + 0x02, 0x0a, 0x0a, 0x43, 0x61, 0x6e, 0x76, 0x61, 0x73, 0x53, 0x70, 0x65, 0x63, 0x12, 0x21, 0x0a, + 0x0c, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, + 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x61, 0x78, 0x5f, 0x77, 0x69, 0x64, 0x74, 0x68, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0d, 0x52, 0x08, 0x6d, 0x61, 0x78, 0x57, 0x69, 0x64, 0x74, 0x68, 0x12, 0x14, 0x0a, + 0x05, 0x74, 0x68, 0x65, 0x6d, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x68, + 0x65, 0x6d, 0x65, 0x12, 0x41, 0x0a, 0x0e, 0x65, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x5f, + 0x74, 0x68, 0x65, 0x6d, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x72, 0x69, + 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x68, + 0x65, 0x6d, 0x65, 0x53, 0x70, 0x65, 0x63, 0x52, 0x0d, 0x65, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, + 0x64, 0x54, 0x68, 0x65, 0x6d, 0x65, 0x12, 0x40, 0x0a, 0x09, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, + 0x6c, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x72, 0x69, 0x6c, 0x6c, + 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x70, + 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x09, 0x76, + 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x12, 0x31, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, + 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, + 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x61, 0x6e, 0x76, 0x61, 0x73, + 0x49, 0x74, 0x65, 0x6d, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x12, 0x44, 0x0a, 0x0e, 0x73, + 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x5f, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x06, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, + 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x52, 0x75, + 0x6c, 0x65, 0x52, 0x0d, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x52, 0x75, 0x6c, 0x65, + 0x73, 0x22, 0x49, 0x0a, 0x0b, 0x43, 0x61, 0x6e, 0x76, 0x61, 0x73, 0x53, 0x74, 0x61, 0x74, 0x65, + 0x12, 0x3a, 0x0a, 0x0a, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, + 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x61, 0x6e, 0x76, 0x61, 0x73, 0x53, 0x70, 0x65, + 0x63, 0x52, 0x09, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x53, 0x70, 0x65, 0x63, 0x22, 0xd5, 0x01, 0x0a, + 0x0a, 0x43, 0x61, 0x6e, 0x76, 0x61, 0x73, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x1c, 0x0a, 0x09, 0x63, + 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, + 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x12, 0x2a, 0x0a, 0x11, 0x64, 0x65, 0x66, + 0x69, 0x6e, 0x65, 0x64, 0x5f, 0x69, 0x6e, 0x5f, 0x63, 0x61, 0x6e, 0x76, 0x61, 0x73, 0x18, 0x08, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x49, 0x6e, 0x43, + 0x61, 0x6e, 0x76, 0x61, 0x73, 0x12, 0x11, 0x0a, 0x01, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, + 0x48, 0x00, 0x52, 0x01, 0x78, 0x88, 0x01, 0x01, 0x12, 0x11, 0x0a, 0x01, 0x79, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x0d, 0x48, 0x01, 0x52, 0x01, 0x79, 0x88, 0x01, 0x01, 0x12, 0x19, 0x0a, 0x05, 0x77, + 0x69, 0x64, 0x74, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x48, 0x02, 0x52, 0x05, 0x77, 0x69, + 0x64, 0x74, 0x68, 0x88, 0x01, 0x01, 0x12, 0x1b, 0x0a, 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x48, 0x03, 0x52, 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, + 0x88, 0x01, 0x01, 0x42, 0x04, 0x0a, 0x02, 0x5f, 0x78, 0x42, 0x04, 0x0a, 0x02, 0x5f, 0x79, 0x42, + 0x08, 0x0a, 0x06, 0x5f, 0x77, 0x69, 0x64, 0x74, 0x68, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x68, 0x65, + 0x69, 0x67, 0x68, 0x74, 0x22, 0x64, 0x0a, 0x03, 0x41, 0x50, 0x49, 0x12, 0x2c, 0x0a, 0x04, 0x73, + 0x70, 0x65, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x72, 0x69, 0x6c, 0x6c, + 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x50, 0x49, 0x53, + 0x70, 0x65, 0x63, 0x52, 0x04, 0x73, 0x70, 0x65, 0x63, 0x12, 0x2f, 0x0a, 0x05, 0x73, 0x74, 0x61, + 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, + 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x50, 0x49, 0x53, 0x74, + 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x22, 0xb1, 0x02, 0x0a, 0x07, 0x41, + 0x50, 0x49, 0x53, 0x70, 0x65, 0x63, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x6c, 0x76, + 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x6c, 0x76, + 0x65, 0x72, 0x12, 0x48, 0x0a, 0x13, 0x72, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x72, 0x5f, 0x70, + 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x12, 0x72, 0x65, 0x73, 0x6f, 0x6c, 0x76, + 0x65, 0x72, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x12, 0x27, 0x0a, 0x0f, + 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x5f, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x53, 0x75, + 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x12, 0x46, 0x0a, 0x12, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, + 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x11, 0x6f, 0x70, 0x65, 0x6e, + 0x61, 0x70, 0x69, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x12, 0x4f, 0x0a, + 0x17, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x15, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x22, 0x0a, + 0x0a, 0x08, 0x41, 0x50, 0x49, 0x53, 0x74, 0x61, 0x74, 0x65, 0x22, 0x9b, 0x01, 0x0a, 0x08, 0x53, + 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x66, 0x5f, 0x75, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x72, 0x65, 0x66, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, + 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, + 0x12, 0x12, 0x0a, 0x04, 0x63, 0x72, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x63, 0x72, 0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x0e, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x72, 0x5f, 0x73, + 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0d, 0x74, 0x69, + 0x63, 0x6b, 0x65, 0x72, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x74, + 0x69, 0x6d, 0x65, 0x5f, 0x7a, 0x6f, 0x6e, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, + 0x74, 0x69, 0x6d, 0x65, 0x5a, 0x6f, 0x6e, 0x65, 0x22, 0xa5, 0x01, 0x0a, 0x0a, 0x50, 0x61, 0x72, + 0x73, 0x65, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x50, 0x61, 0x74, 0x68, 0x12, 0x44, + 0x0a, 0x0e, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, + 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x68, 0x61, 0x72, 0x4c, 0x6f, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0d, 0x73, 0x74, 0x61, 0x72, 0x74, 0x4c, 0x6f, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, + 0x22, 0x50, 0x0a, 0x0f, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1b, 0x0a, - 0x09, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x50, 0x61, 0x74, 0x68, 0x12, 0x44, 0x0a, 0x0e, 0x73, 0x74, - 0x61, 0x72, 0x74, 0x5f, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, - 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x68, 0x61, 0x72, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x52, 0x0d, 0x73, 0x74, 0x61, 0x72, 0x74, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x12, 0x1a, 0x0a, 0x08, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x08, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x22, 0x50, 0x0a, 0x0f, - 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, - 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x70, 0x72, 0x6f, - 0x70, 0x65, 0x72, 0x74, 0x79, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, - 0x52, 0x0c, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x50, 0x61, 0x74, 0x68, 0x22, 0x4b, - 0x0a, 0x0f, 0x44, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x79, 0x45, 0x72, 0x72, 0x6f, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x23, 0x0a, + 0x0d, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, + 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x50, 0x61, + 0x74, 0x68, 0x22, 0x4b, 0x0a, 0x0f, 0x44, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x79, + 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, + 0x1e, 0x0a, 0x0a, 0x64, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0a, 0x64, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x79, 0x22, + 0x2a, 0x0a, 0x0e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x64, - 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0a, 0x64, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x79, 0x22, 0x2a, 0x0a, 0x0e, 0x45, - 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x18, 0x0a, - 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, - 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x22, 0x0a, 0x0c, 0x43, 0x68, 0x61, 0x72, 0x4c, - 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6c, 0x69, 0x6e, 0x65, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x6c, 0x69, 0x6e, 0x65, 0x22, 0x78, 0x0a, 0x0b, 0x43, - 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x56, 0x32, 0x12, 0x32, 0x0a, 0x04, 0x73, 0x70, - 0x65, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, - 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, - 0x63, 0x74, 0x6f, 0x72, 0x53, 0x70, 0x65, 0x63, 0x52, 0x04, 0x73, 0x70, 0x65, 0x63, 0x12, 0x35, - 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, - 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, - 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, - 0x73, 0x74, 0x61, 0x74, 0x65, 0x22, 0x8c, 0x04, 0x0a, 0x0d, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, - 0x74, 0x6f, 0x72, 0x53, 0x70, 0x65, 0x63, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x72, 0x69, 0x76, 0x65, - 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x12, - 0x4e, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x18, 0x02, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, - 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x53, - 0x70, 0x65, 0x63, 0x2e, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x45, 0x6e, - 0x74, 0x72, 0x79, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x12, - 0x31, 0x0a, 0x14, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x70, 0x72, 0x6f, - 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x13, 0x74, - 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x64, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, - 0x65, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x18, - 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, - 0x12, 0x3e, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x61, 0x72, - 0x67, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, - 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, - 0x74, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x41, 0x72, 0x67, 0x73, - 0x12, 0x77, 0x0a, 0x19, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x5f, 0x66, - 0x72, 0x6f, 0x6d, 0x5f, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x18, 0x03, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x3b, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, - 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x53, - 0x70, 0x65, 0x63, 0x2e, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x46, 0x72, - 0x6f, 0x6d, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, - 0x52, 0x17, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x46, 0x72, 0x6f, 0x6d, - 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x1a, 0x3d, 0x0a, 0x0f, 0x50, 0x72, 0x6f, - 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, + 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x22, 0x0a, 0x0c, 0x43, + 0x68, 0x61, 0x72, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6c, + 0x69, 0x6e, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x6c, 0x69, 0x6e, 0x65, 0x22, + 0x78, 0x0a, 0x0b, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x56, 0x32, 0x12, 0x32, + 0x0a, 0x04, 0x73, 0x70, 0x65, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x72, + 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, + 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x53, 0x70, 0x65, 0x63, 0x52, 0x04, 0x73, 0x70, + 0x65, 0x63, 0x12, 0x35, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1f, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, + 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x53, 0x74, 0x61, + 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x22, 0x8c, 0x04, 0x0a, 0x0d, 0x43, 0x6f, + 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x53, 0x70, 0x65, 0x63, 0x12, 0x16, 0x0a, 0x06, 0x64, + 0x72, 0x69, 0x76, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x72, 0x69, + 0x76, 0x65, 0x72, 0x12, 0x4e, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, + 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, + 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, + 0x74, 0x6f, 0x72, 0x53, 0x70, 0x65, 0x63, 0x2e, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, + 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, + 0x69, 0x65, 0x73, 0x12, 0x31, 0x0a, 0x14, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x64, + 0x5f, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x13, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x64, 0x50, 0x72, 0x6f, 0x70, + 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, + 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x70, 0x72, 0x6f, 0x76, 0x69, + 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x3e, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, + 0x6e, 0x5f, 0x61, 0x72, 0x67, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, + 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, + 0x41, 0x72, 0x67, 0x73, 0x12, 0x77, 0x0a, 0x19, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, + 0x65, 0x73, 0x5f, 0x66, 0x72, 0x6f, 0x6d, 0x5f, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, + 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3b, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, + 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, + 0x74, 0x6f, 0x72, 0x53, 0x70, 0x65, 0x63, 0x2e, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, + 0x65, 0x73, 0x46, 0x72, 0x6f, 0x6d, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x45, + 0x6e, 0x74, 0x72, 0x79, 0x52, 0x17, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, + 0x46, 0x72, 0x6f, 0x6d, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x1a, 0x3d, 0x0a, + 0x0f, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, + 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x4a, 0x0a, 0x1c, + 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x46, 0x72, 0x6f, 0x6d, 0x56, 0x61, + 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x4a, 0x0a, 0x1c, 0x50, 0x72, 0x6f, 0x70, - 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x46, 0x72, 0x6f, 0x6d, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, - 0x6c, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, - 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, - 0x3a, 0x02, 0x38, 0x01, 0x22, 0x2d, 0x0a, 0x0e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x6f, - 0x72, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x70, 0x65, 0x63, 0x5f, 0x68, - 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x70, 0x65, 0x63, 0x48, - 0x61, 0x73, 0x68, 0x2a, 0x8a, 0x01, 0x0a, 0x0f, 0x52, 0x65, 0x63, 0x6f, 0x6e, 0x63, 0x69, 0x6c, - 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x20, 0x0a, 0x1c, 0x52, 0x45, 0x43, 0x4f, 0x4e, - 0x43, 0x49, 0x4c, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x55, 0x4e, 0x53, 0x50, - 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x19, 0x0a, 0x15, 0x52, 0x45, 0x43, - 0x4f, 0x4e, 0x43, 0x49, 0x4c, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x49, 0x44, - 0x4c, 0x45, 0x10, 0x01, 0x12, 0x1c, 0x0a, 0x18, 0x52, 0x45, 0x43, 0x4f, 0x4e, 0x43, 0x49, 0x4c, - 0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, - 0x10, 0x02, 0x12, 0x1c, 0x0a, 0x18, 0x52, 0x45, 0x43, 0x4f, 0x4e, 0x43, 0x49, 0x4c, 0x45, 0x5f, - 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x52, 0x55, 0x4e, 0x4e, 0x49, 0x4e, 0x47, 0x10, 0x03, - 0x2a, 0xab, 0x01, 0x0a, 0x15, 0x45, 0x78, 0x70, 0x6c, 0x6f, 0x72, 0x65, 0x43, 0x6f, 0x6d, 0x70, - 0x61, 0x72, 0x69, 0x73, 0x6f, 0x6e, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x27, 0x0a, 0x23, 0x45, 0x58, - 0x50, 0x4c, 0x4f, 0x52, 0x45, 0x5f, 0x43, 0x4f, 0x4d, 0x50, 0x41, 0x52, 0x49, 0x53, 0x4f, 0x4e, - 0x5f, 0x4d, 0x4f, 0x44, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, - 0x44, 0x10, 0x00, 0x12, 0x20, 0x0a, 0x1c, 0x45, 0x58, 0x50, 0x4c, 0x4f, 0x52, 0x45, 0x5f, 0x43, - 0x4f, 0x4d, 0x50, 0x41, 0x52, 0x49, 0x53, 0x4f, 0x4e, 0x5f, 0x4d, 0x4f, 0x44, 0x45, 0x5f, 0x4e, - 0x4f, 0x4e, 0x45, 0x10, 0x01, 0x12, 0x20, 0x0a, 0x1c, 0x45, 0x58, 0x50, 0x4c, 0x4f, 0x52, 0x45, - 0x5f, 0x43, 0x4f, 0x4d, 0x50, 0x41, 0x52, 0x49, 0x53, 0x4f, 0x4e, 0x5f, 0x4d, 0x4f, 0x44, 0x45, - 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x10, 0x02, 0x12, 0x25, 0x0a, 0x21, 0x45, 0x58, 0x50, 0x4c, 0x4f, + 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x2d, 0x0a, 0x0e, 0x43, 0x6f, 0x6e, 0x6e, + 0x65, 0x63, 0x74, 0x6f, 0x72, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x70, + 0x65, 0x63, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, + 0x70, 0x65, 0x63, 0x48, 0x61, 0x73, 0x68, 0x2a, 0x8a, 0x01, 0x0a, 0x0f, 0x52, 0x65, 0x63, 0x6f, + 0x6e, 0x63, 0x69, 0x6c, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x20, 0x0a, 0x1c, 0x52, + 0x45, 0x43, 0x4f, 0x4e, 0x43, 0x49, 0x4c, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, + 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x19, 0x0a, + 0x15, 0x52, 0x45, 0x43, 0x4f, 0x4e, 0x43, 0x49, 0x4c, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, + 0x53, 0x5f, 0x49, 0x44, 0x4c, 0x45, 0x10, 0x01, 0x12, 0x1c, 0x0a, 0x18, 0x52, 0x45, 0x43, 0x4f, + 0x4e, 0x43, 0x49, 0x4c, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x50, 0x45, 0x4e, + 0x44, 0x49, 0x4e, 0x47, 0x10, 0x02, 0x12, 0x1c, 0x0a, 0x18, 0x52, 0x45, 0x43, 0x4f, 0x4e, 0x43, + 0x49, 0x4c, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x52, 0x55, 0x4e, 0x4e, 0x49, + 0x4e, 0x47, 0x10, 0x03, 0x2a, 0xab, 0x01, 0x0a, 0x15, 0x45, 0x78, 0x70, 0x6c, 0x6f, 0x72, 0x65, + 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x69, 0x73, 0x6f, 0x6e, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x27, + 0x0a, 0x23, 0x45, 0x58, 0x50, 0x4c, 0x4f, 0x52, 0x45, 0x5f, 0x43, 0x4f, 0x4d, 0x50, 0x41, 0x52, + 0x49, 0x53, 0x4f, 0x4e, 0x5f, 0x4d, 0x4f, 0x44, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, + 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x20, 0x0a, 0x1c, 0x45, 0x58, 0x50, 0x4c, 0x4f, 0x52, 0x45, 0x5f, 0x43, 0x4f, 0x4d, 0x50, 0x41, 0x52, 0x49, 0x53, 0x4f, 0x4e, 0x5f, 0x4d, 0x4f, - 0x44, 0x45, 0x5f, 0x44, 0x49, 0x4d, 0x45, 0x4e, 0x53, 0x49, 0x4f, 0x4e, 0x10, 0x03, 0x2a, 0xae, - 0x01, 0x0a, 0x0e, 0x45, 0x78, 0x70, 0x6c, 0x6f, 0x72, 0x65, 0x57, 0x65, 0x62, 0x56, 0x69, 0x65, - 0x77, 0x12, 0x20, 0x0a, 0x1c, 0x45, 0x58, 0x50, 0x4c, 0x4f, 0x52, 0x45, 0x5f, 0x57, 0x45, 0x42, - 0x5f, 0x56, 0x49, 0x45, 0x57, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, - 0x44, 0x10, 0x00, 0x12, 0x1c, 0x0a, 0x18, 0x45, 0x58, 0x50, 0x4c, 0x4f, 0x52, 0x45, 0x5f, 0x57, - 0x45, 0x42, 0x5f, 0x56, 0x49, 0x45, 0x57, 0x5f, 0x45, 0x58, 0x50, 0x4c, 0x4f, 0x52, 0x45, 0x10, - 0x01, 0x12, 0x23, 0x0a, 0x1f, 0x45, 0x58, 0x50, 0x4c, 0x4f, 0x52, 0x45, 0x5f, 0x57, 0x45, 0x42, - 0x5f, 0x56, 0x49, 0x45, 0x57, 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x5f, 0x44, 0x49, 0x4d, 0x45, 0x4e, - 0x53, 0x49, 0x4f, 0x4e, 0x10, 0x02, 0x12, 0x1a, 0x0a, 0x16, 0x45, 0x58, 0x50, 0x4c, 0x4f, 0x52, - 0x45, 0x5f, 0x57, 0x45, 0x42, 0x5f, 0x56, 0x49, 0x45, 0x57, 0x5f, 0x50, 0x49, 0x56, 0x4f, 0x54, - 0x10, 0x03, 0x12, 0x1b, 0x0a, 0x17, 0x45, 0x58, 0x50, 0x4c, 0x4f, 0x52, 0x45, 0x5f, 0x57, 0x45, - 0x42, 0x5f, 0x56, 0x49, 0x45, 0x57, 0x5f, 0x43, 0x41, 0x4e, 0x56, 0x41, 0x53, 0x10, 0x04, 0x2a, - 0xdc, 0x01, 0x0a, 0x0f, 0x45, 0x78, 0x70, 0x6c, 0x6f, 0x72, 0x65, 0x53, 0x6f, 0x72, 0x74, 0x54, - 0x79, 0x70, 0x65, 0x12, 0x21, 0x0a, 0x1d, 0x45, 0x58, 0x50, 0x4c, 0x4f, 0x52, 0x45, 0x5f, 0x53, - 0x4f, 0x52, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, - 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1b, 0x0a, 0x17, 0x45, 0x58, 0x50, 0x4c, 0x4f, 0x52, - 0x45, 0x5f, 0x53, 0x4f, 0x52, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x56, 0x41, 0x4c, 0x55, - 0x45, 0x10, 0x01, 0x12, 0x1d, 0x0a, 0x19, 0x45, 0x58, 0x50, 0x4c, 0x4f, 0x52, 0x45, 0x5f, 0x53, - 0x4f, 0x52, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x50, 0x45, 0x52, 0x43, 0x45, 0x4e, 0x54, - 0x10, 0x02, 0x12, 0x23, 0x0a, 0x1f, 0x45, 0x58, 0x50, 0x4c, 0x4f, 0x52, 0x45, 0x5f, 0x53, 0x4f, - 0x52, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x44, 0x45, 0x4c, 0x54, 0x41, 0x5f, 0x50, 0x45, - 0x52, 0x43, 0x45, 0x4e, 0x54, 0x10, 0x03, 0x12, 0x24, 0x0a, 0x20, 0x45, 0x58, 0x50, 0x4c, 0x4f, - 0x52, 0x45, 0x5f, 0x53, 0x4f, 0x52, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x44, 0x45, 0x4c, - 0x54, 0x41, 0x5f, 0x41, 0x42, 0x53, 0x4f, 0x4c, 0x55, 0x54, 0x45, 0x10, 0x04, 0x12, 0x1f, 0x0a, - 0x1b, 0x45, 0x58, 0x50, 0x4c, 0x4f, 0x52, 0x45, 0x5f, 0x53, 0x4f, 0x52, 0x54, 0x5f, 0x54, 0x59, - 0x50, 0x45, 0x5f, 0x44, 0x49, 0x4d, 0x45, 0x4e, 0x53, 0x49, 0x4f, 0x4e, 0x10, 0x05, 0x2a, 0x85, - 0x01, 0x0a, 0x0f, 0x41, 0x73, 0x73, 0x65, 0x72, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, - 0x75, 0x73, 0x12, 0x20, 0x0a, 0x1c, 0x41, 0x53, 0x53, 0x45, 0x52, 0x54, 0x49, 0x4f, 0x4e, 0x5f, - 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, - 0x45, 0x44, 0x10, 0x00, 0x12, 0x19, 0x0a, 0x15, 0x41, 0x53, 0x53, 0x45, 0x52, 0x54, 0x49, 0x4f, - 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x50, 0x41, 0x53, 0x53, 0x10, 0x01, 0x12, - 0x19, 0x0a, 0x15, 0x41, 0x53, 0x53, 0x45, 0x52, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41, - 0x54, 0x55, 0x53, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x10, 0x02, 0x12, 0x1a, 0x0a, 0x16, 0x41, 0x53, - 0x53, 0x45, 0x52, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x45, - 0x52, 0x52, 0x4f, 0x52, 0x10, 0x03, 0x42, 0xc1, 0x01, 0x0a, 0x13, 0x63, 0x6f, 0x6d, 0x2e, 0x72, - 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x76, 0x31, 0x42, 0x0e, - 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, - 0x5a, 0x3c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x69, 0x6c, - 0x6c, 0x64, 0x61, 0x74, 0x61, 0x2f, 0x72, 0x69, 0x6c, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x72, 0x69, 0x6c, 0x6c, 0x2f, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, - 0x65, 0x2f, 0x76, 0x31, 0x3b, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x76, 0x31, 0xa2, 0x02, - 0x03, 0x52, 0x52, 0x58, 0xaa, 0x02, 0x0f, 0x52, 0x69, 0x6c, 0x6c, 0x2e, 0x52, 0x75, 0x6e, 0x74, - 0x69, 0x6d, 0x65, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x0f, 0x52, 0x69, 0x6c, 0x6c, 0x5c, 0x52, 0x75, - 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x1b, 0x52, 0x69, 0x6c, 0x6c, 0x5c, - 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, - 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x11, 0x52, 0x69, 0x6c, 0x6c, 0x3a, 0x3a, 0x52, - 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x33, + 0x44, 0x45, 0x5f, 0x4e, 0x4f, 0x4e, 0x45, 0x10, 0x01, 0x12, 0x20, 0x0a, 0x1c, 0x45, 0x58, 0x50, + 0x4c, 0x4f, 0x52, 0x45, 0x5f, 0x43, 0x4f, 0x4d, 0x50, 0x41, 0x52, 0x49, 0x53, 0x4f, 0x4e, 0x5f, + 0x4d, 0x4f, 0x44, 0x45, 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x10, 0x02, 0x12, 0x25, 0x0a, 0x21, 0x45, + 0x58, 0x50, 0x4c, 0x4f, 0x52, 0x45, 0x5f, 0x43, 0x4f, 0x4d, 0x50, 0x41, 0x52, 0x49, 0x53, 0x4f, + 0x4e, 0x5f, 0x4d, 0x4f, 0x44, 0x45, 0x5f, 0x44, 0x49, 0x4d, 0x45, 0x4e, 0x53, 0x49, 0x4f, 0x4e, + 0x10, 0x03, 0x2a, 0xae, 0x01, 0x0a, 0x0e, 0x45, 0x78, 0x70, 0x6c, 0x6f, 0x72, 0x65, 0x57, 0x65, + 0x62, 0x56, 0x69, 0x65, 0x77, 0x12, 0x20, 0x0a, 0x1c, 0x45, 0x58, 0x50, 0x4c, 0x4f, 0x52, 0x45, + 0x5f, 0x57, 0x45, 0x42, 0x5f, 0x56, 0x49, 0x45, 0x57, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, + 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1c, 0x0a, 0x18, 0x45, 0x58, 0x50, 0x4c, 0x4f, + 0x52, 0x45, 0x5f, 0x57, 0x45, 0x42, 0x5f, 0x56, 0x49, 0x45, 0x57, 0x5f, 0x45, 0x58, 0x50, 0x4c, + 0x4f, 0x52, 0x45, 0x10, 0x01, 0x12, 0x23, 0x0a, 0x1f, 0x45, 0x58, 0x50, 0x4c, 0x4f, 0x52, 0x45, + 0x5f, 0x57, 0x45, 0x42, 0x5f, 0x56, 0x49, 0x45, 0x57, 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x5f, 0x44, + 0x49, 0x4d, 0x45, 0x4e, 0x53, 0x49, 0x4f, 0x4e, 0x10, 0x02, 0x12, 0x1a, 0x0a, 0x16, 0x45, 0x58, + 0x50, 0x4c, 0x4f, 0x52, 0x45, 0x5f, 0x57, 0x45, 0x42, 0x5f, 0x56, 0x49, 0x45, 0x57, 0x5f, 0x50, + 0x49, 0x56, 0x4f, 0x54, 0x10, 0x03, 0x12, 0x1b, 0x0a, 0x17, 0x45, 0x58, 0x50, 0x4c, 0x4f, 0x52, + 0x45, 0x5f, 0x57, 0x45, 0x42, 0x5f, 0x56, 0x49, 0x45, 0x57, 0x5f, 0x43, 0x41, 0x4e, 0x56, 0x41, + 0x53, 0x10, 0x04, 0x2a, 0xdc, 0x01, 0x0a, 0x0f, 0x45, 0x78, 0x70, 0x6c, 0x6f, 0x72, 0x65, 0x53, + 0x6f, 0x72, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x21, 0x0a, 0x1d, 0x45, 0x58, 0x50, 0x4c, 0x4f, + 0x52, 0x45, 0x5f, 0x53, 0x4f, 0x52, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, + 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1b, 0x0a, 0x17, 0x45, 0x58, + 0x50, 0x4c, 0x4f, 0x52, 0x45, 0x5f, 0x53, 0x4f, 0x52, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, + 0x56, 0x41, 0x4c, 0x55, 0x45, 0x10, 0x01, 0x12, 0x1d, 0x0a, 0x19, 0x45, 0x58, 0x50, 0x4c, 0x4f, + 0x52, 0x45, 0x5f, 0x53, 0x4f, 0x52, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x50, 0x45, 0x52, + 0x43, 0x45, 0x4e, 0x54, 0x10, 0x02, 0x12, 0x23, 0x0a, 0x1f, 0x45, 0x58, 0x50, 0x4c, 0x4f, 0x52, + 0x45, 0x5f, 0x53, 0x4f, 0x52, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x44, 0x45, 0x4c, 0x54, + 0x41, 0x5f, 0x50, 0x45, 0x52, 0x43, 0x45, 0x4e, 0x54, 0x10, 0x03, 0x12, 0x24, 0x0a, 0x20, 0x45, + 0x58, 0x50, 0x4c, 0x4f, 0x52, 0x45, 0x5f, 0x53, 0x4f, 0x52, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, + 0x5f, 0x44, 0x45, 0x4c, 0x54, 0x41, 0x5f, 0x41, 0x42, 0x53, 0x4f, 0x4c, 0x55, 0x54, 0x45, 0x10, + 0x04, 0x12, 0x1f, 0x0a, 0x1b, 0x45, 0x58, 0x50, 0x4c, 0x4f, 0x52, 0x45, 0x5f, 0x53, 0x4f, 0x52, + 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x44, 0x49, 0x4d, 0x45, 0x4e, 0x53, 0x49, 0x4f, 0x4e, + 0x10, 0x05, 0x2a, 0x85, 0x01, 0x0a, 0x0f, 0x41, 0x73, 0x73, 0x65, 0x72, 0x74, 0x69, 0x6f, 0x6e, + 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x20, 0x0a, 0x1c, 0x41, 0x53, 0x53, 0x45, 0x52, 0x54, + 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, + 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x19, 0x0a, 0x15, 0x41, 0x53, 0x53, 0x45, + 0x52, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x50, 0x41, 0x53, + 0x53, 0x10, 0x01, 0x12, 0x19, 0x0a, 0x15, 0x41, 0x53, 0x53, 0x45, 0x52, 0x54, 0x49, 0x4f, 0x4e, + 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x10, 0x02, 0x12, 0x1a, + 0x0a, 0x16, 0x41, 0x53, 0x53, 0x45, 0x52, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, + 0x55, 0x53, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x03, 0x42, 0xc1, 0x01, 0x0a, 0x13, 0x63, + 0x6f, 0x6d, 0x2e, 0x72, 0x69, 0x6c, 0x6c, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, + 0x76, 0x31, 0x42, 0x0e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x50, 0x72, 0x6f, + 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x3c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, + 0x2f, 0x72, 0x69, 0x6c, 0x6c, 0x64, 0x61, 0x74, 0x61, 0x2f, 0x72, 0x69, 0x6c, 0x6c, 0x2f, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x72, 0x69, 0x6c, 0x6c, 0x2f, 0x72, 0x75, + 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2f, 0x76, 0x31, 0x3b, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, + 0x76, 0x31, 0xa2, 0x02, 0x03, 0x52, 0x52, 0x58, 0xaa, 0x02, 0x0f, 0x52, 0x69, 0x6c, 0x6c, 0x2e, + 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x0f, 0x52, 0x69, 0x6c, + 0x6c, 0x5c, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x1b, 0x52, + 0x69, 0x6c, 0x6c, 0x5c, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x5c, 0x56, 0x31, 0x5c, 0x47, + 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x11, 0x52, 0x69, 0x6c, + 0x6c, 0x3a, 0x3a, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -8374,14 +8364,14 @@ var file_rill_runtime_v1_resources_proto_depIdxs = []int32{ 98, // 123: rill.runtime.v1.ThemeSpec.secondary_color:type_name -> rill.runtime.v1.Color 63, // 124: rill.runtime.v1.Component.spec:type_name -> rill.runtime.v1.ComponentSpec 64, // 125: rill.runtime.v1.Component.state:type_name -> rill.runtime.v1.ComponentState - 93, // 126: rill.runtime.v1.ComponentSpec.resolver_properties:type_name -> google.protobuf.Struct - 93, // 127: rill.runtime.v1.ComponentSpec.renderer_properties:type_name -> google.protobuf.Struct - 65, // 128: rill.runtime.v1.ComponentSpec.input:type_name -> rill.runtime.v1.ComponentVariable - 65, // 129: rill.runtime.v1.ComponentSpec.output:type_name -> rill.runtime.v1.ComponentVariable - 63, // 130: rill.runtime.v1.ComponentState.valid_spec:type_name -> rill.runtime.v1.ComponentSpec - 99, // 131: rill.runtime.v1.ComponentVariable.default_value:type_name -> google.protobuf.Value - 67, // 132: rill.runtime.v1.Canvas.spec:type_name -> rill.runtime.v1.CanvasSpec - 68, // 133: rill.runtime.v1.Canvas.state:type_name -> rill.runtime.v1.CanvasState + 93, // 126: rill.runtime.v1.ComponentSpec.renderer_properties:type_name -> google.protobuf.Struct + 65, // 127: rill.runtime.v1.ComponentSpec.input:type_name -> rill.runtime.v1.ComponentVariable + 65, // 128: rill.runtime.v1.ComponentSpec.output:type_name -> rill.runtime.v1.ComponentVariable + 63, // 129: rill.runtime.v1.ComponentState.valid_spec:type_name -> rill.runtime.v1.ComponentSpec + 99, // 130: rill.runtime.v1.ComponentVariable.default_value:type_name -> google.protobuf.Value + 67, // 131: rill.runtime.v1.Canvas.spec:type_name -> rill.runtime.v1.CanvasSpec + 68, // 132: rill.runtime.v1.Canvas.state:type_name -> rill.runtime.v1.CanvasState + 60, // 133: rill.runtime.v1.CanvasSpec.embedded_theme:type_name -> rill.runtime.v1.ThemeSpec 65, // 134: rill.runtime.v1.CanvasSpec.variables:type_name -> rill.runtime.v1.ComponentVariable 69, // 135: rill.runtime.v1.CanvasSpec.items:type_name -> rill.runtime.v1.CanvasItem 22, // 136: rill.runtime.v1.CanvasSpec.security_rules:type_name -> rill.runtime.v1.SecurityRule diff --git a/proto/gen/rill/runtime/v1/resources.pb.validate.go b/proto/gen/rill/runtime/v1/resources.pb.validate.go index 8543df817c0..df359e13202 100644 --- a/proto/gen/rill/runtime/v1/resources.pb.validate.go +++ b/proto/gen/rill/runtime/v1/resources.pb.validate.go @@ -9603,37 +9603,6 @@ func (m *ComponentSpec) validate(all bool) error { // no validation rules for Description - // no validation rules for Resolver - - if all { - switch v := interface{}(m.GetResolverProperties()).(type) { - case interface{ ValidateAll() error }: - if err := v.ValidateAll(); err != nil { - errors = append(errors, ComponentSpecValidationError{ - field: "ResolverProperties", - reason: "embedded message failed validation", - cause: err, - }) - } - case interface{ Validate() error }: - if err := v.Validate(); err != nil { - errors = append(errors, ComponentSpecValidationError{ - field: "ResolverProperties", - reason: "embedded message failed validation", - cause: err, - }) - } - } - } else if v, ok := interface{}(m.GetResolverProperties()).(interface{ Validate() error }); ok { - if err := v.Validate(); err != nil { - return ComponentSpecValidationError{ - field: "ResolverProperties", - reason: "embedded message failed validation", - cause: err, - } - } - } - // no validation rules for Renderer if all { @@ -10254,9 +10223,38 @@ func (m *CanvasSpec) validate(all bool) error { // no validation rules for DisplayName - // no validation rules for Columns + // no validation rules for MaxWidth + + // no validation rules for Theme - // no validation rules for Gap + if all { + switch v := interface{}(m.GetEmbeddedTheme()).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, CanvasSpecValidationError{ + field: "EmbeddedTheme", + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, CanvasSpecValidationError{ + field: "EmbeddedTheme", + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(m.GetEmbeddedTheme()).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return CanvasSpecValidationError{ + field: "EmbeddedTheme", + reason: "embedded message failed validation", + cause: err, + } + } + } for idx, item := range m.GetVariables() { _, _ = idx, item diff --git a/proto/gen/rill/runtime/v1/runtime.swagger.yaml b/proto/gen/rill/runtime/v1/runtime.swagger.yaml index d095d23cc90..fab0abe7171 100644 --- a/proto/gen/rill/runtime/v1/runtime.swagger.yaml +++ b/proto/gen/rill/runtime/v1/runtime.swagger.yaml @@ -1133,7 +1133,7 @@ paths: properties: args: type: object - title: Optional args to pass to the data resolver and for resolving templating in the renderer properties + title: Optional args for resolving templating in the renderer properties tags: - QueryService /v1/instances/{instanceId}/queries/descriptive-statistics/tables/{tableName}: @@ -3477,12 +3477,13 @@ definitions: properties: displayName: type: string - columns: - type: integer - format: int64 - gap: + maxWidth: type: integer format: int64 + theme: + type: string + embeddedTheme: + $ref: '#/definitions/v1ThemeSpec' variables: type: array items: @@ -3832,10 +3833,6 @@ definitions: type: string description: type: string - resolver: - type: string - resolverProperties: - type: object renderer: type: string rendererProperties: @@ -5893,14 +5890,6 @@ definitions: description: |- Show property with templating resolved for the provided args. If it resolves to false, the other fields are not set. - schema: - $ref: '#/definitions/v1StructType' - title: Schema of the resolved component data - data: - type: array - items: - type: object - title: Resolved component data rendererProperties: type: object title: Renderer properties with templating resolved for the provided args diff --git a/proto/rill/runtime/v1/queries.proto b/proto/rill/runtime/v1/queries.proto index 3235922a9f5..b687ad6082c 100644 --- a/proto/rill/runtime/v1/queries.proto +++ b/proto/rill/runtime/v1/queries.proto @@ -779,7 +779,7 @@ message ResolveComponentRequest { string instance_id = 1; // Component name string component = 2; - // Optional args to pass to the data resolver and for resolving templating in the renderer properties + // Optional args for resolving templating in the renderer properties google.protobuf.Struct args = 3; } @@ -787,12 +787,8 @@ message ResolveComponentResponse { // Show property with templating resolved for the provided args. // If it resolves to false, the other fields are not set. bool show = 1; - // Schema of the resolved component data - StructType schema = 2; - // Resolved component data - repeated google.protobuf.Struct data = 3; // Renderer properties with templating resolved for the provided args - google.protobuf.Struct renderer_properties = 4; + google.protobuf.Struct renderer_properties = 2; } // ********** diff --git a/proto/rill/runtime/v1/resources.proto b/proto/rill/runtime/v1/resources.proto index e0e60d567f7..7f50127512a 100644 --- a/proto/rill/runtime/v1/resources.proto +++ b/proto/rill/runtime/v1/resources.proto @@ -671,8 +671,6 @@ message Component { message ComponentSpec { string display_name = 1; string description = 7; - string resolver = 2; - google.protobuf.Struct resolver_properties = 3; string renderer = 4; google.protobuf.Struct renderer_properties = 5; repeated ComponentVariable input = 8; @@ -698,8 +696,9 @@ message Canvas { message CanvasSpec { string display_name = 1; - uint32 columns = 2; - uint32 gap = 3; + uint32 max_width = 2; + string theme = 7; + ThemeSpec embedded_theme = 8; repeated ComponentVariable variables = 5; repeated CanvasItem items = 4; repeated SecurityRule security_rules = 6; diff --git a/runtime/compilers/rillv1/connectors.go b/runtime/compilers/rillv1/connectors.go index 1abdd2a919e..95fdbd7dd02 100644 --- a/runtime/compilers/rillv1/connectors.go +++ b/runtime/compilers/rillv1/connectors.go @@ -81,8 +81,6 @@ func (a *connectorAnalyzer) analyzeResource(ctx context.Context, r *Resource) { a.trackConnector(r.MigrationSpec.Connector, r, false) } else if r.APISpec != nil { a.analyzeResourceWithResolver(r, r.APISpec.Resolver, r.APISpec.ResolverProperties) - } else if r.ComponentSpec != nil { - a.analyzeResourceWithResolver(r, r.ComponentSpec.Resolver, r.ComponentSpec.ResolverProperties) } else if r.AlertSpec != nil { a.analyzeResourceNotifiers(r, r.AlertSpec.Notifiers) } else if r.ReportSpec != nil { diff --git a/runtime/compilers/rillv1/data/component-template-v1.json b/runtime/compilers/rillv1/data/component-template-v1.json index 2fd19c3b92b..2c865bfec44 100644 --- a/runtime/compilers/rillv1/data/component-template-v1.json +++ b/runtime/compilers/rillv1/data/component-template-v1.json @@ -5,25 +5,75 @@ "ChartProperties": { "additionalProperties": false, "properties": { - "color": { + "config": { + "$ref": "#/definitions/ChartConfig" + }, + "title": { + "type": "string" + }, + "description": { + "type": "string" + } + }, + "required": [ + "config" + ], + "type": "object" + }, + "ChartConfig": { + "additionalProperties": false, + "properties": { + "metrics_view": { "type": "string" }, "x": { + "$ref": "#/definitions/FieldConfig" + }, + "y": { + "$ref": "#/definitions/FieldConfig" + }, + "color": { + "oneOf": [ + { + "$ref": "#/definitions/FieldConfig" + }, + { + "type": "string" + } + ] + }, + "tooltip": { + "$ref": "#/definitions/FieldConfig" + } + }, + "required": [ + "metrics_view" + ], + "type": "object" + }, + "FieldConfig": { + "additionalProperties": false, + "properties": { + "field": { "type": "string" }, - "xLabel": { + "title": { "type": "string" }, - "y": { + "format": { "type": "string" }, - "yLabel": { + "type": { + "type": "string", + "enum": ["quantitative", "ordinal", "nominal", "temporal", "geojson"] + }, + "timeUnit": { "type": "string" } }, "required": [ - "x", - "y" + "field", + "type" ], "type": "object" }, @@ -35,6 +85,12 @@ }, "url": { "type": "string" + }, + "title": { + "type": "string" + }, + "description": { + "type": "string" } }, "required": [ @@ -71,6 +127,12 @@ }, "time_range": { "type": "string" + }, + "title": { + "type": "string" + }, + "description": { + "type": "string" } }, "required": [ @@ -100,6 +162,12 @@ }, "css": { "type": "object" + }, + "title": { + "type": "string" + }, + "description": { + "type": "string" } }, "required": [ @@ -218,6 +286,12 @@ }, "time_range": { "type": "string" + }, + "title": { + "type": "string" + }, + "description": { + "type": "string" } }, "required": [ @@ -265,6 +339,20 @@ ], "type": "object" }, + { + "additionalProperties": false, + "properties": { + "vega_lite": { + "spec": { + "type": "string" + } + } + }, + "required": [ + "vega_lite" + ], + "type": "object" + }, { "additionalProperties": false, "properties": { diff --git a/runtime/compilers/rillv1/parse_canvas.go b/runtime/compilers/rillv1/parse_canvas.go index c020b3f3473..d88c419864f 100644 --- a/runtime/compilers/rillv1/parse_canvas.go +++ b/runtime/compilers/rillv1/parse_canvas.go @@ -13,8 +13,8 @@ type CanvasYAML struct { commonYAML `yaml:",inline"` // Not accessed here, only setting it so we can use KnownFields for YAML parsing DisplayName string `yaml:"display_name"` Title string `yaml:"title"` // Deprecated: use display_name - Columns uint32 `yaml:"columns"` - Gap uint32 `yaml:"gap"` + MaxWidth uint32 `yaml:"max_width"` + Theme yaml.Node `yaml:"theme"` // Name (string) or inline theme definition (map) Variables []*ComponentVariableYAML `yaml:"variables"` Items []*struct { Component yaml.Node `yaml:"component"` // Can be a name (string) or inline component definition (map) @@ -47,6 +47,16 @@ func (p *Parser) parseCanvas(node *Node) error { tmp.DisplayName = tmp.Title } + // Parse theme if present. + // If it returns a themeSpec, it will be inserted as a separate resource later in this function. + themeName, themeSpec, err := p.parseThemeRef(&tmp.Theme) + if err != nil { + return err + } + if themeName != "" && themeSpec == nil { + node.Refs = append(node.Refs, ResourceName{Kind: ResourceKindTheme, Name: themeName}) + } + // Parse variable definitions. var variables []*runtimev1.ComponentVariable if len(tmp.Variables) > 0 { @@ -61,7 +71,7 @@ func (p *Parser) parseCanvas(node *Node) error { // Parse items. // Each item can either reference an externally defined component by name or define a component inline. - items := make([]*runtimev1.CanvasItem, len(tmp.Items)) + var items []*runtimev1.CanvasItem var inlineComponentDefs []*componentDef for i, item := range tmp.Items { if item == nil { @@ -78,14 +88,14 @@ func (p *Parser) parseCanvas(node *Node) error { inlineComponentDefs = append(inlineComponentDefs, inlineComponentDef) } - items[i] = &runtimev1.CanvasItem{ + items = append(items, &runtimev1.CanvasItem{ Component: component, DefinedInCanvas: inlineComponentDef != nil, X: item.X, Y: item.Y, Width: item.Width, Height: item.Height, - } + }) node.Refs = append(node.Refs, ResourceName{Kind: ResourceKindComponent, Name: component}) } @@ -108,12 +118,12 @@ func (p *Parser) parseCanvas(node *Node) error { } // NOTE: After calling insertResource, an error must not be returned. Any validation should be done before calling it. - r.CanvasSpec.DisplayName = tmp.DisplayName if r.CanvasSpec.DisplayName == "" { r.CanvasSpec.DisplayName = ToDisplayName(node.Name) } - r.CanvasSpec.Columns = tmp.Columns - r.CanvasSpec.Gap = tmp.Gap + r.CanvasSpec.MaxWidth = tmp.MaxWidth + r.CanvasSpec.Theme = themeName + r.CanvasSpec.EmbeddedTheme = themeSpec r.CanvasSpec.Variables = variables r.CanvasSpec.Items = items r.CanvasSpec.SecurityRules = rules diff --git a/runtime/compilers/rillv1/parse_component.go b/runtime/compilers/rillv1/parse_component.go index be00bed8dfd..3d48158498b 100644 --- a/runtime/compilers/rillv1/parse_component.go +++ b/runtime/compilers/rillv1/parse_component.go @@ -3,7 +3,6 @@ package rillv1 import ( "errors" "fmt" - "strings" runtimev1 "github.com/rilldata/rill/proto/gen/rill/runtime/v1" "github.com/santhosh-tekuri/jsonschema/v5" @@ -25,9 +24,7 @@ type ComponentYAML struct { Subtitle string `yaml:"subtitle"` // Deprecated: use description Input []*ComponentVariableYAML `yaml:"input"` Output *ComponentVariableYAML `yaml:"output"` - Data *DataYAML `yaml:"data"` Show string `yaml:"show"` - VegaLite *string `yaml:"vega_lite"` Other map[string]map[string]any `yaml:",inline" mapstructure:",remain"` // Generic renderer: can only have one key } @@ -82,28 +79,10 @@ func (p *Parser) parseComponentYAML(tmp *ComponentYAML) (*runtimev1.ComponentSpe tmp.Description = tmp.Subtitle } - // Parse the data YAML - var refs []ResourceName - var resolver string - var resolverProps *structpb.Struct - if tmp.Data != nil { - var err error - resolver, resolverProps, refs, err = p.parseDataYAML(tmp.Data, "") - if err != nil { - return nil, nil, err - } - } - // Discover and validate the renderer n := 0 var renderer string var rendererProps *structpb.Struct - if tmp.VegaLite != nil { - n++ - - renderer = "vega_lite" - rendererProps = must(structpb.NewStruct(map[string]any{"spec": strings.TrimSpace(*tmp.VegaLite)})) - } if len(tmp.Other) == 1 { n++ var props map[string]any @@ -111,8 +90,9 @@ func (p *Parser) parseComponentYAML(tmp *ComponentYAML) (*runtimev1.ComponentSpe break } + // nolint // TODO: Activate validation later when in production if err := componentTemplateSchema.Validate(map[string]any{renderer: props}); err != nil { - return nil, nil, fmt.Errorf(`failed to validate renderer %q: %w`, renderer, err) + // return nil, nil, fmt.Errorf(`failed to validate renderer %q: %w`, renderer, err) } propsPB, err := structpb.NewStruct(props) @@ -125,6 +105,19 @@ func (p *Parser) parseComponentYAML(tmp *ComponentYAML) (*runtimev1.ComponentSpe n += len(tmp.Other) } + // We generally treat the renderer props as untyped, but since "metrics_view" is a very common field, + // and adding it to refs generally makes for nicer error messages, we specifically search for and link it here. + var refs []ResourceName + for k, v := range rendererProps.Fields { + if k == "metrics_view" { + name := v.GetStringValue() + if name != "" { + refs = append(refs, ResourceName{Kind: ResourceKindMetricsView, Name: name}) + } + break + } + } + // Check there is exactly one renderer if n == 0 { return nil, nil, errors.New(`missing renderer configuration`) @@ -160,8 +153,6 @@ func (p *Parser) parseComponentYAML(tmp *ComponentYAML) (*runtimev1.ComponentSpe spec := &runtimev1.ComponentSpec{ DisplayName: tmp.DisplayName, Description: tmp.Description, - Resolver: resolver, - ResolverProperties: resolverProps, Renderer: renderer, RendererProperties: rendererProps, Input: input, @@ -192,10 +183,3 @@ func (y *ComponentVariableYAML) Proto() (*runtimev1.ComponentVariable, error) { DefaultValue: val, }, nil } - -func must[T any](v T, err error) T { - if err != nil { - panic(err) - } - return v -} diff --git a/runtime/compilers/rillv1/parse_explore.go b/runtime/compilers/rillv1/parse_explore.go index 93d5276fc8e..a8f27b6acf9 100644 --- a/runtime/compilers/rillv1/parse_explore.go +++ b/runtime/compilers/rillv1/parse_explore.go @@ -154,7 +154,7 @@ func (p *Parser) parseExplore(node *Node) error { // Parse theme if present. // If it returns a themeSpec, it will be inserted as a separate resource later in this function. - themeName, themeSpec, err := p.parseExploreTheme(&tmp.Theme) + themeName, themeSpec, err := p.parseThemeRef(&tmp.Theme) if err != nil { return err } @@ -275,24 +275,21 @@ func (p *Parser) parseExplore(node *Node) error { r.ExploreSpec.DimensionsSelector = dimensionsSelector r.ExploreSpec.Measures = measures r.ExploreSpec.MeasuresSelector = measuresSelector + r.ExploreSpec.Theme = themeName + r.ExploreSpec.EmbeddedTheme = themeSpec r.ExploreSpec.TimeRanges = timeRanges r.ExploreSpec.TimeZones = tmp.TimeZones r.ExploreSpec.DefaultPreset = defaultPreset r.ExploreSpec.EmbedsHidePivot = tmp.Embeds.HidePivot r.ExploreSpec.SecurityRules = rules - if themeName != "" && themeSpec == nil { - r.ExploreSpec.Theme = themeName - } - - if themeSpec != nil { - r.ExploreSpec.EmbeddedTheme = themeSpec - } - return nil } -func (p *Parser) parseExploreTheme(n *yaml.Node) (string, *runtimev1.ThemeSpec, error) { +// parseThemeRef parses a theme from a YAML node. +// It accepts either a reference to a theme by name or an inline definition of a theme. +// It returns either a theme name or a theme spec, not both. +func (p *Parser) parseThemeRef(n *yaml.Node) (string, *runtimev1.ThemeSpec, error) { if n == nil || n.IsZero() { return "", nil, nil } diff --git a/runtime/compilers/rillv1/parser_test.go b/runtime/compilers/rillv1/parser_test.go index 48b59a1d01c..1299445f727 100644 --- a/runtime/compilers/rillv1/parser_test.go +++ b/runtime/compilers/rillv1/parser_test.go @@ -1542,6 +1542,18 @@ theme: t1 `explores/e2.yaml`: ` type: explore metrics_view: missing +theme: + colors: + primary: red +`, + // Canvas referencing the external theme resource + `canvases/c1.yaml`: ` +type: canvas +theme: t1 +`, + // Canvas that defines an inline theme + `canvases/c2.yaml`: ` +type: canvas theme: colors: primary: red @@ -1601,6 +1613,31 @@ theme: }, }, }, + { + Name: ResourceName{Kind: ResourceKindCanvas, Name: "c1"}, + Paths: []string{"/canvases/c1.yaml"}, + Refs: []ResourceName{{Kind: ResourceKindTheme, Name: "t1"}}, + CanvasSpec: &runtimev1.CanvasSpec{ + DisplayName: "C1", + Theme: "t1", + }, + }, + { + Name: ResourceName{Kind: ResourceKindCanvas, Name: "c2"}, + Paths: []string{"/canvases/c2.yaml"}, + CanvasSpec: &runtimev1.CanvasSpec{ + DisplayName: "C2", + EmbeddedTheme: &runtimev1.ThemeSpec{ + PrimaryColor: &runtimev1.Color{ + Red: 1, + Green: 0, + Blue: 0, + Alpha: 1, + }, + PrimaryColorRaw: "red", + }, + }, + }, } p, err := Parse(ctx, repo, "", "", "duckdb") @@ -1627,34 +1664,24 @@ func TestComponentsAndCanvas(t *testing.T) { `rill.yaml`: ``, `components/c1.yaml`: fmt.Sprintf(` type: component -data: - api: MetricsViewAggregation - args: - metrics_view: foo -vega_lite: > - %s +vega_lite: + spec: '%s' `, vegaLiteSpec), `components/c2.yaml`: fmt.Sprintf(` type: component -data: - api: MetricsViewAggregation - args: - metrics_view: bar -vega_lite: > - %s +vega_lite: + spec: '%s' `, vegaLiteSpec), `components/c3.yaml`: ` type: component -data: - metrics_sql: SELECT 1 -line_chart: - x: time - y: total_sales +kpi: + metrics_view: foo + measure: bar + time_range: P1W `, `canvases/d1.yaml`: ` type: canvas -columns: 4 -gap: 3 +max_width: 4 items: - component: c1 - component: c2 @@ -1670,11 +1697,8 @@ items: { Name: ResourceName{Kind: ResourceKindComponent, Name: "c1"}, Paths: []string{"/components/c1.yaml"}, - Refs: []ResourceName{{Kind: ResourceKindAPI, Name: "MetricsViewAggregation"}}, ComponentSpec: &runtimev1.ComponentSpec{ DisplayName: "C1", - Resolver: "api", - ResolverProperties: must(structpb.NewStruct(map[string]any{"api": "MetricsViewAggregation", "args": map[string]any{"metrics_view": "foo"}})), Renderer: "vega_lite", RendererProperties: must(structpb.NewStruct(map[string]any{"spec": vegaLiteSpec})), }, @@ -1682,11 +1706,8 @@ items: { Name: ResourceName{Kind: ResourceKindComponent, Name: "c2"}, Paths: []string{"/components/c2.yaml"}, - Refs: []ResourceName{{Kind: ResourceKindAPI, Name: "MetricsViewAggregation"}}, ComponentSpec: &runtimev1.ComponentSpec{ DisplayName: "C2", - Resolver: "api", - ResolverProperties: must(structpb.NewStruct(map[string]any{"api": "MetricsViewAggregation", "args": map[string]any{"metrics_view": "bar"}})), Renderer: "vega_lite", RendererProperties: must(structpb.NewStruct(map[string]any{"spec": vegaLiteSpec})), }, @@ -1694,12 +1715,11 @@ items: { Name: ResourceName{Kind: ResourceKindComponent, Name: "c3"}, Paths: []string{"/components/c3.yaml"}, + Refs: []ResourceName{{Kind: ResourceKindMetricsView, Name: "foo"}}, ComponentSpec: &runtimev1.ComponentSpec{ DisplayName: "C3", - Resolver: "metrics_sql", - ResolverProperties: must(structpb.NewStruct(map[string]any{"sql": "SELECT 1"})), - Renderer: "line_chart", - RendererProperties: must(structpb.NewStruct(map[string]any{"x": "time", "y": "total_sales"})), + Renderer: "kpi", + RendererProperties: must(structpb.NewStruct(map[string]any{"metrics_view": "foo", "measure": "bar", "time_range": "P1W"})), }, }, { @@ -1721,8 +1741,7 @@ items: }, CanvasSpec: &runtimev1.CanvasSpec{ DisplayName: "D1", - Columns: 4, - Gap: 3, + MaxWidth: 4, Items: []*runtimev1.CanvasItem{ {Component: "c1"}, {Component: "c2", Width: asPtr(uint32(1)), Height: asPtr(uint32(2))}, @@ -2229,3 +2248,10 @@ func normalizeJSON(t *testing.T, s string) string { require.NoError(t, err) return string(b) } + +func must[T any](v T, err error) T { + if err != nil { + panic(err) + } + return v +} diff --git a/runtime/server/components.go b/runtime/server/components.go index 569854bfa38..172bdaba9b9 100644 --- a/runtime/server/components.go +++ b/runtime/server/components.go @@ -2,17 +2,13 @@ package server import ( "context" - "encoding/json" "errors" - "io" - "net/http" "strconv" runtimev1 "github.com/rilldata/rill/proto/gen/rill/runtime/v1" "github.com/rilldata/rill/runtime" "github.com/rilldata/rill/runtime/compilers/rillv1" "github.com/rilldata/rill/runtime/drivers" - "github.com/rilldata/rill/runtime/pkg/httputil" "github.com/rilldata/rill/runtime/pkg/observability" "github.com/rilldata/rill/runtime/server/auth" "go.opentelemetry.io/otel/attribute" @@ -106,119 +102,9 @@ func (s *Server) ResolveComponent(ctx context.Context, req *runtimev1.ResolveCom } } - // Call the component's data resolver - var schema *runtimev1.StructType - var data []*structpb.Struct - if spec.Resolver != "" { - res, err := s.runtime.Resolve(ctx, &runtime.ResolveOptions{ - InstanceID: req.InstanceId, - Resolver: spec.Resolver, - ResolverProperties: spec.ResolverProperties.AsMap(), - Args: req.Args.AsMap(), - Claims: auth.GetClaims(ctx).SecurityClaims(), - }) - if err != nil { - return nil, status.Error(codes.InvalidArgument, err.Error()) - } - defer res.Close() - - schema = res.Schema() - for { - row, err := res.Next() - if err != nil { - if errors.Is(err, io.EOF) { - break - } - return nil, status.Error(codes.Internal, err.Error()) - } - - pb, err := structpb.NewStruct(row) - if err != nil { - return nil, status.Errorf(codes.Internal, "failed to convert row to struct: %s", err.Error()) - } - - data = append(data, pb) - } - } - // Return the response return &runtimev1.ResolveComponentResponse{ Show: true, - Schema: schema, - Data: data, RendererProperties: rendererProps, }, nil } - -// componentDataHandler handles requests to resolve a component's data. -// Deprecated: Use ResolveComponent instead. -func (s *Server) componentDataHandler(w http.ResponseWriter, req *http.Request) error { - // Parse path parameters - ctx := req.Context() - instanceID := req.PathValue("instance_id") - component := req.PathValue("name") - - // Check if user has access to query for component data (we use the ReadAPI permission for this for now) - if !auth.GetClaims(req.Context()).CanInstance(instanceID, auth.ReadAPI) { - return httputil.Errorf(http.StatusForbidden, "does not have access to component data") - } - - // Parse args from the request body and URL query - args := make(map[string]any) - body, err := io.ReadAll(req.Body) - if err != nil { - return httputil.Errorf(http.StatusBadRequest, "failed to read request body: %w", err) - } - if len(body) > 0 { // For POST requests - if err := json.Unmarshal(body, &args); err != nil { - return httputil.Errorf(http.StatusBadRequest, "failed to unmarshal request body: %w", err) - } - } - for k, v := range req.URL.Query() { - // Set only the first value so that client does need to put array accessors in templates. - args[k] = v[0] - } - - // Find the component spec - ctrl, err := s.runtime.Controller(ctx, instanceID) - if err != nil { - return httputil.Error(http.StatusInternalServerError, err) - } - rs, err := ctrl.Get(ctx, &runtimev1.ResourceName{Kind: runtime.ResourceKindComponent, Name: component}, false) - if err != nil { - if errors.Is(err, drivers.ErrResourceNotFound) { - return httputil.Errorf(http.StatusNotFound, "component with name %q not found", component) - } - return httputil.Error(http.StatusInternalServerError, err) - } - componentSpec := rs.GetComponent().State.ValidSpec - if componentSpec == nil { - return httputil.Errorf(http.StatusBadRequest, "component %q is invalid", component) - } - - // Call the component's data resolver - res, err := s.runtime.Resolve(ctx, &runtime.ResolveOptions{ - InstanceID: instanceID, - Resolver: componentSpec.Resolver, - ResolverProperties: componentSpec.ResolverProperties.AsMap(), - Args: args, - Claims: auth.GetClaims(ctx).SecurityClaims(), - }) - if err != nil { - return httputil.Error(http.StatusBadRequest, err) - } - defer res.Close() - - // Write the response - data, err := res.MarshalJSON() - if err != nil { - return httputil.Error(http.StatusInternalServerError, err) - } - w.Header().Set("Content-Type", "application/json") - _, err = w.Write(data) - if err != nil { - return httputil.Error(http.StatusInternalServerError, err) - } - - return nil -} diff --git a/runtime/server/server.go b/runtime/server/server.go index 57692f357c9..5942f730c4e 100644 --- a/runtime/server/server.go +++ b/runtime/server/server.go @@ -215,10 +215,6 @@ func (s *Server) HTTPHandler(ctx context.Context, registerAdditionalHandlers fun // Add handler for combined OpenAPI spec of custom APIs observability.MuxHandle(httpMux, "/v1/instances/{instance_id}/api/openapi", observability.Middleware("runtime", s.logger, auth.HTTPMiddleware(s.aud, httputil.Handler(s.combinedOpenAPISpec)))) - // Add handler for resolving component data - // NOTE: Deprecated in favor of the ResolveComponent RPC. - observability.MuxHandle(httpMux, "/v1/instances/{instance_id}/components/{name}/data", observability.Middleware("runtime", s.logger, auth.HTTPMiddleware(s.aud, httputil.Handler(s.componentDataHandler)))) - // Serving static assets observability.MuxHandle(httpMux, "/v1/instances/{instance_id}/assets/{path...}", observability.Middleware("runtime", s.logger, auth.HTTPMiddleware(s.aud, httputil.Handler(s.assetsHandler)))) diff --git a/web-admin/src/features/embeds/CanvasEmbed.svelte b/web-admin/src/features/embeds/CanvasEmbed.svelte index 8074c2fef40..c5074ae2a87 100644 --- a/web-admin/src/features/embeds/CanvasEmbed.svelte +++ b/web-admin/src/features/embeds/CanvasEmbed.svelte @@ -8,15 +8,14 @@ export let instanceId: string; export let canvasName: string; + // TODO: Remove later + let columns = 20; + let gap = 1; $: canvasQuery = useResource(instanceId, canvasName, ResourceKind.Canvas); $: canvas = $canvasQuery.data?.canvas.spec; - $: ({ - items = [], - columns, - gap, - } = canvas || { items: [], columns: 24, gap: 2 }); + $: ({ items = [] } = canvas || { items: [], columns: 24, gap: 2 }); </script> -<CanvasDashboardEmbed {canvasName} {columns} {items} {gap} /> +<CanvasDashboardEmbed {columns} {items} {gap} /> diff --git a/web-admin/src/routes/[organization]/[project]/-/dashboards/[dashboard]/+page.svelte b/web-admin/src/routes/[organization]/[project]/-/dashboards/[dashboard]/+page.svelte index 8beae7c7d86..eb75686caef 100644 --- a/web-admin/src/routes/[organization]/[project]/-/dashboards/[dashboard]/+page.svelte +++ b/web-admin/src/routes/[organization]/[project]/-/dashboards/[dashboard]/+page.svelte @@ -14,11 +14,10 @@ $: canvas = $canvasQuery.data?.canvas.spec; - $: ({ - items = [], - columns, - gap, - } = canvas || { items: [], columns: 24, gap: 2 }); + // TODO: Remove later + let columns = 20; + let gap = 1; + $: ({ items = [] } = canvas || { items: [], columns: 24, gap: 2 }); </script> -<CanvasDashboardEmbed {canvasName} {columns} {items} {gap} /> +<CanvasDashboardEmbed {columns} {items} {gap} /> diff --git a/web-common/package.json b/web-common/package.json index 774d9cc5dbe..cf756eca95c 100644 --- a/web-common/package.json +++ b/web-common/package.json @@ -6,7 +6,7 @@ "lint": "prettier --check . && eslint .", "format": "prettier --write .", "generate:runtime-client": "orval && tsx src/runtime-client/add-signal-argument.ts src/runtime-client/gen/query-service/query-service.ts src/runtime-client/gen/runtime-service/runtime-service.ts", - "generate:template-schema": "ts-json-schema-generator -p src/features/templates/types.ts -t TemplateSpec -o ../runtime/compilers/rillv1/data/component-template-v1.json", + "generate:template-schema": "ts-json-schema-generator --path 'src/features/canvas/components/types.ts' --type TemplateSpec -o ../runtime/compilers/rillv1/data/component-template-v1.json", "test": "vitest run", "coverage": "vitest run --coverage", "test:watch": "vitest", diff --git a/web-common/src/components/chip/core/Chip.svelte b/web-common/src/components/chip/core/Chip.svelte index 4bec61da5d2..52109ae3415 100644 --- a/web-common/src/components/chip/core/Chip.svelte +++ b/web-common/src/components/chip/core/Chip.svelte @@ -1,12 +1,12 @@ <script lang="ts"> import { builderActions, getAttrs, type Builder } from "bits-ui"; import { createEventDispatcher, getContext } from "svelte"; - import { slideRight } from "../../../lib/transitions"; import type { Writable } from "svelte/store"; - import Tooltip from "../../tooltip/Tooltip.svelte"; + import { slideRight } from "../../../lib/transitions"; import CancelCircle from "../../icons/CancelCircle.svelte"; - import TooltipContent from "../../tooltip/TooltipContent.svelte"; import CaretDownIcon from "../../icons/CaretDownIcon.svelte"; + import Tooltip from "../../tooltip/Tooltip.svelte"; + import TooltipContent from "../../tooltip/TooltipContent.svelte"; export let removable = false; export let active = false; @@ -15,6 +15,7 @@ export let exclude = false; export let grab = false; export let compact = false; + export let fullWidth = false; export let builders: Builder[] = []; export let caret = builders.length > 0; export let slideDuration = 150; @@ -44,6 +45,7 @@ class:grab class:exclude class:compact + class:fullWidth class:pointer-events-none={readOnly && !allowPointerEvents} aria-label={label} {...getAttrs(builders)} @@ -78,7 +80,7 @@ on:click on:mousedown aria-label={label} - class="text-inherit w-full select-none flex items-center gap-x-1 px-0.5" + class="text-inherit w-full select-none flex items-center justify-between gap-x-1 px-0.5" > <slot name="body" /> @@ -169,4 +171,8 @@ .compact { @apply py-0; } + + .fullWidth { + @apply w-full; + } </style> diff --git a/web-common/src/components/color-picker/ColorInput.svelte b/web-common/src/components/color-picker/ColorInput.svelte index 2a35b82866a..4f40a4a1b71 100644 --- a/web-common/src/components/color-picker/ColorInput.svelte +++ b/web-common/src/components/color-picker/ColorInput.svelte @@ -1,12 +1,13 @@ <script lang="ts"> import * as Popover from "@rilldata/web-common/components/popover"; - import ColorSlider from "./ColorSlider.svelte"; import InputLabel from "../forms/InputLabel.svelte"; + import ColorSlider from "./ColorSlider.svelte"; export let stringColor: string | undefined; export let label: string; export let disabled = false; export let onChange: (color: string) => void; + export let small = false; let open = false; @@ -184,6 +185,7 @@ <div class="color-wrapper" + class:small class:pointer-events-none={disabled} class:bg-gray-50={disabled} class:text-gray-400={disabled} @@ -198,7 +200,7 @@ /> </Popover.Trigger> - <Popover.Content class="w-[270px] space-y-2" align="start" sideOffset={10}> + <Popover.Content class="w-[270px] space-y-2" align="start" sideOffset={10}> <div class="space-y-1"> <InputLabel label="Hue" id="hue" /> <ColorSlider @@ -229,6 +231,7 @@ </Popover.Root> <input + class:small bind:value={stringColor} {disabled} on:keydown={(e) => { @@ -243,7 +246,7 @@ }} /> - <p class:text-gray-500={!disabled}>{label}</p> + <p class:small class:text-gray-500={!disabled}>{label}</p> </div> <style lang="postcss"> @@ -258,6 +261,10 @@ @apply flex gap-x-3; } + .color-wrapper.small { + @apply h-6 text-xs; + } + .color-wrapper:focus-within { @apply border-primary-500 ring-2 ring-primary-100; } @@ -266,8 +273,16 @@ @apply text-sm; } + p.small { + @apply text-xs; + } + input { @apply w-full text-sm; @apply outline-none border-0 bg-transparent; } + + input.small { + @apply text-xs; + } </style> diff --git a/web-common/src/components/forms/FieldSwitcher.svelte b/web-common/src/components/forms/FieldSwitcher.svelte index 7ec949ec6e5..7801c3e5c3c 100644 --- a/web-common/src/components/forms/FieldSwitcher.svelte +++ b/web-common/src/components/forms/FieldSwitcher.svelte @@ -2,9 +2,10 @@ export let fields: string[]; export let selected: number = -1; export let onClick: (i: number, value: string) => void = () => {}; + export let small = false; </script> -<div class="option-wrapper"> +<div class:small class="option-wrapper"> {#each fields as field, i (field)} <button on:click={() => onClick(i, field)} @@ -29,6 +30,10 @@ @apply flex h-6 text-sm w-fit mb-1 rounded-[2px]; } + .option-wrapper.small { + @apply h-5 text-xs; + } + .option-wrapper > .selected { @apply border-primary-500 z-50 text-primary-500; } diff --git a/web-common/src/components/forms/Input.svelte b/web-common/src/components/forms/Input.svelte index 00bafa8b9d7..2d986778647 100644 --- a/web-common/src/components/forms/Input.svelte +++ b/web-common/src/components/forms/Input.svelte @@ -8,7 +8,7 @@ const voidFunction = () => {}; - export let value: string | undefined; + export let value: number | string | undefined; export let id = ""; export let label = ""; export let description = ""; @@ -23,6 +23,7 @@ export let truncate = false; export let width: string = "100%"; export let size: "sm" | "md" | "lg" = "lg"; + export let labelGap = 1; export let selected: number = -1; export let full = false; export let multiline = false; @@ -59,6 +60,7 @@ }, ) => void = voidFunction; export let onEscape: () => void = voidFunction; + export let inputType: "text" | "number" = "text"; export let onFieldSwitch: (i: number, value: string) => void = voidFunction; let hitEnter = false; @@ -67,7 +69,7 @@ let selectElement: HTMLButtonElement | undefined; let focus = false; - $: type = secret && !showPassword ? "password" : "text"; + $: type = secret && !showPassword ? "password" : inputType; onMount(() => { if (claimFocusOnMount) { @@ -107,7 +109,7 @@ </script> <div - class="component-wrapper {additionalClass}" + class="component-wrapper gap-y-{labelGap} {additionalClass}" class:w-full={full} style:width > @@ -118,6 +120,7 @@ {id} {hint} {link} + small={size === "sm"} capitalize={capitalizeLabel} > <slot name="mode-switch" slot="mode-switch" /> @@ -140,7 +143,7 @@ </span> {/if} - {#if multiline} + {#if multiline && typeof value !== "number"} <div {id} contenteditable @@ -158,7 +161,7 @@ /> {:else} <input - title={value} + title={label} {id} {type} {placeholder} @@ -194,7 +197,7 @@ </button> {/if} </div> - {:else} + {:else if typeof value !== "number"} <Select {disabled} {enableSearch} @@ -207,7 +210,8 @@ bind:value {options} {onChange} - fontSize={14} + {size} + fontSize={size === "sm" ? 12 : 14} {truncate} placeholder={disabled ? disabledMessage : placeholder} /> @@ -234,11 +238,12 @@ <style lang="postcss"> .component-wrapper { - @apply flex flex-col gap-y-1 h-fit justify-center; + @apply flex flex-col h-fit justify-center; } .sm { height: 24px; + font-size: 12px; } .md { diff --git a/web-common/src/components/forms/InputLabel.svelte b/web-common/src/components/forms/InputLabel.svelte index 9598e959ef5..148bd8874ab 100644 --- a/web-common/src/components/forms/InputLabel.svelte +++ b/web-common/src/components/forms/InputLabel.svelte @@ -1,7 +1,7 @@ <script lang="ts"> + import InfoCircle from "../icons/InfoCircle.svelte"; import Tooltip from "../tooltip/Tooltip.svelte"; import TooltipContent from "../tooltip/TooltipContent.svelte"; - import InfoCircle from "../icons/InfoCircle.svelte"; export let id: string; export let label: string; @@ -9,10 +9,15 @@ export let optional = false; export let capitalize = true; export let link: string | undefined = undefined; + export let small = false; </script> <div class="label-wrapper"> - <label for={id} class="line-clamp-1" class:capitalize> + <label + for={id} + class="line-clamp-1 {small ? 'text-xs' : 'text-sm'}" + class:capitalize + > {label} {#if optional} <span class="text-gray-500 text-[12px] font-normal">(optional)</span> @@ -41,6 +46,6 @@ } label { - @apply text-sm font-medium text-gray-800; + @apply font-medium text-gray-800; } </style> diff --git a/web-common/src/components/forms/Select.svelte b/web-common/src/components/forms/Select.svelte index a5c870c7915..aa2111f88d1 100644 --- a/web-common/src/components/forms/Select.svelte +++ b/web-common/src/components/forms/Select.svelte @@ -1,8 +1,8 @@ <script lang="ts"> - import { InfoIcon } from "lucide-svelte"; - import { createEventDispatcher } from "svelte"; import * as Select from "@rilldata/web-common/components/select"; import * as Tooltip from "@rilldata/web-common/components/tooltip-v2"; + import { InfoIcon } from "lucide-svelte"; + import { createEventDispatcher } from "svelte"; import DataTypeIcon from "../data-types/DataTypeIcon.svelte"; import Search from "../search/Search.svelte"; @@ -12,6 +12,7 @@ export let id: string; export let label: string = ""; export let lockTooltip: string = ""; + export let size: "sm" | "md" | "lg" = "lg"; export let options: { value: string; label: string; @@ -87,8 +88,8 @@ {lockable} {lockTooltip} bind:el={selectElement} - class="flex px-3 gap-x-2 max-w-full {width && - `w-[${width}px]`} {ringFocus && + class="flex px-3 gap-x-2 max-w-full {size === 'sm' ? 'h-6' : ''} {width && + `w-[${width}px]`} {ringFocus && 'focus:ring-2 focus:ring-primary-100'} {truncate ? 'break-all overflow-hidden' : ''}" diff --git a/web-common/src/components/select/select-trigger.svelte b/web-common/src/components/select/select-trigger.svelte index fbe5f55c97a..a573fd0b1b1 100644 --- a/web-common/src/components/select/select-trigger.svelte +++ b/web-common/src/components/select/select-trigger.svelte @@ -1,8 +1,8 @@ <script lang="ts"> - import { Select as SelectPrimitive } from "bits-ui"; - import CaretDownIcon from "../icons/CaretDownIcon.svelte"; import { cn } from "@rilldata/web-common/lib/shadcn"; + import { Select as SelectPrimitive } from "bits-ui"; import { Lock, UnlockIcon } from "lucide-svelte"; + import CaretDownIcon from "../icons/CaretDownIcon.svelte"; import Tooltip from "../tooltip/Tooltip.svelte"; import TooltipContent from "../tooltip/TooltipContent.svelte"; diff --git a/web-common/src/features/canvas-components/render/VegaLiteRenderer.svelte b/web-common/src/components/vega/VegaLiteRenderer.svelte similarity index 93% rename from web-common/src/features/canvas-components/render/VegaLiteRenderer.svelte rename to web-common/src/components/vega/VegaLiteRenderer.svelte index 510bfcbdeaf..6c3c638cdb8 100644 --- a/web-common/src/features/canvas-components/render/VegaLiteRenderer.svelte +++ b/web-common/src/components/vega/VegaLiteRenderer.svelte @@ -1,16 +1,16 @@ <script lang="ts"> import CancelCircle from "@rilldata/web-common/components/icons/CancelCircle.svelte"; - import { getRillTheme } from "@rilldata/web-common/features/canvas-components/render/vega-config"; import { runtime } from "@rilldata/web-common/runtime-client/runtime-store"; - import { get } from "svelte/store"; import { + type EmbedOptions, type SignalListeners, VegaLite, type View, type VisualizationSpec, - type EmbedOptions, } from "svelte-vega"; - import type { ExpressionFunction, VLTooltipFormatter } from "../types"; + import { get } from "svelte/store"; + import type { ExpressionFunction, VLTooltipFormatter } from "./types"; + import { getRillTheme } from "./vega-config"; import { VegaLiteTooltipHandler } from "./vega-tooltip"; export let data: Record<string, unknown> = {}; @@ -27,7 +27,7 @@ let jwt = get(runtime).jwt; $: width = contentRect.width; - $: height = contentRect.height * 0.95 - 80; + $: height = contentRect.height - 10; $: if (viewVL && tooltipFormatter) { const handler = new VegaLiteTooltipHandler(tooltipFormatter); @@ -64,8 +64,7 @@ <div bind:contentRect class:bg-white={canvasDashboard} - class:px-4={canvasDashboard} - class:pb-2={canvasDashboard} + class:px-2={canvasDashboard} class="overflow-hidden size-full flex flex-col items-center justify-center" > {#if error} diff --git a/web-common/src/features/canvas-components/render/VegaRenderer.svelte b/web-common/src/components/vega/VegaRenderer.svelte similarity index 99% rename from web-common/src/features/canvas-components/render/VegaRenderer.svelte rename to web-common/src/components/vega/VegaRenderer.svelte index 0645175dbc7..f8d5756cca2 100644 --- a/web-common/src/features/canvas-components/render/VegaRenderer.svelte +++ b/web-common/src/components/vega/VegaRenderer.svelte @@ -1,18 +1,18 @@ <script lang="ts"> import CancelCircle from "@rilldata/web-common/components/icons/CancelCircle.svelte"; import { runtime } from "@rilldata/web-common/runtime-client/runtime-store"; - import { get } from "svelte/store"; + import { onDestroy } from "svelte"; import { + type EmbedOptions, type SignalListeners, Vega, type View, type VisualizationSpec, - type EmbedOptions, } from "svelte-vega"; - import type { ExpressionFunction, VLTooltipFormatter } from "../types"; - import { VegaLiteTooltipHandler } from "./vega-tooltip"; - import { onDestroy } from "svelte"; + import { get } from "svelte/store"; + import type { ExpressionFunction, VLTooltipFormatter } from "./types"; import { getRillTheme } from "./vega-config"; + import { VegaLiteTooltipHandler } from "./vega-tooltip"; export let data: Record<string, unknown> = {}; export let spec: VisualizationSpec; diff --git a/web-common/src/features/canvas-components/types.ts b/web-common/src/components/vega/types.ts similarity index 93% rename from web-common/src/features/canvas-components/types.ts rename to web-common/src/components/vega/types.ts index 1415c54030c..a0e2ac311fe 100644 --- a/web-common/src/features/canvas-components/types.ts +++ b/web-common/src/components/vega/types.ts @@ -1,5 +1,6 @@ import { TDDChart } from "@rilldata/web-common/features/dashboards/time-dimension-details/types"; +// TODO: Consolidate with Canvas components types /** * Type definitions for common chart types supported by Vega */ diff --git a/web-common/src/features/canvas-components/render/vega-config.ts b/web-common/src/components/vega/vega-config.ts similarity index 98% rename from web-common/src/features/canvas-components/render/vega-config.ts rename to web-common/src/components/vega/vega-config.ts index 27935d3841e..d3c3b566eb0 100644 --- a/web-common/src/features/canvas-components/render/vega-config.ts +++ b/web-common/src/components/vega/vega-config.ts @@ -51,6 +51,7 @@ export const getRillTheme: (isCustomDashboard: boolean) => Config = ( shape: { stroke: defaultMarkColor }, symbol: { fill: defaultMarkColor }, + legend: { orient: "top" }, axisY: { orient: "right", gridColor: gridColor, diff --git a/web-common/src/features/canvas-components/render/vega-signals.ts b/web-common/src/components/vega/vega-signals.ts similarity index 100% rename from web-common/src/features/canvas-components/render/vega-signals.ts rename to web-common/src/components/vega/vega-signals.ts diff --git a/web-common/src/features/canvas-components/render/vega-tooltip.ts b/web-common/src/components/vega/vega-tooltip.ts similarity index 96% rename from web-common/src/features/canvas-components/render/vega-tooltip.ts rename to web-common/src/components/vega/vega-tooltip.ts index 48c8dd72ed5..c754dea8447 100644 --- a/web-common/src/features/canvas-components/render/vega-tooltip.ts +++ b/web-common/src/components/vega/vega-tooltip.ts @@ -1,13 +1,13 @@ -import { - mouseLocationToBoundingRect, - placeElement, -} from "@rilldata/web-common/lib/place-element"; import type { Alignment, Location, } from "@rilldata/web-common/lib/place-element"; +import { + mouseLocationToBoundingRect, + placeElement, +} from "@rilldata/web-common/lib/place-element"; import type { View } from "svelte-vega"; -import type { VLTooltipFormatter } from "../types"; +import type { VLTooltipFormatter } from "./types"; const TOOLTIP_ID = "rill-vg-tooltip"; diff --git a/web-common/src/features/canvas-components/ComponentDataDisplay.svelte b/web-common/src/features/canvas-components/ComponentDataDisplay.svelte deleted file mode 100644 index 49563ca3e57..00000000000 --- a/web-common/src/features/canvas-components/ComponentDataDisplay.svelte +++ /dev/null @@ -1,69 +0,0 @@ -<script lang="ts"> - import CancelCircle from "@rilldata/web-common/components/icons/CancelCircle.svelte"; - import PreviewTable from "@rilldata/web-common/components/preview-table/PreviewTable.svelte"; - import { useVariableInputParams } from "@rilldata/web-common/features/canvas/variables-store"; - import Spinner from "@rilldata/web-common/features/entity-management/Spinner.svelte"; - import { EntityStatus } from "@rilldata/web-common/features/entity-management/types"; - import { - createQueryServiceResolveComponent, - type V1ComponentSpecResolverProperties, - type V1ComponentVariable, - } from "@rilldata/web-common/runtime-client"; - import { runtime } from "@rilldata/web-common/runtime-client/runtime-store"; - import { getContext } from "svelte"; - - export let componentName: string; - export let tablePercentage = 0.45; - export let resolverProperties: V1ComponentSpecResolverProperties | undefined; - export let input: V1ComponentVariable[] | undefined; - - const canvasName = getContext("rill::canvas:name") as string; - - $: ({ instanceId } = $runtime); - - $: inputVariableParams = useVariableInputParams(canvasName, input); - - $: componentDataQuery = resolverProperties - ? createQueryServiceResolveComponent(instanceId, componentName, { - args: $inputVariableParams, - }) - : null; - - $: componentData = $componentDataQuery?.data?.data; - $: isFetching = $componentDataQuery?.isFetching ?? false; - $: errorMessage = $componentDataQuery?.error?.response?.data?.message; -</script> - -{#if resolverProperties} - <div - class="w-full h-48 relative flex-none border rounded-[2px] overflow-hidden" - style:height="{tablePercentage * 100}%" - > - {#if isFetching} - <div class="flex flex-col gap-y-2 size-full justify-center items-center"> - <Spinner size="2em" status={EntityStatus.Running} /> - <div>Loading component data</div> - </div> - {:else if errorMessage} - <div class="size-full flex flex-col items-center justify-center"> - <div class="flex items-center gap-x-2 text-lg"> - <CancelCircle /> Error fetching data from SQL - </div> - <div class="text-sm">{errorMessage}</div> - </div> - {:else if componentData} - <PreviewTable - rows={componentData} - name={componentName} - columnNames={Object.keys(componentData[0]).map((key) => ({ - type: "VARCHAR", - name: key, - }))} - /> - {:else} - <p class="text-lg size-full grid place-content-center"> - Update or add SQL to view data - </p> - {/if} - </div> -{/if} diff --git a/web-common/src/features/canvas-components/ComponentStatusDisplay.svelte b/web-common/src/features/canvas-components/ComponentStatusDisplay.svelte deleted file mode 100644 index 70f942725d4..00000000000 --- a/web-common/src/features/canvas-components/ComponentStatusDisplay.svelte +++ /dev/null @@ -1,47 +0,0 @@ -<script lang="ts"> - import CancelCircle from "@rilldata/web-common/components/icons/CancelCircle.svelte"; - import { - chartPromptsStore, - ChartPromptStatus, - } from "@rilldata/web-common/features/canvas-components/prompt/chartPrompt"; - import Spinner from "@rilldata/web-common/features/entity-management/Spinner.svelte"; - import { EntityStatus } from "@rilldata/web-common/features/entity-management/types"; - - export let componentName: string; - export let isFetching: boolean; - - $: chartPrompt = chartPromptsStore.getStatusForChart(componentName); -</script> - -<!-- TODO: handle prompt error --> -<div class="size-full flex items-center justify-center"> - {#if $chartPrompt && $chartPrompt?.status === ChartPromptStatus.Error} - <div class="flex flex-col gap-y-2 text-red-600 items-center justify-center"> - <CancelCircle size="16px" /> - <div class="flex flex-col gap-y-2"> - <div>Failed to generate chart using AI</div> - <div>Using prompt: "{$chartPrompt.prompt}"</div> - <div>{$chartPrompt.error}</div> - </div> - </div> - {:else if $chartPrompt && $chartPrompt.status !== ChartPromptStatus.Idle} - <div class="flex flex-col gap-y-2 items-center justify-center"> - <Spinner size="16px" status={EntityStatus.Running} /> - <div class="flex flex-col gap-y-2"> - <div> - Generating {$chartPrompt.status === ChartPromptStatus.GeneratingData - ? "data" - : "chart spec"} using AI - </div> - <div>Using prompt: "{$chartPrompt.prompt}"</div> - </div> - </div> - {:else if isFetching} - <div class="flex flex-col gap-y-2 items-center justify-center"> - <Spinner size="16px" status={EntityStatus.Running} /> - <div>Loading chart data</div> - </div> - {:else} - <slot /> - {/if} -</div> diff --git a/web-common/src/features/canvas-components/ComponentsHeader.svelte b/web-common/src/features/canvas-components/ComponentsHeader.svelte deleted file mode 100644 index f41978fa9e9..00000000000 --- a/web-common/src/features/canvas-components/ComponentsHeader.svelte +++ /dev/null @@ -1,58 +0,0 @@ -<script lang="ts"> - import { goto } from "$app/navigation"; - import { Button } from "@rilldata/web-common/components/button"; - import PanelCTA from "@rilldata/web-common/components/panel/PanelCTA.svelte"; - import GenerateVegaSpecPrompt from "@rilldata/web-common/features/canvas-components/prompt/GenerateVegaSpecPrompt.svelte"; - import { - extractFileName, - splitFolderAndFileName, - } from "@rilldata/web-common/features/entity-management/file-path-utils"; - import { ResourceKind } from "@rilldata/web-common/features/entity-management/resource-selectors"; - import { handleEntityRename } from "@rilldata/web-common/features/entity-management/ui-actions"; - import { WorkspaceHeader } from "@rilldata/web-common/layout/workspace"; - import { runtime } from "@rilldata/web-common/runtime-client/runtime-store"; - - export let filePath: string; - export let hasUnsavedChanges: boolean; - - let fileName: string; - $: [, fileName] = splitFolderAndFileName(filePath); - $: ({ instanceId } = $runtime); - $: componentName = extractFileName(filePath); - - async function handleNameChange(newTitle: string) { - const newRoute = await handleEntityRename( - instanceId, - newTitle, - filePath, - componentName, - ); - - if (newRoute) await goto(newRoute); - } - - let generateOpen = false; -</script> - -<WorkspaceHeader - resourceKind={ResourceKind.Component} - onTitleChange={handleNameChange} - titleInput={fileName} - {hasUnsavedChanges} - {filePath} - showInspectorToggle={false} -> - <svelte:fragment slot="cta"> - <PanelCTA side="right"> - <Button type="secondary" on:click={() => (generateOpen = true)} - >Generate using AI</Button - > - </PanelCTA> - </svelte:fragment> -</WorkspaceHeader> - -<GenerateVegaSpecPrompt - bind:open={generateOpen} - chart={componentName} - {filePath} -/> diff --git a/web-common/src/features/canvas-components/chartYaml.ts b/web-common/src/features/canvas-components/chartYaml.ts deleted file mode 100644 index 2510087a2ca..00000000000 --- a/web-common/src/features/canvas-components/chartYaml.ts +++ /dev/null @@ -1,53 +0,0 @@ -import type { V1ComponentSpec } from "@rilldata/web-common/runtime-client"; -import { Document, parse } from "yaml"; - -export function getChartYaml( - vegaLite: string | undefined, - resolver: string | undefined, - resolverProperties: Record<string, any> | undefined, -) { - const doc = new Document(); - doc.commentBefore = ` Component YAML\n Reference documentation: https://docs.rilldata.com/reference/project-files/components`; - doc.set("type", "component"); - - // TODO: more fields from resolverProperties - if (resolver === "sql") { - doc.set("data", { sql: (resolverProperties?.sql as string) ?? "" }); - } else if (resolver === "metrics_sql") { - doc.set("data", { metrics_sql: (resolverProperties?.sql as string) ?? "" }); - } else if (resolver === "api") { - doc.set("data", { api: (resolverProperties?.api as string) ?? "" }); - } - - doc.set("vega_lite", vegaLite ?? "{}"); - - return doc.toString(); -} - -export function parseChartYaml(chartContent: string): V1ComponentSpec { - const chartYaml = parse(chartContent); - - let resolver = ""; - const resolverProperties: Record<string, string> = {}; - - if (chartYaml.data?.sql) { - resolver = "sql"; - resolverProperties.sql = chartYaml.data?.sql; - } else if (chartYaml.data?.metrics_sql) { - resolver = "metrics_sql"; - resolverProperties.sql = chartYaml.data?.metrics_sql; - } else if (chartYaml.data?.api) { - resolver = "api"; - resolverProperties.api = chartYaml.data?.api; - } - - return { - displayName: chartYaml.title, - renderer: "chart", - rendererProperties: { - spec: chartYaml.vegaLiteSpec, - }, - resolver, - resolverProperties, - }; -} diff --git a/web-common/src/features/canvas-components/editor/ComponentsEditor.svelte b/web-common/src/features/canvas-components/editor/ComponentsEditor.svelte deleted file mode 100644 index 94c8a0b9edc..00000000000 --- a/web-common/src/features/canvas-components/editor/ComponentsEditor.svelte +++ /dev/null @@ -1,40 +0,0 @@ -<script lang="ts"> - import type { EditorView } from "@codemirror/view"; - import { customYAMLwithJSONandSQL } from "@rilldata/web-common/components/editor/presets/yamlWithJsonAndSql"; - import ComponentsEditorContainer from "@rilldata/web-common/features/canvas-components/editor/ComponentsEditorContainer.svelte"; - import { fileArtifacts } from "@rilldata/web-common/features/entity-management/file-artifacts"; - import { mapParseErrorsToLines } from "@rilldata/web-common/features/metrics-views/errors"; - import { queryClient } from "@rilldata/web-common/lib/svelte-query/globalQueryClient"; - import { runtime } from "@rilldata/web-common/runtime-client/runtime-store"; - import Editor from "../../editor/Editor.svelte"; - - export let filePath: string; - - let editor: EditorView; - - $: ({ instanceId } = $runtime); - - $: fileArtifact = fileArtifacts.getFileArtifact(filePath); - - $: ({ autoSave, remoteContent } = fileArtifact); - - $: allErrors = fileArtifact.getAllErrors(queryClient, instanceId); - - $: lineBasedRuntimeErrors = mapParseErrorsToLines( - $allErrors, - $remoteContent ?? "", - ); - /** display the main error (the first in this array) at the bottom */ - $: mainError = lineBasedRuntimeErrors?.at(0); -</script> - -<ComponentsEditorContainer - error={$remoteContent?.length ? mainError : undefined} -> - <Editor - {fileArtifact} - extensions={[customYAMLwithJSONandSQL]} - bind:editor - bind:autoSave={$autoSave} - /> -</ComponentsEditorContainer> diff --git a/web-common/src/features/canvas-components/editor/ComponentsEditorContainer.svelte b/web-common/src/features/canvas-components/editor/ComponentsEditorContainer.svelte deleted file mode 100644 index c80ea17fbca..00000000000 --- a/web-common/src/features/canvas-components/editor/ComponentsEditorContainer.svelte +++ /dev/null @@ -1,38 +0,0 @@ -<!-- @component -The full size container is meant to be embedded in a Workspace.svelte component. -It will show an error message if passed in. ---> - -<script lang="ts"> - import type { LineStatus } from "@rilldata/web-common/components/editor/line-status/state"; - import CancelCircle from "@rilldata/web-common/components/icons/CancelCircle.svelte"; - import { LIST_SLIDE_DURATION } from "@rilldata/web-common/layout/config"; - import type { V1ParseError } from "@rilldata/web-common/runtime-client"; - import { slide } from "svelte/transition"; - - export let error: LineStatus | V1ParseError | undefined = undefined; -</script> - -<div - class="flex flex-col size-full bg-white border rounded-[2px] overflow-hidden" -> - <div - class="overflow-auto size-full border-white" - class:border-b-hidden={error} - class:border-red-500={error} - > - <slot /> - </div> - - {#if error} - <div - role="status" - transition:slide={{ duration: LIST_SLIDE_DURATION }} - class="m-2 editor-error ui-editor-text-error ui-editor-bg-error border border-red-500 border-l-4 px-2 py-2 max-h-72" - > - <div class="flex gap-x-2 items-center"> - <CancelCircle />{error.message} - </div> - </div> - {/if} -</div> diff --git a/web-common/src/features/canvas-components/prompt/ChartPromptHistoryDisplay.svelte b/web-common/src/features/canvas-components/prompt/ChartPromptHistoryDisplay.svelte deleted file mode 100644 index 608fe0db980..00000000000 --- a/web-common/src/features/canvas-components/prompt/ChartPromptHistoryDisplay.svelte +++ /dev/null @@ -1,31 +0,0 @@ -<script lang="ts"> - import { Button } from "@rilldata/web-common/components/button"; - import RefreshIcon from "@rilldata/web-common/components/icons/RefreshIcon.svelte"; - import { chartPromptsStore } from "@rilldata/web-common/features/canvas-components/prompt/chartPrompt"; - import { createEventDispatcher } from "svelte"; - - export let entityName: string; - - const dispatch = createEventDispatcher(); - - $: chartPromptHistory = chartPromptsStore.getHistoryForEntity(entityName); -</script> - -{#if $chartPromptHistory.length} - <div class="flex flex-col py-2"> - <div class="text-sm">Prompt history:</div> - {#each $chartPromptHistory as history} - <div class="flex flex-row items-center text-xs"> - <Button - type="secondary" - compact - noStroke - on:click={() => dispatch("reuse-prompt", history.prompt)} - > - <RefreshIcon size="14px" /> - </Button> - <span>{history.prompt}</span> - </div> - {/each} - </div> -{/if} diff --git a/web-common/src/features/canvas-components/prompt/GenerateChartYAMLPrompt.svelte b/web-common/src/features/canvas-components/prompt/GenerateChartYAMLPrompt.svelte deleted file mode 100644 index e00a9af5abd..00000000000 --- a/web-common/src/features/canvas-components/prompt/GenerateChartYAMLPrompt.svelte +++ /dev/null @@ -1,55 +0,0 @@ -<script lang="ts"> - import { Button } from "@rilldata/web-common/components/button"; - import * as Dialog from "@rilldata/web-common/components/dialog-v2"; - import Input from "@rilldata/web-common/components/forms/Input.svelte"; - import ChartPromptHistoryDisplay from "@rilldata/web-common/features/canvas-components/prompt/ChartPromptHistoryDisplay.svelte"; - import { createFullChartGenerator } from "@rilldata/web-common/features/canvas-components/prompt/generateChart"; - import { useAllFileNames } from "@rilldata/web-common/features/entity-management/file-selectors"; - import { getName } from "@rilldata/web-common/features/entity-management/name-utils"; - import { runtime } from "@rilldata/web-common/runtime-client/runtime-store"; - import { queryClient } from "@rilldata/web-common/lib/svelte-query/globalQueryClient"; - - export let open: boolean; - export let table: string = ""; - export let connector: string = ""; - export let metricsView: string = ""; - - $: ({ instanceId } = $runtime); - - let prompt: string; - - $: chartFileNames = useAllFileNames(queryClient, instanceId); - $: generateVegaConfig = createFullChartGenerator(instanceId); - - async function createVegaConfig() { - open = false; - await generateVegaConfig( - prompt, - { - table, - connector, - metricsView, - }, - getName(`${table || metricsView}_chart`, $chartFileNames.data ?? []), - ); - } -</script> - -<Dialog.Root bind:open> - <Dialog.Content> - <Dialog.Title> - Generate component yaml for "{table || metricsView}" using AI</Dialog.Title - > - - <Input bind:value={prompt} label="Prompt" /> - <ChartPromptHistoryDisplay - entityName={table || metricsView} - on:reuse-prompt={({ detail }) => { - prompt = detail; - }} - /> - <div class="ml-auto"> - <Button on:click={createVegaConfig} large type="primary">Generate</Button> - </div> - </Dialog.Content> -</Dialog.Root> diff --git a/web-common/src/features/canvas-components/prompt/GenerateVegaSpecPrompt.svelte b/web-common/src/features/canvas-components/prompt/GenerateVegaSpecPrompt.svelte deleted file mode 100644 index 4da16ab0db9..00000000000 --- a/web-common/src/features/canvas-components/prompt/GenerateVegaSpecPrompt.svelte +++ /dev/null @@ -1,40 +0,0 @@ -<script lang="ts"> - import { Button } from "@rilldata/web-common/components/button"; - import * as Dialog from "@rilldata/web-common/components/dialog-v2"; - import Input from "@rilldata/web-common/components/forms/Input.svelte"; - import ChartPromptHistoryDisplay from "@rilldata/web-common/features/canvas-components/prompt/ChartPromptHistoryDisplay.svelte"; - import { createChartGenerator } from "@rilldata/web-common/features/canvas-components/prompt/generateChart"; - import { runtime } from "@rilldata/web-common/runtime-client/runtime-store"; - - export let open: boolean; - export let chart: string; - export let filePath: string; - - let prompt: string; - - $: ({ instanceId } = $runtime); - - $: generateVegaConfig = createChartGenerator(instanceId, chart, filePath); - - async function createVegaConfig() { - open = false; - await generateVegaConfig(prompt); - } -</script> - -<Dialog.Root bind:open> - <Dialog.Content> - <Dialog.Title>Generate vega config using AI</Dialog.Title> - - <Input bind:value={prompt} label="Prompt" /> - <ChartPromptHistoryDisplay - entityName={chart} - on:reuse-prompt={({ detail }) => { - prompt = detail; - }} - /> - <div class="ml-auto"> - <Button on:click={createVegaConfig} large type="primary">Generate</Button> - </div> - </Dialog.Content> -</Dialog.Root> diff --git a/web-common/src/features/canvas-components/prompt/chartPrompt.ts b/web-common/src/features/canvas-components/prompt/chartPrompt.ts deleted file mode 100644 index 87f5ee179ef..00000000000 --- a/web-common/src/features/canvas-components/prompt/chartPrompt.ts +++ /dev/null @@ -1,137 +0,0 @@ -import { localStorageStore } from "@rilldata/web-common/lib/store-utils"; -import { derived, get, type Readable, writable } from "svelte/store"; - -export enum ChartPromptStatus { - Idle, - GeneratingData, - GeneratingChartSpec, - Error, -} - -export type ChartPrompt = { - entityName: string; - chartName: string; - prompt: string; - time: number; - status: ChartPromptStatus; - error?: string; -}; - -export type ChartPromptHistory = { - entities: Record<string, Array<ChartPrompt>>; - count: number; -}; - -export class ChartPromptsStore { - private readonly history = localStorageStore<ChartPromptHistory>( - "chart-prompt", - { - entities: {}, - count: 0, - }, - ); - - private readonly chartStatus = writable<Record<string, ChartPrompt>>({}); - - public constructor(private readonly maxHistoryCount: number) {} - - public getStatusForChart( - chartName: string, - ): Readable<ChartPrompt | undefined> { - return derived(this.chartStatus, (cs) => cs[chartName]); - } - - public getHistoryForEntity(entityName: string): Readable<Array<ChartPrompt>> { - return derived(this.history, (h) => h.entities[entityName] ?? []); - } - - public startPrompt(entityName: string, chartName: string, prompt: string) { - const chartPrompt: ChartPrompt = { - entityName, - chartName, - prompt, - time: Date.now(), - status: - entityName === chartName - ? ChartPromptStatus.GeneratingData - : ChartPromptStatus.GeneratingChartSpec, - }; - this.chartStatus.update((cs) => { - cs[chartName] = chartPrompt; - return cs; - }); - this.addToHistory(entityName, chartPrompt); - } - - public updatePromptStatus(chartName: string, status: ChartPromptStatus) { - this.chartStatus.update((cs) => { - if (cs[chartName]) cs[chartName].status = status; - return cs; - }); - this.history.update((h) => { - if (!h.entities[chartName]?.length) return h; - h.entities[chartName][0].status = status; - - return h; - }); - } - - public setPromptError(chartName: string, error: string) { - this.chartStatus.update((cs) => { - if (cs[chartName]) { - cs[chartName].status = ChartPromptStatus.Error; - cs[chartName].error = error; - } - return cs; - }); - this.history.update((h) => { - if (!h.entities[chartName]?.length) return h; - h.entities[chartName][0].status = ChartPromptStatus.Error; - - return h; - }); - } - - private addToHistory(entityName: string, newEntry: ChartPrompt) { - let history = get(this.history); - history.entities[entityName] ??= []; - - const existingPromptIdx = history.entities[entityName].findIndex( - (p) => p.prompt === newEntry.prompt, - ); - if (existingPromptIdx >= 0) { - history.entities[entityName].splice(existingPromptIdx, 1); - } - history.entities[entityName].unshift(newEntry); - - while (history.count >= this.maxHistoryCount) { - history = this.removeOldestHistoryEvent(history); - } - - this.history.set(history); - } - - private removeOldestHistoryEvent(history: ChartPromptHistory) { - let oldestPrompt: ChartPrompt | undefined; - let oldestEntity: string | undefined; - - for (const entity in history) { - if (history.entities[entity].length === 0) continue; - const prompt = - history.entities[entity][history.entities[entity].length - 1]; - if (!oldestPrompt || prompt.time < oldestPrompt.time) { - oldestPrompt = prompt; - oldestEntity = entity; - } - } - - if (oldestEntity) { - history.entities[oldestEntity].pop(); - history.count--; - } - - return history; - } -} - -export const chartPromptsStore = new ChartPromptsStore(10); diff --git a/web-common/src/features/canvas-components/prompt/chartPromptStatus.ts b/web-common/src/features/canvas-components/prompt/chartPromptStatus.ts deleted file mode 100644 index c6dc0195401..00000000000 --- a/web-common/src/features/canvas-components/prompt/chartPromptStatus.ts +++ /dev/null @@ -1,41 +0,0 @@ -import type { ChartPromptStatus } from "@rilldata/web-common/features/canvas-components/prompt/chartPrompt"; -import { type Readable, type Updater, writable } from "svelte/store"; - -export type ChartPromptState = { - charts: Record<string, ChartPromptStatus>; -}; -export type ChartPromptStore = Readable<ChartPromptState> & - ReturnType<typeof chartPromptStoreActions>; - -function chartPromptStoreActions( - update: (this: void, updater: Updater<ChartPromptState>) => void, -) { - return { - setStatus(chartPath: string, status: ChartPromptStatus) { - update((s) => { - s.charts[chartPath] = status; - return s; - }); - }, - - deleteStatus(chartPath: string) { - update((s) => { - delete s.charts[chartPath]; - return s; - }); - }, - }; -} - -function createChartPromptStore(): ChartPromptStore { - const { subscribe, update } = writable<ChartPromptState>({ - charts: {}, - }); - - return { - subscribe, - ...chartPromptStoreActions(update), - }; -} - -export const chartPromptStore = createChartPromptStore(); diff --git a/web-common/src/features/canvas-components/prompt/generateChart.spec.ts b/web-common/src/features/canvas-components/prompt/generateChart.spec.ts deleted file mode 100644 index 7c7b88ec22e..00000000000 --- a/web-common/src/features/canvas-components/prompt/generateChart.spec.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { getChartYaml } from "@rilldata/web-common/features/canvas-components/chartYaml"; -import { describe, expect, it } from "vitest"; - -const VegaLiteSpec = `{ - "$schema": "https://vega.github.io/schema/vega-lite/v5.json", - "description": "A simple bar chart with embedded data.", - "mark": "bar", - "encoding": { - "x": {"field": "time", "type": "nominal", "axis": {"labelAngle": 0}}, - "y": {"field": "total_sales", "type": "quantitative"} - } -}`; - -describe("getComponentYaml", () => { - it("multi line sql", () => { - expect( - getChartYaml(VegaLiteSpec, "sql", { - sql: `select * from AdBids -where publisher is not null`, - }), - ).toEqual(`# Component YAML -# Reference documentation: https://docs.rilldata.com/reference/project-files/components - -type: component -data: - sql: |- - select * from AdBids - where publisher is not null -vega_lite: |- -${VegaLiteSpec.replace(/^/gm, " ")} -`); - }); - - it("multi line metrics sql", () => { - expect( - getChartYaml(VegaLiteSpec, "metrics_sql", { - sql: `select * from AdBids -where publisher is not null`, - }), - ).toEqual(`# Component YAML -# Reference documentation: https://docs.rilldata.com/reference/project-files/components - -type: component -data: - metrics_sql: |- - select * from AdBids - where publisher is not null -vega_lite: |- -${VegaLiteSpec.replace(/^/gm, " ")} -`); - }); -}); diff --git a/web-common/src/features/canvas-components/prompt/generateChart.ts b/web-common/src/features/canvas-components/prompt/generateChart.ts deleted file mode 100644 index e79eb7e872e..00000000000 --- a/web-common/src/features/canvas-components/prompt/generateChart.ts +++ /dev/null @@ -1,166 +0,0 @@ -import { goto } from "$app/navigation"; -import { - getChartYaml, - parseChartYaml, -} from "@rilldata/web-common/features/canvas-components/chartYaml"; -import { - ChartPromptStatus, - chartPromptsStore, -} from "@rilldata/web-common/features/canvas-components/prompt/chartPrompt"; -import { useComponent } from "@rilldata/web-common/features/canvas-components/selectors"; -import { getFileAPIPathFromNameAndType } from "@rilldata/web-common/features/entity-management/entity-mappers"; -import { EntityType } from "@rilldata/web-common/features/entity-management/types"; -import { - type V1ComponentSpec, - createRuntimeServiceGenerateRenderer, - createRuntimeServiceGenerateResolver, - createRuntimeServiceGetFile, - runtimeServicePutFile, -} from "@rilldata/web-common/runtime-client"; -import { get } from "svelte/store"; - -export function createChartGenerator( - instanceId: string, - chart: string, - filePath: string, -) { - const generateVegaConfig = createRuntimeServiceGenerateRenderer(); - const chartQuery = useComponent(instanceId, chart); - const chartContent = createRuntimeServiceGetFile(instanceId, { - path: filePath, - }); - // TODO: update for new API - - return async (prompt: string) => { - try { - const [resolver, resolverProperties] = tryParseChart( - get(chartQuery).data?.component?.spec, - get(chartContent).data?.blob, - ); - chartPromptsStore.startPrompt(chart, chart, prompt); - const resp = await get(generateVegaConfig).mutateAsync({ - instanceId, - data: { - prompt, - resolver, - resolverProperties, - }, - }); - chartPromptsStore.updatePromptStatus(chart, ChartPromptStatus.Idle); - await runtimeServicePutFile(instanceId, { - path: filePath, - blob: getChartYaml( - resp.rendererProperties?.spec, - resolver, - resolverProperties, - ), - }); - } catch (e) { - chartPromptsStore.setPromptError( - chart, - e.message ?? e.response.data?.message, - ); - } - }; -} - -export function createFullChartGenerator(instanceId: string) { - const generateResolver = createRuntimeServiceGenerateResolver(); - const generateVegaConfig = createRuntimeServiceGenerateRenderer(); - - return async ( - prompt: string, - { - table, - connector, - metricsView, - }: { table?: string; connector?: string; metricsView?: string }, - newChartName: string, - ) => { - const filePath = getFileAPIPathFromNameAndType( - newChartName, - EntityType.Chart, - ); - try { - // add an empty chart - await runtimeServicePutFile(instanceId, { - path: filePath, - blob: `type: component`, - }); - chartPromptsStore.startPrompt( - (table || metricsView) ?? "", - newChartName, - prompt, - ); - await goto(`/files/${filePath}`); - const resolverResp = await get(generateResolver).mutateAsync({ - instanceId, - data: { - table, - connector, - metricsView, - prompt, - }, - }); - - // add a chart with just the resolver - await runtimeServicePutFile(instanceId, { - path: filePath, - blob: getChartYaml( - "{}", - resolverResp.resolver, - resolverResp.resolverProperties, - ), - }); - chartPromptsStore.updatePromptStatus( - newChartName, - ChartPromptStatus.GeneratingChartSpec, - ); - const resp = await get(generateVegaConfig).mutateAsync({ - instanceId, - data: { - prompt, - resolver: resolverResp.resolver, - resolverProperties: resolverResp.resolverProperties, - }, - }); - - chartPromptsStore.updatePromptStatus( - newChartName, - ChartPromptStatus.Idle, - ); - await runtimeServicePutFile(instanceId, { - path: filePath, - blob: getChartYaml( - resp.rendererProperties?.spec, - resolverResp.resolver, - resolverResp.resolverProperties, - ), - }); - } catch (e) { - chartPromptsStore.setPromptError( - newChartName, - e.message ?? e.response.data?.message, - ); - } - }; -} - -function tryParseChart( - chartSpec: V1ComponentSpec | undefined, - chartContent: string | undefined, -): [resolver: string, resolverProperties: Record<string, string>] { - if (!chartSpec?.resolver && chartContent) { - try { - chartSpec = parseChartYaml(chartContent); - } catch { - throw new Error( - "Failed to parse yaml. Please fix it before trying to generate chart spec.", - ); - } - } - if (chartSpec?.resolver) { - return [chartSpec.resolver, chartSpec.resolverProperties ?? {}]; - } - throw new Error("Chart is invalid"); -} diff --git a/web-common/src/features/canvas-components/selectors.ts b/web-common/src/features/canvas-components/selectors.ts deleted file mode 100644 index dc4b610641d..00000000000 --- a/web-common/src/features/canvas-components/selectors.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { - ResourceKind, - useResource, -} from "@rilldata/web-common/features/entity-management/resource-selectors"; - -export const useComponent = (instanceId: string, componentName: string) => { - return useResource(instanceId, componentName, ResourceKind.Component); -}; diff --git a/web-common/src/features/canvas/AddComponentMenu.svelte b/web-common/src/features/canvas/AddComponentMenu.svelte deleted file mode 100644 index 1f692c63ca2..00000000000 --- a/web-common/src/features/canvas/AddComponentMenu.svelte +++ /dev/null @@ -1,88 +0,0 @@ -<script lang="ts"> - import * as DropdownMenu from "@rilldata/web-common/components/dropdown-menu"; - import Search from "@rilldata/web-common/components/search/Search.svelte"; - import { - ResourceKind, - useClientFilteredResources, - } from "@rilldata/web-common/features/entity-management/resource-selectors"; - import { ChevronDown, Plus } from "lucide-svelte"; - import { runtime } from "../../runtime-client/runtime-store"; - import { getNameFromFile } from "../entity-management/entity-mappers"; - // import { featureFlags } from "../feature-flags"; - import Button from "@rilldata/web-common/components/button/Button.svelte"; - import { createResourceFile } from "../file-explorer/new-files"; - - // const { ai } = featureFlags; - - export let addComponent: (componentName: string) => void; - - let open = false; - let value = ""; - - $: ({ instanceId } = $runtime); - - // We want to get only valid components here. Hence using ListResources API - $: componentsQuery = useClientFilteredResources( - instanceId, - ResourceKind.Component, - ); - $: componentFileNames = - $componentsQuery.data - ?.filter((c) => !c.component?.spec?.definedInCanvas) - .map((c) => c.meta?.name?.name ?? "") ?? []; - - async function handleAddComponent() { - const newFilePath = await createResourceFile(ResourceKind.Component); - - if (!newFilePath) return; - - const componentName = getNameFromFile(newFilePath); - - if (componentName) { - addComponent(componentName); - } - } -</script> - -<DropdownMenu.Root bind:open typeahead={false}> - <DropdownMenu.Trigger asChild let:builder> - <Button builders={[builder]} type="secondary"> - <Plus class="flex items-center justify-center" size="16px" /> - <div class="flex gap-x-1 items-center"> - Add component - <ChevronDown size="14px" /> - </div> - </Button> - </DropdownMenu.Trigger> - <DropdownMenu.Content class="flex flex-col gap-y-1 "> - <DropdownMenu.Group> - <!-- <DropdownMenu.Item disabled> - Generate chart - {#if $ai} - with AI - <WandIcon class="w-3 h-3" /> - {/if} - </DropdownMenu.Item> --> - <DropdownMenu.Item on:click={handleAddComponent}> - Create new component - </DropdownMenu.Item> - </DropdownMenu.Group> - - <DropdownMenu.Separator /> - <div class="px-1"> - <Search bind:value /> - </div> - <DropdownMenu.Separator /> - - <DropdownMenu.Label class="text-[11px] text-gray-500 py-0"> - EXISTING COMPONENTS - </DropdownMenu.Label> - <DropdownMenu.Group> - {#each componentFileNames.filter( (n) => n.startsWith(value), ) as componentName (componentName)} - <DropdownMenu.Item on:click={() => addComponent(componentName)}> - {componentName} - </DropdownMenu.Item> - {/each} - </DropdownMenu.Group> - </DropdownMenu.Content> -</DropdownMenu.Root> diff --git a/web-common/src/features/canvas/Canvas.svelte b/web-common/src/features/canvas/Canvas.svelte new file mode 100644 index 00000000000..1ccab605fae --- /dev/null +++ b/web-common/src/features/canvas/Canvas.svelte @@ -0,0 +1,99 @@ +<script lang="ts"> + import CanvasDashboardPreview from "@rilldata/web-common/features/canvas/CanvasDashboardPreview.svelte"; + import { getCanvasStateManagers } from "@rilldata/web-common/features/canvas/state-managers/state-managers"; + import type { Vector } from "@rilldata/web-common/features/canvas/types"; + import type { FileArtifact } from "@rilldata/web-common/features/entity-management/file-artifact"; + import type { V1CanvasSpec } from "@rilldata/web-common/runtime-client"; + import { parseDocument } from "yaml"; + + export let fileArtifact: FileArtifact; + + const { canvasEntity, validSpecStore } = getCanvasStateManagers(); + $: selectedIndex = canvasEntity?.selectedComponentIndex; + + let showGrid = true; + + // TODO: Remove later when we move to new tiling system + const columns = 24; + const gap = 1; + + let spec: V1CanvasSpec = { + items: [], + }; + + $: ({ + saveLocalContent: updateComponentFile, + autoSave, + updateEditorContent, + editorContent, + remoteContent, + } = fileArtifact); + + $: spec = structuredClone($validSpecStore?.data ?? spec); + + $: ({ items = [] } = spec); + + async function handleDeleteEvent( + e: CustomEvent<{ + index: number; + }>, + ) { + if (!e.detail.index) return; + await deleteComponent(e.detail.index); + } + + async function deleteComponent(index: number) { + const parsedDocument = parseDocument( + $editorContent ?? $remoteContent ?? "", + ); + + const items = parsedDocument.get("items") as any; + if (!items) return; + items.delete(index); + updateEditorContent(parsedDocument.toString(), true); + if ($autoSave) await updateComponentFile(); + } + + async function handlePreviewUpdate( + e: CustomEvent<{ + index: number; + position: Vector; + dimensions: Vector; + }>, + ) { + const parsedDocument = parseDocument( + $editorContent ?? $remoteContent ?? "", + ); + const items = parsedDocument.get("items") as any; + + const node = items.get(e.detail.index); + + node.set("width", e.detail.dimensions[0]); + node.set("height", e.detail.dimensions[1]); + node.set("x", e.detail.position[0]); + node.set("y", e.detail.position[1]); + + updateEditorContent(parsedDocument.toString(), true); + + if ($autoSave) await updateComponentFile(); + } +</script> + +<CanvasDashboardPreview + {gap} + {items} + {columns} + {showGrid} + selectedIndex={$selectedIndex} + on:update={handlePreviewUpdate} + on:delete={handleDeleteEvent} +/> + +<svelte:window + on:keydown={async (e) => { + if (e.target !== document.body || $selectedIndex === null) return; + if (e.key === "Delete" || e.key === "Backspace") { + await deleteComponent($selectedIndex); + } + }} +/> diff --git a/web-common/src/features/canvas/CanvasDashboardEmbed.svelte b/web-common/src/features/canvas/CanvasDashboardEmbed.svelte index d8bb50345d1..205016be4b5 100644 --- a/web-common/src/features/canvas/CanvasDashboardEmbed.svelte +++ b/web-common/src/features/canvas/CanvasDashboardEmbed.svelte @@ -1,25 +1,17 @@ <script lang="ts"> - import { - type V1CanvasItem, - type V1ComponentVariable, - } from "@rilldata/web-common/runtime-client"; + import CanvasFilters from "@rilldata/web-common/features/canvas/filters/CanvasFilters.svelte"; + import { type V1CanvasItem } from "@rilldata/web-common/runtime-client"; import { runtime } from "@rilldata/web-common/runtime-client/runtime-store"; - import { setContext } from "svelte"; import Component from "./Component.svelte"; import * as defaults from "./constants"; import DashboardWrapper from "./DashboardWrapper.svelte"; - import { canvasVariablesStore } from "./variables-store"; - export let canvasName: string; export let columns = 20; export let items: V1CanvasItem[]; - export let gap = 4; + export let gap = 1; export let chartView = false; - export let variables: V1ComponentVariable[] = []; let contentRect: DOMRectReadOnly = new DOMRectReadOnly(0, 0, 0, 0); - setContext("rill::canvas:name", canvasName); - $: ({ instanceId } = $runtime); const dashboardWidth = chartView @@ -36,12 +28,15 @@ const bottom = Number(el.height) + Number(el.y); return Math.max(max, bottom); }, 0); - - $: if (variables.length && canvasName) { - canvasVariablesStore.init(canvasName, variables); - } </script> +<div + id="header" + class="border-b w-fit min-w-full flex flex-col bg-slate-50 slide" +> + <CanvasFilters /> +</div> + <DashboardWrapper bind:contentRect {scale} diff --git a/web-common/src/features/canvas/CanvasDashboardPreview.svelte b/web-common/src/features/canvas/CanvasDashboardPreview.svelte index cb819254cfc..bc55bdea981 100644 --- a/web-common/src/features/canvas/CanvasDashboardPreview.svelte +++ b/web-common/src/features/canvas/CanvasDashboardPreview.svelte @@ -1,9 +1,8 @@ <script lang="ts"> - import { canvasVariablesStore } from "@rilldata/web-common/features/canvas/variables-store"; - import type { - V1CanvasItem, - V1ComponentVariable, - } from "@rilldata/web-common/runtime-client"; + import CanvasFilters from "@rilldata/web-common/features/canvas/filters/CanvasFilters.svelte"; + import { getCanvasStateManagers } from "@rilldata/web-common/features/canvas/state-managers/state-managers"; + import { navigationOpen } from "@rilldata/web-common/layout/navigation/Navigation.svelte"; + import type { V1CanvasItem } from "@rilldata/web-common/runtime-client"; import { runtime } from "@rilldata/web-common/runtime-client/runtime-store"; import { createEventDispatcher } from "svelte"; import * as defaults from "./constants"; @@ -15,16 +14,15 @@ const dispatch = createEventDispatcher(); const zeroVector = [0, 0] as [0, 0]; - export let canvasDashboardName: string; export let columns: number | undefined; export let items: V1CanvasItem[]; export let gap: number | undefined; - export let variables: V1ComponentVariable[]; export let showGrid = false; export let snap = true; - export let selectedComponentName: string | null; export let selectedIndex: number | null = null; + const { canvasEntity } = getCanvasStateManagers(); + let contentRect: DOMRectReadOnly = new DOMRectReadOnly(0, 0, 0, 0); let scrollOffset = 0; let changing = false; @@ -37,6 +35,8 @@ $: ({ instanceId } = $runtime); + $: extraLeftPadding = !$navigationOpen; + $: gridWidth = contentRect.width; $: scale = gridWidth / defaults.DASHBOARD_WIDTH; @@ -63,9 +63,6 @@ $: finalDrag = vector.multiply(getCell(dragPosition, snap), gridVector); $: finalResize = vector.multiply(getCell(resizeDimenions, snap), gridVector); - $: if (variables.length) { - canvasVariablesStore.init(canvasDashboardName, variables); - } function handleMouseUp() { if (selectedIndex === null || !changing) return; @@ -134,7 +131,7 @@ mousePosition = startMouse; selectedIndex = index; - selectedComponentName = items[index].component ?? null; + canvasEntity.setSelectedComponentIndex(selectedIndex); changing = true; } @@ -165,7 +162,7 @@ function deselect() { selectedIndex = null; - selectedComponentName = null; + canvasEntity.setSelectedComponentIndex(selectedIndex); } $: maxBottom = items.reduce((max, el) => { @@ -176,6 +173,14 @@ <svelte:window on:mousemove={handleMouseMove} on:mouseup={handleMouseUp} /> +<div + id="header" + class="border-b w-fit min-w-full flex flex-col bg-slate-50 slide" + class:left-shift={extraLeftPadding} +> + <CanvasFilters /> +</div> + <DashboardWrapper bind:contentRect {changing} @@ -190,6 +195,9 @@ on:click={deselect} on:scroll={handleScroll} > + <section + class="flex relative justify-between gap-x-4 py-4 pb-6 px-4" + ></section> {#each items as component, i (i)} {@const selected = i === selectedIndex} {@const interacting = selected && changing} diff --git a/web-common/src/features/canvas/CanvasEditor.svelte b/web-common/src/features/canvas/CanvasEditor.svelte new file mode 100644 index 00000000000..41d97db1e8c --- /dev/null +++ b/web-common/src/features/canvas/CanvasEditor.svelte @@ -0,0 +1,35 @@ +<script lang="ts"> + import { yaml } from "@codemirror/lang-yaml"; + import type { EditorView } from "@codemirror/view"; + import { setLineStatuses } from "@rilldata/web-common/components/editor/line-status"; + import type { LineStatus } from "@rilldata/web-common/components/editor/line-status/state"; + import { canvasEntities } from "@rilldata/web-common/features/canvas/stores/canvas-entities"; + import Editor from "@rilldata/web-common/features/editor/Editor.svelte"; + import { FileArtifact } from "@rilldata/web-common/features/entity-management/file-artifact"; + + export let canvasName: string; + export let fileArtifact: FileArtifact; + export let autoSave: boolean; + export let lineBasedRuntimeErrors: LineStatus[]; + + let editor: EditorView; + + /** If the errors change, run the following transaction. */ + $: if (editor) setLineStatuses(lineBasedRuntimeErrors, editor); +</script> + +<Editor + bind:autoSave + bind:editor + onSave={(content) => { + // Remove the canvas entity so that everything is reset to defaults next time user navigates to it + canvasEntities.removeCanvas(canvasName); + + // Reset local persisted dashboard state for the metrics view + if (!content?.length) { + setLineStatuses([], editor); + } + }} + {fileArtifact} + extensions={[yaml()]} +/> diff --git a/web-common/src/features/canvas/CanvasThemeProvider.svelte b/web-common/src/features/canvas/CanvasThemeProvider.svelte new file mode 100644 index 00000000000..475e4413793 --- /dev/null +++ b/web-common/src/features/canvas/CanvasThemeProvider.svelte @@ -0,0 +1,26 @@ +<script lang="ts"> + import { page } from "$app/stores"; + import { getCanvasStateManagers } from "@rilldata/web-common/features/canvas/state-managers/state-managers"; + import { setTheme } from "@rilldata/web-common/features/themes/actions"; + import { useTheme } from "@rilldata/web-common/features/themes/selectors"; + import { runtime } from "@rilldata/web-common/runtime-client/runtime-store"; + import { onMount } from "svelte"; + + const { validSpecStore } = getCanvasStateManagers(); + $: themeFromUrl = $page.url.searchParams.get("theme"); + + let theme: ReturnType<typeof useTheme>; + $: themeName = themeFromUrl ?? $validSpecStore?.data?.theme; + $: if (themeName) theme = useTheme($runtime.instanceId, themeName); + + $: setTheme( + $theme?.data?.theme?.spec ?? $validSpecStore?.data?.embeddedTheme, + ); + + onMount(() => { + // Handle the case where we have data in cache but the dashboard is not mounted yet + setTheme($theme?.data?.theme?.spec ?? $validSpecStore?.data?.embeddedTheme); + }); +</script> + +<slot /> diff --git a/web-common/src/features/canvas/Chart.svelte b/web-common/src/features/canvas/Chart.svelte deleted file mode 100644 index 19a6b871dea..00000000000 --- a/web-common/src/features/canvas/Chart.svelte +++ /dev/null @@ -1,53 +0,0 @@ -<script lang="ts"> - import { - createQueryServiceResolveComponent, - type V1ComponentVariable, - } from "@rilldata/web-common/runtime-client"; - import { runtime } from "@rilldata/web-common/runtime-client/runtime-store"; - import { getContext } from "svelte"; - import type { View, VisualizationSpec } from "svelte-vega"; - import VegaLiteRenderer from "../canvas-components/render/VegaLiteRenderer.svelte"; - import { useVariableInputParams } from "./variables-store"; - - export let componentName: string; - export let chartView: boolean; - export let input: V1ComponentVariable[] | undefined; - - let viewVL: View; - let error: string | null = null; - let parsedVegaSpec: VisualizationSpec | null = null; - - $: ({ instanceId } = $runtime); - - $: canvasName = getContext("rill::canvas:name") as string; - $: inputVariableParams = useVariableInputParams(canvasName, input); - - $: componentDataQuery = createQueryServiceResolveComponent( - instanceId, - componentName, - { args: $inputVariableParams }, - ); - $: vegaSpec = $componentDataQuery?.data?.rendererProperties?.spec; - $: data = $componentDataQuery?.data?.data; - - $: try { - if (typeof vegaSpec === "string") { - parsedVegaSpec = JSON.parse(vegaSpec) as VisualizationSpec; - } else { - parsedVegaSpec = vegaSpec ?? null; - } - } catch (e: unknown) { - error = JSON.stringify(e); - } -</script> - -{#if parsedVegaSpec} - <VegaLiteRenderer - bind:viewVL - canvasDashboard - {error} - {chartView} - data={{ table: data }} - spec={parsedVegaSpec} - /> -{/if} diff --git a/web-common/src/features/canvas/Component.svelte b/web-common/src/features/canvas/Component.svelte index 426a89c8cbe..80d6b934660 100644 --- a/web-common/src/features/canvas/Component.svelte +++ b/web-common/src/features/canvas/Component.svelte @@ -1,5 +1,4 @@ <script lang="ts" context="module"> - import TemplateRenderer from "@rilldata/web-common/features/templates/TemplateRenderer.svelte"; import { builderActions, getAttrs, type Builder } from "bits-ui"; import type { ComponentType } from "svelte"; import { onMount } from "svelte"; @@ -7,8 +6,8 @@ ResourceKind, useResource, } from "../entity-management/resource-selectors"; - import Chart from "./Chart.svelte"; import type ResizeHandle from "./ResizeHandle.svelte"; + import ComponentRenderer from "@rilldata/web-common/features/canvas/components/ComponentRenderer.svelte"; const options = [0, 0.5, 1]; const allSides = options @@ -41,15 +40,11 @@ ); $: ({ data: componentResource } = $resourceQuery); - $: ({ - renderer, - rendererProperties, - resolverProperties, - input, - output, - displayName, - description, - } = componentResource?.component?.spec ?? {}); + $: ({ renderer, rendererProperties } = + componentResource?.component?.spec ?? {}); + + $: title = rendererProperties?.title; + $: description = rendererProperties?.description; let ResizeHandleComponent: ComponentType<ResizeHandle>; @@ -93,31 +88,22 @@ {/if} <div - class="size-full overflow-hidden flex flex-col gap-y-1 flex-none" + class="size-full overflow-hidden flex flex-col flex-none" class:shadow-lg={interacting} style:border-radius="{radius}px" > - {#if displayName || description} - <div class="w-full h-fit flex flex-col pb-2"> - {#if displayName} - <h1 class="text-slate-900">{displayName}</h1> + {#if title || description} + <div class="w-full h-fit flex flex-col border-b bg-white p-2"> + {#if title} + <h1 class="text-slate-700">{title}</h1> {/if} {#if description} <h2 class="text-slate-600 leading-none">{description}</h2> {/if} </div> {/if} - {#if renderer === "vega_lite" && rendererProperties?.spec && resolverProperties} - <Chart {componentName} {chartView} {input} /> - {:else if renderer && rendererProperties} - <TemplateRenderer - {chartView} - {renderer} - {input} - {output} - {resolverProperties} - {componentName} - /> + {#if renderer && rendererProperties} + <ComponentRenderer {renderer} {componentName} /> {/if} </div> </div> @@ -129,12 +115,12 @@ } h1 { - font-size: 18px; - font-weight: 600; + font-size: 16px; + font-weight: 500; } h2 { - font-size: 14px; + font-size: 12px; font-weight: 400; } </style> diff --git a/web-common/src/features/canvas/CreateCanvasDialog.svelte b/web-common/src/features/canvas/CreateCanvasDialog.svelte new file mode 100644 index 00000000000..b3240a20b83 --- /dev/null +++ b/web-common/src/features/canvas/CreateCanvasDialog.svelte @@ -0,0 +1,78 @@ +<!-- + To be used later when we have all the components in place. + This dialog will be used as a quickstart option. + --> + +<script lang="ts"> + import * as AlertDialog from "@rilldata/web-common/components/alert-dialog"; + import Button from "@rilldata/web-common/components/button/Button.svelte"; + import Select from "@rilldata/web-common/components/forms/Select.svelte"; + import { ResourceKind } from "@rilldata/web-common/features/entity-management/resource-selectors"; + import type { V1Resource } from "@rilldata/web-common/runtime-client"; + import { createResourceFile } from "../file-explorer/new-files"; + + export let open = false; + export let metricsViews: V1Resource[]; + export let wrapNavigation: (path: string | undefined) => Promise<void>; + + let selectedMetricsView: V1Resource | undefined = undefined; + + $: metricsViewOptions = metricsViews.map((resource) => ({ + value: resource.meta?.name?.name ?? "", + label: resource.meta?.name?.name ?? "", + })); + + async function createResource() { + if (selectedMetricsView) { + const newFilePath = await createResourceFile( + ResourceKind.Canvas, + selectedMetricsView, + ); + await wrapNavigation(newFilePath); + } + } +</script> + +<AlertDialog.Root bind:open> + <AlertDialog.Content> + <AlertDialog.Title> + Which metrics view should this dashboard reference? + </AlertDialog.Title> + + <AlertDialog.Description> + This will determine the measures and dimensions you can explore on this + dashboard. + </AlertDialog.Description> + + <Select + sameWidth + options={metricsViewOptions} + fontSize={14} + placeholder="Select a metrics view" + id="metrics-explore-selection" + onChange={(value) => { + selectedMetricsView = metricsViews.find( + (resource) => resource.meta?.name?.name === value, + ); + }} + /> + + <AlertDialog.Footer> + <AlertDialog.Cancel asChild let:builder> + <Button large builders={[builder]} type="secondary">Cancel</Button> + </AlertDialog.Cancel> + + <AlertDialog.Action asChild let:builder> + <Button + disabled={!selectedMetricsView} + large + builders={[builder]} + type="primary" + on:click={createResource} + > + Continue + </Button> + </AlertDialog.Action> + </AlertDialog.Footer> + </AlertDialog.Content> +</AlertDialog.Root> diff --git a/web-common/src/features/canvas/DashboardWrapper.svelte b/web-common/src/features/canvas/DashboardWrapper.svelte index 58ce62ad6ee..394895809d4 100644 --- a/web-common/src/features/canvas/DashboardWrapper.svelte +++ b/web-common/src/features/canvas/DashboardWrapper.svelte @@ -25,7 +25,7 @@ </script> <div - class="size-full bg-gray-100 flex justify-center overflow-y-auto" + class="dashboard-theme-boundary size-full bg-gray-100 flex justify-center overflow-y-auto" on:scroll > <div diff --git a/web-common/src/features/canvas/components/AddComponentMenu.svelte b/web-common/src/features/canvas/components/AddComponentMenu.svelte new file mode 100644 index 00000000000..d0374d34556 --- /dev/null +++ b/web-common/src/features/canvas/components/AddComponentMenu.svelte @@ -0,0 +1,42 @@ +<script lang="ts"> + import Button from "@rilldata/web-common/components/button/Button.svelte"; + import * as DropdownMenu from "@rilldata/web-common/components/dropdown-menu"; + import type { CanvasComponentType } from "@rilldata/web-common/features/canvas/components/types"; + import { ChevronDown, Plus } from "lucide-svelte"; + + export let addComponent: (componentName: CanvasComponentType) => void; + + let open = false; + + const menuItems: { + id: CanvasComponentType; + label: string; + }[] = [ + { id: "markdown", label: "Text" }, + { id: "kpi", label: "KPI" }, + { id: "image", label: "Image" }, + { id: "bar_chart", label: "Chart" }, + { id: "table", label: "Table" }, + ]; +</script> + +<DropdownMenu.Root bind:open typeahead={false}> + <DropdownMenu.Trigger asChild let:builder> + <Button builders={[builder]} type="secondary"> + <Plus class="flex items-center justify-center" size="16px" /> + <div class="flex gap-x-1 items-center"> + Add component + <ChevronDown size="14px" /> + </div> + </Button> + </DropdownMenu.Trigger> + <DropdownMenu.Content class="flex flex-col gap-y-1 "> + <DropdownMenu.Group> + {#each menuItems as item} + <DropdownMenu.Item on:click={() => addComponent(item.id)}> + {item.label} + </DropdownMenu.Item> + {/each} + </DropdownMenu.Group> + </DropdownMenu.Content> +</DropdownMenu.Root> diff --git a/web-common/src/features/canvas/components/BaseCanvasComponent.ts b/web-common/src/features/canvas/components/BaseCanvasComponent.ts new file mode 100644 index 00000000000..1239b284892 --- /dev/null +++ b/web-common/src/features/canvas/components/BaseCanvasComponent.ts @@ -0,0 +1,88 @@ +import type { ChartType } from "@rilldata/web-common/features/canvas/components/charts/types"; +import type { + CanvasComponent, + ComponentSize, +} from "@rilldata/web-common/features/canvas/components/types"; +import { getParsedDocument } from "@rilldata/web-common/features/canvas/inspector/selectors"; +import type { InputParams } from "@rilldata/web-common/features/canvas/inspector/types"; +import type { FileArtifact } from "@rilldata/web-common/features/entity-management/file-artifact"; +import { get, writable, type Writable } from "svelte/store"; + +// A base class that implements all the store logic +export abstract class BaseCanvasComponent<T> implements CanvasComponent<T> { + specStore: Writable<T>; + pathInYAML: (string | number)[] = []; + fileArtifact: FileArtifact; + + // Let child classes define these + abstract minSize: ComponentSize; + abstract defaultSize: ComponentSize; + abstract isValid(spec: T): boolean; + abstract inputParams(): InputParams<T>; + abstract newComponentSpec( + metrics_view: string, + measure: string, + dimension: string, + ): T; + + constructor( + fileArtifact: FileArtifact, + path: (string | number)[], + defaultSpec: T, + initialSpec: Partial<T> = {}, + ) { + // Initialize the store with merged spec + const mergedSpec = { ...defaultSpec, ...initialSpec }; + this.specStore = writable(mergedSpec); + this.pathInYAML = path; + this.fileArtifact = fileArtifact; + } + + private async updateYAML(newSpec: T): Promise<void> { + const parseDocumentStore = getParsedDocument(this.fileArtifact); + const parsedDocument = get(parseDocumentStore); + + const { updateEditorContent, saveLocalContent } = this.fileArtifact; + + // Update the Item + parsedDocument.setIn(this.pathInYAML, newSpec); + + // Save the updated document + updateEditorContent(parsedDocument.toString(), true); + await saveLocalContent(); + } + + async setSpec(newSpec: T): Promise<void> { + if (this.isValid(newSpec)) { + await this.updateYAML(newSpec); + } + this.specStore.set(newSpec); + } + + // TODO: Add stricter type definition for keys and value deriving from spec + async updateProperty(key: string, value: unknown): Promise<void> { + const currentSpec = get(this.specStore); + const newSpec = { ...currentSpec, [key]: value }; + if (this.isValid(newSpec)) { + await this.updateYAML(newSpec); + } + this.specStore.set(newSpec); + } + + async updateChartType(key: ChartType) { + const currentSpec = get(this.specStore); + const parentSpec = { [key]: currentSpec }; + const parentPath = this.pathInYAML.slice(0, -1); + + const parseDocumentStore = getParsedDocument(this.fileArtifact); + const parsedDocument = get(parseDocumentStore); + + const { updateEditorContent, saveLocalContent } = this.fileArtifact; + + parsedDocument.setIn(parentPath, parentSpec); + + // Save the updated document + updateEditorContent(parsedDocument.toString(), true); + await saveLocalContent(); + } +} diff --git a/web-common/src/features/canvas/components/ComponentRenderer.svelte b/web-common/src/features/canvas/components/ComponentRenderer.svelte new file mode 100644 index 00000000000..fe7ce7dbfef --- /dev/null +++ b/web-common/src/features/canvas/components/ComponentRenderer.svelte @@ -0,0 +1,39 @@ +<script lang="ts"> + import { Chart } from "./charts"; + import { Image } from "./image"; + import { KPI } from "./kpi"; + import { Markdown } from "./markdown"; + import { Table } from "./table"; + + import { + createQueryServiceResolveComponent, + type V1ComponentSpecRendererProperties, + } from "@rilldata/web-common/runtime-client"; + import { runtime } from "@rilldata/web-common/runtime-client/runtime-store"; + + export let renderer: string; + export let componentName: string; + + $: componentQuery = createQueryServiceResolveComponent( + $runtime.instanceId, + componentName, + { args: {} }, + ); + $: componentData = $componentQuery?.data; + $: rendererProperties = + componentData?.rendererProperties as V1ComponentSpecRendererProperties; +</script> + +{#if rendererProperties} + {#if renderer === "kpi"} + <KPI {rendererProperties} /> + {:else if renderer === "table"} + <Table {rendererProperties} /> + {:else if renderer === "markdown"} + <Markdown {rendererProperties} /> + {:else if renderer === "image"} + <Image {rendererProperties} /> + {:else} + <Chart {rendererProperties} {renderer} /> + {/if} +{/if} diff --git a/web-common/src/features/templates/README.md b/web-common/src/features/canvas/components/README.md similarity index 100% rename from web-common/src/features/templates/README.md rename to web-common/src/features/canvas/components/README.md diff --git a/web-common/src/features/canvas/components/charts/Chart.svelte b/web-common/src/features/canvas/components/charts/Chart.svelte new file mode 100644 index 00000000000..08d742714ca --- /dev/null +++ b/web-common/src/features/canvas/components/charts/Chart.svelte @@ -0,0 +1,43 @@ +<script lang="ts"> + import VegaLiteRenderer from "@rilldata/web-common/components/vega/VegaLiteRenderer.svelte"; + import { getCanvasStateManagers } from "@rilldata/web-common/features/canvas/state-managers/state-managers"; + import Spinner from "@rilldata/web-common/features/entity-management/Spinner.svelte"; + import { EntityStatus } from "@rilldata/web-common/features/entity-management/types"; + import type { V1ComponentSpecRendererProperties } from "@rilldata/web-common/runtime-client"; + import { runtime } from "@rilldata/web-common/runtime-client/runtime-store"; + import type { View } from "svelte-vega"; + import { getChartData } from "./selector"; + import type { ChartConfig, ChartType } from "./types"; + import { generateSpec } from "./util"; + + export let rendererProperties: V1ComponentSpecRendererProperties; + export let renderer: string; + + let stateManagers = getCanvasStateManagers(); + + const instanceId = $runtime.instanceId; + $: chartConfig = rendererProperties as ChartConfig; + $: chartType = renderer as ChartType; + + let viewVL: View; + + $: data = getChartData(stateManagers, instanceId, chartConfig); + $: spec = generateSpec(chartType, chartConfig, $data); +</script> + +{#if chartConfig?.x} + {#if $data.isFetching} + <div class="flex items-center h-full w-full"> + <Spinner status={EntityStatus.Running} size="16px" /> + </div> + {:else if $data.error} + <div class="text-red-500">{$data.error.message}</div> + {:else} + <VegaLiteRenderer + bind:viewVL + canvasDashboard + data={{ "metrics-view": $data.data }} + {spec} + /> + {/if} +{/if} diff --git a/web-common/src/features/canvas/components/charts/bar-chart/index.ts b/web-common/src/features/canvas/components/charts/bar-chart/index.ts new file mode 100644 index 00000000000..e69de29bb2d diff --git a/web-common/src/features/canvas/components/charts/bar-chart/spec.ts b/web-common/src/features/canvas/components/charts/bar-chart/spec.ts new file mode 100644 index 00000000000..8dfa500779b --- /dev/null +++ b/web-common/src/features/canvas/components/charts/bar-chart/spec.ts @@ -0,0 +1,61 @@ +import type { ChartConfig } from "@rilldata/web-common/features/canvas/components/charts/types"; +import type { VisualizationSpec } from "svelte-vega"; +import type { ChartDataResult } from "../selector"; + +export function generateVLBarChartSpec( + config: ChartConfig, + data: ChartDataResult, +): VisualizationSpec { + return { + $schema: "https://vega.github.io/schema/vega-lite/v5.json", + mark: "bar", + width: "container", + autosize: { type: "fit" }, + data: { name: "metrics-view" }, + encoding: { + ...(config.x && { + x: { + field: config.x.field, + title: data.fields[config.x.field]?.displayName || config.x.field, + type: config.x.type, + ...(config.x.timeUnit && { timeUnit: config.x.timeUnit }), + }, + }), + ...(config.y && { + y: { + field: config.y.field, + title: data.fields[config.y.field]?.displayName || config.y.field, + type: config.y.type, + ...(config.y.timeUnit && { timeUnit: config.y.timeUnit }), + }, + }), + ...(config.color && + typeof config.color === "object" && { + color: { + field: config.color.field, + title: + data.fields[config.color.field]?.displayName || + config.color.field, + type: config.color.type, + ...(config.color.timeUnit && { + timeUnit: config.color.timeUnit, + }), + }, + }), + ...(config.color && + typeof config.color === "string" && { + color: { value: config.color }, + }), + ...(config.color && + typeof config.color === "object" && + config.x && { + xOffset: { + field: config.color.field, + title: + data.fields[config.color.field]?.displayName || + config.color.field, + }, + }), + }, + }; +} diff --git a/web-common/src/features/canvas/components/charts/index.ts b/web-common/src/features/canvas/components/charts/index.ts new file mode 100644 index 00000000000..a762662fc40 --- /dev/null +++ b/web-common/src/features/canvas/components/charts/index.ts @@ -0,0 +1,74 @@ +import { BaseCanvasComponent } from "@rilldata/web-common/features/canvas/components/BaseCanvasComponent"; +import type { ChartConfig } from "@rilldata/web-common/features/canvas/components/charts/types"; +import { + commonOptions, + getFilterOptions, +} from "@rilldata/web-common/features/canvas/components/util"; +import type { InputParams } from "@rilldata/web-common/features/canvas/inspector/types"; +import type { FileArtifact } from "@rilldata/web-common/features/entity-management/file-artifact"; +import { type ComponentCommonProperties } from "../types"; + +export { default as Chart } from "./Chart.svelte"; + +export type ChartSpec = ComponentCommonProperties & ChartConfig; + +export class ChartComponent extends BaseCanvasComponent<ChartSpec> { + minSize = { width: 4, height: 4 }; + defaultSize = { width: 12, height: 8 }; + + constructor( + fileArtifact: FileArtifact, + path: (string | number)[] = [], + initialSpec: Partial<ChartSpec> = {}, + ) { + const defaultSpec: ChartSpec = { + metrics_view: "", + title: "", + description: "", + time_range: "P1D", + }; + super(fileArtifact, path, defaultSpec, initialSpec); + } + + isValid(spec: ChartSpec): boolean { + return ( + typeof spec.metrics_view === "string" && + Boolean(spec.x || spec.y) && + typeof spec.time_range === "string" + ); + } + + inputParams(): InputParams<ChartSpec> { + return { + component: { + metrics_view: { type: "metrics", label: "Metrics view" }, + time_range: { type: "rill_time", label: "Time Range" }, + x: { type: "positional", label: "X-axis" }, + y: { type: "positional", label: "Y-axis" }, + color: { type: "mark", label: "Color", meta: { type: "color" } }, + tooltip: { type: "tooltip", label: "Tooltip", showInUI: false }, + ...commonOptions, + }, + filter: getFilterOptions(), + }; + } + + newComponentSpec( + metrics_view: string, + measure: string, + dimension: string, + ): ChartSpec { + return { + metrics_view, + x: { + type: "nominal", + field: dimension, + }, + y: { + type: "quantitative", + field: measure, + }, + time_range: "PT24H", + }; + } +} diff --git a/web-common/src/features/canvas/components/charts/line-chart/spec.ts b/web-common/src/features/canvas/components/charts/line-chart/spec.ts new file mode 100644 index 00000000000..e72e549b098 --- /dev/null +++ b/web-common/src/features/canvas/components/charts/line-chart/spec.ts @@ -0,0 +1,51 @@ +import type { ChartConfig } from "@rilldata/web-common/features/canvas/components/charts/types"; +import type { VisualizationSpec } from "svelte-vega"; +import type { ChartDataResult } from "../selector"; + +export function generateVLLineChartSpec( + config: ChartConfig, + data: ChartDataResult, +): VisualizationSpec { + return { + $schema: "https://vega.github.io/schema/vega-lite/v5.json", + mark: "line", + width: "container", + autosize: { type: "fit" }, + data: { name: "metrics-view" }, + encoding: { + ...(config.x && { + x: { + field: config.x.field, + title: data.fields[config.x.field]?.displayName || config.x.field, + type: config.x.type, + ...(config.x.timeUnit && { timeUnit: config.x.timeUnit }), + }, + }), + ...(config.y && { + y: { + field: config.y.field, + title: data.fields[config.y.field]?.displayName || config.y.field, + type: config.y.type, + ...(config.y.timeUnit && { timeUnit: config.y.timeUnit }), + }, + }), + ...(config.color && + typeof config.color === "object" && { + color: { + field: config.color.field, + title: + data.fields[config.color.field]?.displayName || + config.color.field, + type: config.color.type, + ...(config.color.timeUnit && { + timeUnit: config.color.timeUnit, + }), + }, + }), + ...(config.color && + typeof config.color === "string" && { + color: { value: config.color }, + }), + }, + }; +} diff --git a/web-common/src/features/canvas/components/charts/selector.ts b/web-common/src/features/canvas/components/charts/selector.ts new file mode 100644 index 00000000000..31eac8177c0 --- /dev/null +++ b/web-common/src/features/canvas/components/charts/selector.ts @@ -0,0 +1,129 @@ +import type { ChartConfig } from "@rilldata/web-common/features/canvas/components/charts/types"; +import { useStartEndTime } from "@rilldata/web-common/features/canvas/components/kpi/selector"; +import type { StateManagers } from "@rilldata/web-common/features/canvas/state-managers/state-managers"; +import { + createQueryServiceMetricsViewAggregation, + type MetricsViewSpecDimensionV2, + type MetricsViewSpecMeasureV2, + type V1MetricsViewAggregationDimension, + type V1MetricsViewAggregationMeasure, + type V1MetricsViewAggregationResponse, + type V1MetricsViewAggregationResponseDataItem, +} from "@rilldata/web-common/runtime-client"; +import type { HTTPError } from "@rilldata/web-common/runtime-client/fetchWrapper"; +import type { CreateQueryResult } from "@tanstack/svelte-query"; +import { derived, type Readable } from "svelte/store"; +import { useMeasureDimensionSpec } from "../selectors"; + +export type ChartDataResult = { + data: V1MetricsViewAggregationResponseDataItem[]; + isFetching: boolean; + fields: Record< + string, + MetricsViewSpecMeasureV2 | MetricsViewSpecDimensionV2 | undefined + >; + error?: HTTPError; +}; + +export function getChartData( + ctx: StateManagers, + instanceId: string, + config: ChartConfig, +): Readable<ChartDataResult> { + const chartDataQuery = createChartDataQuery(ctx, instanceId, config); + + const fields: { name: string; type: "measure" | "dimension" }[] = []; + if (config.y?.field) fields.push({ name: config.y.field, type: "measure" }); + if (config.x?.field) fields.push({ name: config.x.field, type: "dimension" }); + if (typeof config.color === "object" && config.color?.field) { + fields.push({ name: config.color.field, type: "dimension" }); + } + + const specQueries = useMeasureDimensionSpec( + instanceId, + config.metrics_view, + fields, + ); + + return derived( + [chartDataQuery, ...specQueries], + ([chartData, ...specResults]) => { + const isFetching = + specResults.some((q) => q?.isFetching) || chartData.isFetching; + const error = chartData.isError + ? chartData.error + : specResults.find((q) => q?.isError)?.error; + + // For convenience, match each field to its corresponding data. + const resultMap = fields.reduce( + (acc, f, i) => { + acc[f.name] = specResults[i]?.data; + return acc; + }, + {} as Record< + string, + MetricsViewSpecMeasureV2 | MetricsViewSpecDimensionV2 | undefined + >, + ); + + return { + data: chartData?.data?.data || [], + isFetching, + error, + fields: resultMap, + }; + }, + ); +} + +export function createChartDataQuery( + ctx: StateManagers, + instanceId: string, + config: ChartConfig, + limit = "500", + offset = "0", +): CreateQueryResult<V1MetricsViewAggregationResponse, HTTPError> { + let measures: V1MetricsViewAggregationMeasure[] = []; + if (config.y?.field) { + measures = [{ name: config.y?.field }]; + } + + let dimensions: V1MetricsViewAggregationDimension[] = []; + + if (config.x?.field) { + dimensions = [{ name: config.x?.field }]; + } + if (typeof config.color === "object" && config.color?.field) { + dimensions = [...dimensions, { name: config.color.field }]; + } + + return derived( + [ + ctx.runtime, + useStartEndTime(instanceId, config.metrics_view, config.time_range), + ], + ([runtime, timeRange], set) => + createQueryServiceMetricsViewAggregation( + runtime.instanceId, + config.metrics_view, + { + measures, + dimensions, + where: undefined, + timeRange: { + start: timeRange?.data?.start?.toISOString() || undefined, + end: timeRange?.data?.end?.toISOString() || undefined, + }, + limit, + offset, + }, + { + query: { + enabled: !!timeRange.data, + queryClient: ctx.queryClient, + keepPreviousData: true, + }, + }, + ).subscribe(set), + ); +} diff --git a/web-common/src/features/canvas/components/charts/stacked-bar/spec.ts b/web-common/src/features/canvas/components/charts/stacked-bar/spec.ts new file mode 100644 index 00000000000..ea405afe0e4 --- /dev/null +++ b/web-common/src/features/canvas/components/charts/stacked-bar/spec.ts @@ -0,0 +1,51 @@ +import type { ChartConfig } from "@rilldata/web-common/features/canvas/components/charts/types"; +import type { VisualizationSpec } from "svelte-vega"; +import type { ChartDataResult } from "../selector"; + +export function generateVLStackedBarChartSpec( + config: ChartConfig, + data: ChartDataResult, +): VisualizationSpec { + return { + $schema: "https://vega.github.io/schema/vega-lite/v5.json", + mark: "bar", + width: "container", + data: { name: "metrics-view" }, + autosize: { type: "fit" }, + encoding: { + ...(config.x && { + x: { + field: config.x.field, + title: data.fields[config.x.field]?.displayName || config.x.field, + type: config.x.type, + ...(config.x.timeUnit && { timeUnit: config.x.timeUnit }), + }, + }), + ...(config.y && { + y: { + field: config.y.field, + title: data.fields[config.y.field]?.displayName || config.y.field, + type: config.y.type, + ...(config.y.timeUnit && { timeUnit: config.y.timeUnit }), + }, + }), + ...(config.color && + typeof config.color === "object" && { + color: { + field: config.color.field, + title: + data.fields[config.color.field]?.displayName || + config.color.field, + type: config.color.type, + ...(config.color.timeUnit && { + timeUnit: config.color.timeUnit, + }), + }, + }), + ...(config.color && + typeof config.color === "string" && { + color: { value: config.color }, + }), + }, + }; +} diff --git a/web-common/src/features/canvas/components/charts/types.ts b/web-common/src/features/canvas/components/charts/types.ts new file mode 100644 index 00000000000..4ab51c96bb2 --- /dev/null +++ b/web-common/src/features/canvas/components/charts/types.ts @@ -0,0 +1,27 @@ +import type { ComponentType, SvelteComponent } from "svelte"; + +export interface FieldConfig { + field: string; + label?: string; + format?: string; + type: "quantitative" | "ordinal" | "nominal" | "temporal" | "geojson"; + timeUnit?: string; // For temporal fields +} + +export interface ChartConfig { + metrics_view: string; + x?: FieldConfig; + y?: FieldConfig; + color?: FieldConfig | string; + tooltip?: FieldConfig; + // Temp options + time_range: string; +} + +export type ChartType = "line_chart" | "bar_chart" | "stacked_bar"; + +export interface ChartMetadata { + type: ChartType; + icon: ComponentType<SvelteComponent>; + title: string; +} diff --git a/web-common/src/features/canvas/components/charts/util.ts b/web-common/src/features/canvas/components/charts/util.ts new file mode 100644 index 00000000000..b4f9e0b06d8 --- /dev/null +++ b/web-common/src/features/canvas/components/charts/util.ts @@ -0,0 +1,31 @@ +import BarChart from "@rilldata/web-common/components/icons/BarChart.svelte"; +import LineChart from "@rilldata/web-common/components/icons/LineChart.svelte"; +import StackedBar from "@rilldata/web-common/components/icons/StackedBar.svelte"; +import { generateVLBarChartSpec } from "./bar-chart/spec"; +import { generateVLLineChartSpec } from "./line-chart/spec"; +import { generateVLStackedBarChartSpec } from "./stacked-bar/spec"; + +import type { ChartDataResult } from "./selector"; +import type { ChartConfig, ChartMetadata, ChartType } from "./types"; + +export function generateSpec( + chartType: ChartType, + chartConfig: ChartConfig, + data: ChartDataResult, +) { + if (data.isFetching || data.error) return {}; + switch (chartType) { + case "bar_chart": + return generateVLBarChartSpec(chartConfig, data); + case "stacked_bar": + return generateVLStackedBarChartSpec(chartConfig, data); + case "line_chart": + return generateVLLineChartSpec(chartConfig, data); + } +} + +export const chartMetadata: ChartMetadata[] = [ + { type: "line_chart", title: "Line", icon: LineChart }, + { type: "bar_chart", title: "Bar", icon: BarChart }, + { type: "stacked_bar", title: "Stacked Bar", icon: StackedBar }, +]; diff --git a/web-common/src/features/templates/image/Image.svelte b/web-common/src/features/canvas/components/image/Image.svelte similarity index 96% rename from web-common/src/features/templates/image/Image.svelte rename to web-common/src/features/canvas/components/image/Image.svelte index 13755209f3e..e5aa6eaf768 100644 --- a/web-common/src/features/templates/image/Image.svelte +++ b/web-common/src/features/canvas/components/image/Image.svelte @@ -3,11 +3,10 @@ import type { V1ComponentSpecRendererProperties } from "@rilldata/web-common/runtime-client"; import httpClient from "@rilldata/web-common/runtime-client/http-client"; import { runtime } from "@rilldata/web-common/runtime-client/runtime-store"; - import { get } from "svelte/store"; export let rendererProperties: V1ComponentSpecRendererProperties; - const instanceId = get(runtime).instanceId; + const instanceId = $runtime.instanceId; const DEFAULT_IMAGE_PROPERTIES: ImageProperties = { url: "", css: { diff --git a/web-common/src/features/canvas/components/image/index.ts b/web-common/src/features/canvas/components/image/index.ts new file mode 100644 index 00000000000..a9e6a7991a6 --- /dev/null +++ b/web-common/src/features/canvas/components/image/index.ts @@ -0,0 +1,47 @@ +import { BaseCanvasComponent } from "@rilldata/web-common/features/canvas/components/BaseCanvasComponent"; +import { type ComponentCommonProperties } from "@rilldata/web-common/features/canvas/components/types"; +import { commonOptions } from "@rilldata/web-common/features/canvas/components/util"; +import type { InputParams } from "@rilldata/web-common/features/canvas/inspector/types"; +import type { FileArtifact } from "@rilldata/web-common/features/entity-management/file-artifact"; + +export { default as Image } from "./Image.svelte"; + +export interface ImageSpec extends ComponentCommonProperties { + url: string; +} + +export class ImageComponent extends BaseCanvasComponent<ImageSpec> { + minSize = { width: 1, height: 1 }; + defaultSize = { width: 5, height: 5 }; + + constructor( + fileArtifact: FileArtifact, + path: (string | number)[] = [], + initialSpec: Partial<ImageSpec> = {}, + ) { + const defaultSpec: ImageSpec = { + url: "", + }; + super(fileArtifact, path, defaultSpec, initialSpec); + } + + isValid(spec: ImageSpec): boolean { + return typeof spec.url === "string" && spec.url.trim().length > 0; + } + + inputParams(): InputParams<ImageSpec> { + return { + component: { + url: { type: "text", label: "URL" }, + ...commonOptions, + }, + filter: [], + }; + } + + newComponentSpec(): ImageSpec { + return { + url: "https://cdn.prod.website-files.com/659ddac460dbacbdc813b204/660b0f85094eb576187342cf_rill_logo_sq_gradient.svg", + }; + } +} diff --git a/web-common/src/features/canvas/components/kpi/KPI.svelte b/web-common/src/features/canvas/components/kpi/KPI.svelte new file mode 100644 index 00000000000..3a82703b75a --- /dev/null +++ b/web-common/src/features/canvas/components/kpi/KPI.svelte @@ -0,0 +1,192 @@ +<script lang="ts"> + import { SimpleDataGraphic } from "@rilldata/web-common/components/data-graphic/elements"; + import { ChunkedLine } from "@rilldata/web-common/components/data-graphic/marks"; + import PercentageChange from "@rilldata/web-common/components/data-types/PercentageChange.svelte"; + import { + MainAreaColorGradientDark, + MainAreaColorGradientLight, + MainLineColor, + } from "@rilldata/web-common/features/dashboards/time-series/chart-colors"; + import Spinner from "@rilldata/web-common/features/entity-management/Spinner.svelte"; + import { EntityStatus } from "@rilldata/web-common/features/entity-management/types"; + import { createMeasureValueFormatter } from "@rilldata/web-common/lib/number-formatting/format-measure-value"; + import { FormatPreset } from "@rilldata/web-common/lib/number-formatting/humanizer-types"; + import { formatMeasurePercentageDifference } from "@rilldata/web-common/lib/number-formatting/percentage-formatter"; + import { humaniseISODuration } from "@rilldata/web-common/lib/time/ranges/iso-ranges"; + import type { V1ComponentSpecRendererProperties } from "@rilldata/web-common/runtime-client"; + import { runtime } from "@rilldata/web-common/runtime-client/runtime-store"; + import { useQueryClient } from "@tanstack/svelte-query"; + import { extent } from "d3-array"; + import type { KPISpec } from "."; + import { useMetricsViewSpecMeasure } from "../selectors"; + import { + useKPIComparisonTotal, + useKPISparkline, + useKPITotals, + } from "./selector"; + + export let rendererProperties: V1ComponentSpecRendererProperties; + + const queryClient = useQueryClient(); + let containerWidth: number; + let containerHeight: number; + + $: instanceId = $runtime?.instanceId; + $: kpiProperties = rendererProperties as KPISpec; + + $: ({ + metrics_view: metricsViewName, + measure: measureName, + time_range: timeRange, + sparkline: showSparkline, + comparison_range: comparisonTimeRange, + } = kpiProperties); + + $: measureQuery = useMetricsViewSpecMeasure( + instanceId, + metricsViewName, + measureName, + ); + + $: measure = $measureQuery?.data; + + $: measureValue = useKPITotals( + instanceId, + metricsViewName, + measureName, + timeRange.toUpperCase(), + ); + + $: comparisonValue = useKPIComparisonTotal( + instanceId, + metricsViewName, + measureName, + comparisonTimeRange?.toUpperCase(), + timeRange.toUpperCase(), + undefined, + queryClient, + ); + + $: sparkline = useKPISparkline( + instanceId, + metricsViewName, + measureName, + timeRange.toUpperCase(), + undefined, + queryClient, + ); + + $: sparkData = $sparkline?.data || []; + + const focusedAreaGradient: [string, string] = [ + MainAreaColorGradientDark, + MainAreaColorGradientLight, + ]; + + $: [yMin, yMax] = extent(sparkData, (d) => d[measureName]); + $: [xMin, xMax] = extent(sparkData, (d) => d["ts"]); + + $: measureValueFormatter = measure + ? createMeasureValueFormatter<null>(measure, "big-number") + : () => "no data"; + + $: measureValueFormatted = + measureValueFormatter($measureValue.data) ?? "no data"; + + $: comparisonPercChange = + $comparisonValue.data && + $measureValue.data !== undefined && + $measureValue.data !== null + ? ($measureValue.data - $comparisonValue.data) / $comparisonValue.data + : undefined; + + $: measureIsPercentage = measure?.formatPreset === FormatPreset.PERCENTAGE; + + function getFormattedDiff(comparisonValue) { + const delta = $measureValue.data - comparisonValue; + return `${delta >= 0 ? "+" : ""}${measureValueFormatter(delta)}`; + } +</script> + +{#if measure} + <div + bind:clientWidth={containerWidth} + bind:clientHeight={containerHeight} + class="flex flex-col h-full w-full bg-white p-4" + > + <div class="flex justify-between items-center mb-2"> + <span class="font-semibold text-lg truncate pr-2" + >{measure?.displayName || measureName}</span + > + {#if comparisonTimeRange && $comparisonValue.data} + <span class="text-sm text-gray-500"> + vs last {humaniseISODuration( + comparisonTimeRange?.toUpperCase(), + false, + )} + </span> + {/if} + </div> + + <div class="flex justify-between items-center mb-2"> + <span class="text-2xl font-light">{measureValueFormatted}</span> + {#if $comparisonValue.data} + <div class="flex items-baseline gap-x-3 text-sm"> + <div + role="complementary" + class="w-fit max-w-full overflow-hidden text-ellipsis ui-copy-inactive" + class:font-semibold={$measureValue.data >= 0} + > + {#if $comparisonValue.data != null} + {getFormattedDiff($comparisonValue.data)} + {:else} + <span class="ui-copy-disabled-faint italic" style:font-size=".9em" + >no change</span + > + {/if} + </div> + {#if comparisonPercChange != null && !measureIsPercentage} + <div + role="complementary" + class="w-fit ui-copy-inactive" + class:text-red-500={$measureValue.data < 0} + > + <PercentageChange + tabularNumber={false} + value={formatMeasurePercentageDifference(comparisonPercChange)} + /> + </div> + {/if} + </div> + {/if} + </div> + + {#if containerHeight && containerWidth && showSparkline && sparkData.length} + <SimpleDataGraphic + height={containerHeight - 90} + width={containerWidth - 16} + overflowHidden={false} + top={10} + bottom={0} + right={10} + left={0} + {xMin} + {xMax} + {yMin} + {yMax} + > + <ChunkedLine + lineColor={MainLineColor} + areaGradientColors={focusedAreaGradient} + data={sparkData} + xAccessor="ts" + yAccessor={measureName} + /> + </SimpleDataGraphic> + {/if} + </div> +{:else} + <div class="flex items-center justify-center w-24"> + <Spinner status={EntityStatus.Running} /> + </div> +{/if} diff --git a/web-common/src/features/canvas/components/kpi/index.ts b/web-common/src/features/canvas/components/kpi/index.ts new file mode 100644 index 00000000000..96c27ade821 --- /dev/null +++ b/web-common/src/features/canvas/components/kpi/index.ts @@ -0,0 +1,70 @@ +import { BaseCanvasComponent } from "@rilldata/web-common/features/canvas/components/BaseCanvasComponent"; +import { + commonOptions, + getFilterOptions, +} from "@rilldata/web-common/features/canvas/components/util"; +import type { InputParams } from "@rilldata/web-common/features/canvas/inspector/types"; +import type { FileArtifact } from "@rilldata/web-common/features/entity-management/file-artifact"; +import { type ComponentCommonProperties } from "../types"; + +export { default as KPI } from "./KPI.svelte"; + +export interface KPISpec extends ComponentCommonProperties { + metrics_view: string; + measure: string; + time_range: string; + sparkline?: boolean; + comparison_range?: string; +} + +export class KPIComponent extends BaseCanvasComponent<KPISpec> { + minSize = { width: 2, height: 2 }; + defaultSize = { width: 8, height: 4 }; + + constructor( + fileArtifact: FileArtifact, + path: (string | number)[] = [], + initialSpec: Partial<KPISpec> = {}, + ) { + const defaultSpec: KPISpec = { + metrics_view: "", + measure: "", + time_range: "PT24H", + sparkline: true, + }; + super(fileArtifact, path, defaultSpec, initialSpec); + } + + isValid(spec: KPISpec): boolean { + return ( + typeof spec.measure === "string" && typeof spec.time_range === "string" + ); + } + + inputParams(): InputParams<KPISpec> { + return { + component: { + metrics_view: { type: "metrics", label: "Metrics view" }, + measure: { type: "measure", label: "Measure" }, + sparkline: { type: "boolean", optional: true, label: "Sparkline" }, + time_range: { type: "rill_time", label: "Time Range" }, + comparison_range: { + type: "rill_time", + label: "Comparison Range", + optional: true, + }, + ...commonOptions, + }, + filter: getFilterOptions(), + }; + } + + newComponentSpec(metrics_view: string, measure: string): KPISpec { + return { + metrics_view, + measure, + time_range: "PT24H", + sparkline: true, + }; + } +} diff --git a/web-common/src/features/templates/kpi/selector.ts b/web-common/src/features/canvas/components/kpi/selector.ts similarity index 98% rename from web-common/src/features/templates/kpi/selector.ts rename to web-common/src/features/canvas/components/kpi/selector.ts index 80df2869890..5d4774e00bf 100644 --- a/web-common/src/features/templates/kpi/selector.ts +++ b/web-common/src/features/canvas/components/kpi/selector.ts @@ -14,7 +14,6 @@ export function useKPITotals( metricsViewName: string, measure: string, timeRange: string, - whereSql: string | undefined, ) { return createQueryServiceMetricsViewAggregation( instanceId, @@ -22,7 +21,6 @@ export function useKPITotals( { measures: [{ name: measure }], timeRange: { isoDuration: timeRange }, - whereSql, }, { query: { diff --git a/web-common/src/features/templates/markdown/Markdown.svelte b/web-common/src/features/canvas/components/markdown/Markdown.svelte similarity index 80% rename from web-common/src/features/templates/markdown/Markdown.svelte rename to web-common/src/features/canvas/components/markdown/Markdown.svelte index 6642662ba66..ce7b9cd10d3 100644 --- a/web-common/src/features/templates/markdown/Markdown.svelte +++ b/web-common/src/features/canvas/components/markdown/Markdown.svelte @@ -1,8 +1,8 @@ <script lang="ts"> - import DOMPurify from "dompurify"; - import { marked } from "marked"; import type { MarkdownProperties } from "@rilldata/web-common/features/templates/types"; import type { V1ComponentSpecRendererProperties } from "@rilldata/web-common/runtime-client"; + import DOMPurify from "dompurify"; + import { marked } from "marked"; export let rendererProperties: V1ComponentSpecRendererProperties; @@ -15,10 +15,17 @@ </script> <div - class="markdown size-full items-center flex justify-center" + class="markdown size-full items-center flex justify-center bg-white" style={styleString} > {#await marked(markdownProperties.content) then content} {@html DOMPurify.sanitize(content)} {/await} </div> + +<style lang="postcss"> + :global(.markdown h1) { + font-size: 2em; + font-weight: 500; + } +</style> diff --git a/web-common/src/features/canvas/components/markdown/index.ts b/web-common/src/features/canvas/components/markdown/index.ts new file mode 100644 index 00000000000..1704098a00b --- /dev/null +++ b/web-common/src/features/canvas/components/markdown/index.ts @@ -0,0 +1,49 @@ +import { BaseCanvasComponent } from "@rilldata/web-common/features/canvas/components/BaseCanvasComponent"; +import { commonOptions } from "@rilldata/web-common/features/canvas/components/util"; +import type { InputParams } from "@rilldata/web-common/features/canvas/inspector/types"; +import type { FileArtifact } from "@rilldata/web-common/features/entity-management/file-artifact"; +import { type ComponentCommonProperties } from "../types"; + +export { default as Markdown } from "./Markdown.svelte"; + +export interface MarkdownSpec extends ComponentCommonProperties { + content: string; +} + +export class MarkdownCanvasComponent extends BaseCanvasComponent<MarkdownSpec> { + minSize = { width: 1, height: 1 }; + defaultSize = { width: 6, height: 2 }; + + constructor( + fileArtifact: FileArtifact, + path: (string | number)[] = [], + initialSpec: Partial<MarkdownSpec> = {}, + ) { + const defaultSpec: MarkdownSpec = { + title: "", + description: "", + content: "Your text", + }; + super(fileArtifact, path, defaultSpec, initialSpec); + } + + isValid(spec: MarkdownSpec): boolean { + return typeof spec.content === "string" && spec.content.trim().length > 0; + } + + inputParams(): InputParams<MarkdownSpec> { + return { + component: { + content: { type: "textArea" }, + ...commonOptions, + }, + filter: [], + }; + } + + newComponentSpec(): MarkdownSpec { + return { + content: "Markdown Text", + }; + } +} diff --git a/web-common/src/features/canvas/components/selectors.ts b/web-common/src/features/canvas/components/selectors.ts new file mode 100644 index 00000000000..81a308d6c50 --- /dev/null +++ b/web-common/src/features/canvas/components/selectors.ts @@ -0,0 +1,40 @@ +import { useMetricsViewValidSpec } from "@rilldata/web-common/features/dashboards/selectors"; + +export const useMetricsViewSpecMeasure = ( + instanceId: string, + metricsViewName: string, + measureName: string, +) => + useMetricsViewValidSpec(instanceId, metricsViewName, (meta) => + meta?.measures?.find((measure) => measure.name === measureName), + ); + +export const useMetricsViewSpecDimension = ( + instanceId: string, + metricsViewName: string, + dimensionName: string, +) => + useMetricsViewValidSpec(instanceId, metricsViewName, (meta) => + meta?.dimensions?.find( + (dimension) => + dimension.name === dimensionName || dimension.column === dimensionName, + ), + ); + +export function useMeasureDimensionSpec( + instanceId: string, + metricsViewName: string, + fields: { name: string; type: "dimension" | "measure" }[], +) { + return fields.map((field) => { + if (field.type === "measure") { + return useMetricsViewSpecMeasure(instanceId, metricsViewName, field.name); + } else { + return useMetricsViewSpecDimension( + instanceId, + metricsViewName, + field.name, + ); + } + }); +} diff --git a/web-common/src/features/templates/table/TableRenderer.svelte b/web-common/src/features/canvas/components/table/TableRenderer.svelte similarity index 99% rename from web-common/src/features/templates/table/TableRenderer.svelte rename to web-common/src/features/canvas/components/table/TableRenderer.svelte index 8c13f90f6af..bbb361c5a00 100644 --- a/web-common/src/features/templates/table/TableRenderer.svelte +++ b/web-common/src/features/canvas/components/table/TableRenderer.svelte @@ -426,8 +426,8 @@ .table-wrapper { @apply overflow-auto h-fit max-h-full w-fit max-w-full; - @apply border z-40; - width: calc(100% - 5px); + @apply bg-white border z-40; + width: 100%; } /* Pin header */ @@ -445,11 +445,6 @@ @apply border-r border-b relative; } - th:last-of-type, - td:last-of-type { - @apply border-r-0; - } - th, td { @apply whitespace-nowrap text-xs; diff --git a/web-common/src/features/templates/table/TableTemplate.svelte b/web-common/src/features/canvas/components/table/TableTemplate.svelte similarity index 95% rename from web-common/src/features/templates/table/TableTemplate.svelte rename to web-common/src/features/canvas/components/table/TableTemplate.svelte index adf831da84e..92273aac1e9 100644 --- a/web-common/src/features/templates/table/TableTemplate.svelte +++ b/web-common/src/features/canvas/components/table/TableTemplate.svelte @@ -7,13 +7,13 @@ type PivotState, } from "@rilldata/web-common/features/dashboards/pivot/types"; import { createStateManagers } from "@rilldata/web-common/features/dashboards/state-managers/state-managers"; - import TableRenderer from "@rilldata/web-common/features/templates/table/TableRenderer.svelte"; import type { TableProperties } from "@rilldata/web-common/features/templates/types"; import type { V1ComponentSpecRendererProperties } from "@rilldata/web-common/runtime-client"; import { runtime } from "@rilldata/web-common/runtime-client/runtime-store"; import { useQueryClient } from "@tanstack/svelte-query"; import { type Readable, writable } from "svelte/store"; import { getTableConfig, hasValidTableSchema } from "./selector"; + import TableRenderer from "./TableRenderer.svelte"; export let rendererProperties: V1ComponentSpecRendererProperties; @@ -78,7 +78,7 @@ } </script> -<div class="overflow-y-scroll"> +<div class="overflow-y-auto"> {#if !isValidSchema} <div>{$tableSchema.error}</div> {:else if pivotDataStore && pivotConfig && $pivotConfig} diff --git a/web-common/src/features/canvas/components/table/index.ts b/web-common/src/features/canvas/components/table/index.ts new file mode 100644 index 00000000000..114ca2ddf21 --- /dev/null +++ b/web-common/src/features/canvas/components/table/index.ts @@ -0,0 +1,85 @@ +import { BaseCanvasComponent } from "@rilldata/web-common/features/canvas/components/BaseCanvasComponent"; +import { + commonOptions, + getFilterOptions, +} from "@rilldata/web-common/features/canvas/components/util"; +import type { InputParams } from "@rilldata/web-common/features/canvas/inspector/types"; +import type { FileArtifact } from "@rilldata/web-common/features/entity-management/file-artifact"; +import { type ComponentCommonProperties } from "../types"; + +export { default as Table } from "./TableTemplate.svelte"; + +export interface TableSpec extends ComponentCommonProperties { + metrics_view: string; + time_range: string; + measures: string[]; + comparison_range?: string; + row_dimensions?: string[]; + col_dimensions?: string[]; +} + +export class TableCanvasComponent extends BaseCanvasComponent<TableSpec> { + minSize = { width: 2, height: 2 }; + defaultSize = { width: 16, height: 10 }; + + constructor( + fileArtifact: FileArtifact, + path: (string | number)[] = [], + initialSpec: Partial<TableSpec> = {}, + ) { + const defaultSpec: TableSpec = { + metrics_view: "", + measures: [], + time_range: "", + comparison_range: "", + row_dimensions: [], + col_dimensions: [], + }; + super(fileArtifact, path, defaultSpec, initialSpec); + } + + isValid(spec: TableSpec): boolean { + return ( + typeof spec.time_range === "string" && + ((Array.isArray(spec.measures) && spec.measures.length > 0) || + (Array.isArray(spec.row_dimensions) && + spec.row_dimensions.length > 0) || + (Array.isArray(spec.col_dimensions) && spec.col_dimensions.length > 0)) + ); + } + + inputParams(): InputParams<TableSpec> { + return { + component: { + metrics_view: { type: "metrics", label: "Metrics view" }, + measures: { type: "multi_measures", label: "Measures" }, + col_dimensions: { + type: "multi_dimensions", + label: "Column dimensions", + }, + row_dimensions: { type: "multi_dimensions", label: "Row dimensions" }, + time_range: { type: "rill_time", label: "Time range" }, + comparison_range: { + type: "rill_time", + label: "Comparison range", + optional: true, + }, + ...commonOptions, + }, + filter: getFilterOptions(), + }; + } + + newComponentSpec( + metrics_view: string, + measure: string, + dimension: string, + ): TableSpec { + return { + metrics_view, + measures: [measure], + row_dimensions: [dimension], + time_range: "PT24H", + }; + } +} diff --git a/web-common/src/features/templates/table/selector.ts b/web-common/src/features/canvas/components/table/selector.ts similarity index 98% rename from web-common/src/features/templates/table/selector.ts rename to web-common/src/features/canvas/components/table/selector.ts index 35b2d2aa1a4..05d8a3a9487 100644 --- a/web-common/src/features/templates/table/selector.ts +++ b/web-common/src/features/canvas/components/table/selector.ts @@ -1,3 +1,4 @@ +import { useStartEndTime } from "@rilldata/web-common/features/canvas/components/kpi/selector"; import { canEnablePivotComparison } from "@rilldata/web-common/features/dashboards/pivot/pivot-utils"; import { COMPARISON_DELTA, @@ -10,7 +11,6 @@ import { useMetricsViewValidSpec, } from "@rilldata/web-common/features/dashboards/selectors"; import { createAndExpression } from "@rilldata/web-common/features/dashboards/stores/filter-utils"; -import { useStartEndTime } from "@rilldata/web-common/features/templates/kpi/selector"; import type { TableProperties } from "@rilldata/web-common/features/templates/types"; import { validateDimensions, diff --git a/web-common/src/features/canvas/components/types.ts b/web-common/src/features/canvas/components/types.ts new file mode 100644 index 00000000000..2e179f57bc2 --- /dev/null +++ b/web-common/src/features/canvas/components/types.ts @@ -0,0 +1,113 @@ +import type { Writable } from "svelte/store"; +import type { InputParams } from "../inspector/types"; +import type { ChartConfig, ChartType } from "./charts/types"; +import type { ImageSpec } from "./image"; +import type { KPISpec } from "./kpi"; +import type { MarkdownSpec } from "./markdown"; +import type { TableSpec } from "./table"; + +// First, let's create a union type for all possible specs +export type ComponentSpec = + | ChartConfig + | TableSpec + | ImageSpec + | KPISpec + | MarkdownSpec; + +// The CanvasComponent interface is generic over the spec type. +export interface CanvasComponent<T> { + /** + * Svelte writable for the spec + */ + specStore: Writable<T>; + + /** + * Path in the YAML where the component is stored + */ + pathInYAML: (string | number)[]; + + /** + * Minimum allowed size for the component + * container on the canvas + */ + minSize: ComponentSize; + + /** + * The default size of the container when the component + * is added to the canvas + */ + defaultSize: ComponentSize; + + /** + * The minimum condition needed for the spec to be valid + * for the given component and to be rendered on the canvas + */ + isValid(spec: T): boolean; + + /** + * A map of input params which will be used in the visual + * UI builder + */ + inputParams(): InputParams<T>; + + /** + * Get the spec when the component is added to the canvas + */ + newComponentSpec(metrics_view: string, measure: string, dimension: string): T; + + /** + * Update the spec store with the new values + */ + updateProperty(key: string, value: unknown): Promise<void>; + + /** + * Set the spec store with the new values + */ + setSpec(spec: T): Promise<void>; +} + +export interface ComponentCommonProperties { + title?: string; + description?: string; +} + +export interface ComponentSize { + width: number; + height: number; +} + +export type CanvasComponentType = + | ChartType + | "markdown" + | "kpi" + | "image" + | "table"; + +interface LineChart { + line_chart: ChartConfig; +} + +interface BarChart { + bar_chart: ChartConfig; +} + +export type ChartTemplates = LineChart | BarChart; +export interface KPITemplateT { + kpi: KPISpec; +} +export interface MarkdownTemplateT { + markdown: MarkdownSpec; +} +export interface ImageTemplateT { + image: ImageSpec; +} +export interface TableTemplateT { + table: TableSpec; +} + +export type TemplateSpec = + | ChartTemplates + | KPITemplateT + | TableTemplateT + | MarkdownTemplateT + | ImageTemplateT; diff --git a/web-common/src/features/canvas/components/util.ts b/web-common/src/features/canvas/components/util.ts new file mode 100644 index 00000000000..35dd86ddf75 --- /dev/null +++ b/web-common/src/features/canvas/components/util.ts @@ -0,0 +1,125 @@ +import type { + ComponentInputParam, + FilterInputParam, + FilterInputTypes, +} from "@rilldata/web-common/features/canvas/inspector/types"; +import type { FileArtifact } from "@rilldata/web-common/features/entity-management/file-artifact"; +import { ChartComponent } from "./charts"; +import { ImageComponent } from "./image"; +import { KPIComponent } from "./kpi"; +import { MarkdownCanvasComponent } from "./markdown"; +import { TableCanvasComponent } from "./table"; +import type { CanvasComponentType, ComponentCommonProperties } from "./types"; + +export const commonOptions: Record< + keyof ComponentCommonProperties, + ComponentInputParam +> = { + title: { type: "text", optional: true, showInUI: true, label: "Title" }, + description: { + type: "text", + optional: true, + showInUI: true, + label: "Description", + }, + // position: { type: "text", showInUI: false }, +}; + +export function getFilterOptions( + includeComparisonRange = true, +): Partial<Record<FilterInputTypes, FilterInputParam>> { + const options: Partial<Record<FilterInputTypes, FilterInputParam>> = { + time_range: { type: "time_range", label: "Time Range" }, + dimension_filters: { + type: "dimension_filters", + label: "Dimension Filters", + }, + }; + if (includeComparisonRange) { + options.comparison_range = { + type: "comparison_range", + label: "Comparison Range", + }; + } + return options; +} + +export const getComponentObj = ( + fileArtifact: FileArtifact, + path: (string | number)[], + type: CanvasComponentType, + params: Record<string, unknown>, +) => { + switch (type) { + case "markdown": + return new MarkdownCanvasComponent(fileArtifact, path, params); + case "kpi": + return new KPIComponent(fileArtifact, path, params); + case "image": + return new ImageComponent(fileArtifact, path, params); + case "table": + return new TableCanvasComponent(fileArtifact, path, params); + default: + return new ChartComponent(fileArtifact, path, params); + } +}; + +export type CanvasComponentObj = ReturnType<typeof getComponentObj>; + +// TODO: Apply DRY +export function isCanvasComponentType( + value: string | undefined, +): value is CanvasComponentType { + if (!value) return false; + return [ + "line_chart", + "bar_chart", + "stacked_bar", + "markdown", + "kpi", + "image", + "table", + ].includes(value as CanvasComponentType); +} + +export function isChartComponentType( + value: string | undefined, +): value is CanvasComponentType { + if (!value) return false; + return ["line_chart", "bar_chart", "stacked_bar"].includes( + value as CanvasComponentType, + ); +} + +export function getComponentRegistry( + fileArtifact: FileArtifact, +): Record<CanvasComponentType, CanvasComponentObj> { + return { + kpi: new KPIComponent(fileArtifact), + markdown: new MarkdownCanvasComponent(fileArtifact), + table: new TableCanvasComponent(fileArtifact), + image: new ImageComponent(fileArtifact), + bar_chart: new ChartComponent(fileArtifact), + line_chart: new ChartComponent(fileArtifact), + stacked_bar: new ChartComponent(fileArtifact), + }; +} + +// TODO: Move to config +const displayMap: Record<CanvasComponentType, string> = { + kpi: "KPI", + markdown: "Markdown", + table: "Table", + image: "Image", + bar_chart: "Chart", + line_chart: "Chart", + stacked_bar: "Chart", +}; + +export function getHeaderForComponent(componentType: string | undefined) { + if (!componentType) return "Component"; + if (!displayMap[componentType as CanvasComponentType]) { + return "Component"; + } + return displayMap[componentType as CanvasComponentType]; +} diff --git a/web-common/src/features/canvas/constants.ts b/web-common/src/features/canvas/constants.ts index 57bb5932ce9..cac65410b17 100644 --- a/web-common/src/features/canvas/constants.ts +++ b/web-common/src/features/canvas/constants.ts @@ -1,4 +1,4 @@ -export const DASHBOARD_WIDTH = 1600; +export const DASHBOARD_WIDTH = 1200; export const COMPONENT_RADIUS = 0.08; export const FONT_SIZE = 40; export const COMPONENT_WIDTH = 1; diff --git a/web-common/src/features/canvas/filters/CanvasComparisonPill.svelte b/web-common/src/features/canvas/filters/CanvasComparisonPill.svelte new file mode 100644 index 00000000000..273fa7e689f --- /dev/null +++ b/web-common/src/features/canvas/filters/CanvasComparisonPill.svelte @@ -0,0 +1,131 @@ +<script lang="ts"> + import Label from "@rilldata/web-common/components/forms/Label.svelte"; + import Switch from "@rilldata/web-common/components/forms/Switch.svelte"; + import { getComparisonOptionsForCanvas } from "@rilldata/web-common/features/canvas/filters/util"; + import { getCanvasStateManagers } from "@rilldata/web-common/features/canvas/state-managers/state-managers"; + import { Comparison } from "@rilldata/web-common/features/dashboards/time-controls/super-pill/components"; + import { + TimeComparisonOption, + TimeRangePreset, + type DashboardTimeControls, + type TimeRange, + } from "@rilldata/web-common/lib/time/types"; + import { DateTime, Interval } from "luxon"; + + export let allTimeRange: TimeRange; + export let selectedTimeRange: DashboardTimeControls | undefined; + export let selectedComparisonTimeRange: DashboardTimeControls | undefined; + + const { canvasEntity } = getCanvasStateManagers(); + + const { timeControls } = canvasEntity; + + $: showTimeComparison = timeControls.showTimeComparison; + $: activeTimeZone = timeControls?.selectedTimezone; + + $: interval = selectedTimeRange + ? Interval.fromDateTimes( + DateTime.fromJSDate(selectedTimeRange.start).setZone($activeTimeZone), + DateTime.fromJSDate(selectedTimeRange.end).setZone($activeTimeZone), + ) + : Interval.fromDateTimes(allTimeRange.start, allTimeRange.end); + + $: activeTimeGrain = selectedTimeRange?.interval; + + $: comparisonOptions = getComparisonOptionsForCanvas(selectedTimeRange); + + function onSelectComparisonRange( + name: TimeComparisonOption, + start: Date, + end: Date, + ) { + timeControls.setSelectedComparisonRange({ + name, + start, + end, + }); + + if (!$showTimeComparison) { + timeControls.displayTimeComparison(!$showTimeComparison); + } + } + + $: disabled = + selectedTimeRange?.name === TimeRangePreset.ALL_TIME || undefined; +</script> + +<div + class="wrapper" + title={disabled && "Comparison not available when viewing all time range"} +> + <button + {disabled} + class="flex gap-x-1.5 cursor-pointer" + on:click={() => { + timeControls.displayTimeComparison(!$showTimeComparison); + }} + > + <div class="pointer-events-none flex items-center gap-x-1.5"> + <Switch + checked={$showTimeComparison} + id="comparing" + small + disabled={disabled ?? false} + /> + + <Label class="font-normal text-xs cursor-pointer" for="comparing"> + <span class:opacity-50={disabled}>Comparing</span> + </Label> + </div> + </button> + {#if activeTimeGrain && interval.isValid} + <Comparison + maxDate={DateTime.fromJSDate(allTimeRange.end)} + minDate={DateTime.fromJSDate(allTimeRange.start)} + timeComparisonOptionsState={comparisonOptions} + selectedComparison={selectedComparisonTimeRange} + showComparison={$showTimeComparison} + currentInterval={interval} + grain={activeTimeGrain} + zone={$activeTimeZone} + {onSelectComparisonRange} + disabled={disabled ?? false} + /> + {/if} +</div> + +<style lang="postcss"> + .wrapper { + @apply flex w-fit; + @apply h-7 rounded-full; + @apply overflow-hidden select-none; + } + + :global(.wrapper > button) { + @apply border; + } + + :global(.wrapper > button:not(:first-child)) { + @apply -ml-[1px]; + } + + :global(.wrapper > button) { + @apply border; + @apply px-2 flex items-center justify-center bg-white; + } + + :global(.wrapper > button:first-child) { + @apply pl-2.5 rounded-l-full; + } + :global(.wrapper > button:last-child) { + @apply pr-2.5 rounded-r-full; + } + + :global(.wrapper > button:hover:not(:disabled)) { + @apply bg-gray-50 cursor-pointer; + } + + :global(.wrapper > [data-state="open"]) { + @apply bg-gray-50 border-gray-400 z-50; + } +</style> diff --git a/web-common/src/features/canvas/filters/CanvasFilters.svelte b/web-common/src/features/canvas/filters/CanvasFilters.svelte new file mode 100644 index 00000000000..f59a3dc3b02 --- /dev/null +++ b/web-common/src/features/canvas/filters/CanvasFilters.svelte @@ -0,0 +1,41 @@ +<script lang="ts"> + import Calendar from "@rilldata/web-common/components/icons/Calendar.svelte"; + import CanvasGrainSelector from "@rilldata/web-common/features/canvas/filters/CanvasGrainSelector.svelte"; + import { getCanvasStateManagers } from "@rilldata/web-common/features/canvas/state-managers/state-managers"; + import { TimeRangePreset } from "@rilldata/web-common/lib/time/types"; + import CanvasComparisonPill from "./CanvasComparisonPill.svelte"; + import CanvasSuperPill from "./CanvasSuperPill.svelte"; + + const { canvasEntity } = getCanvasStateManagers(); + const { timeControls } = canvasEntity; + + $: selectedTimeRange = timeControls.selectedTimeRange; + $: selectedComparisonTimeRange = timeControls?.selectedComparisonTimeRange; + $: activeTimeZone = timeControls.selectedTimezone; + + const allTimeRange = { + name: TimeRangePreset.ALL_TIME, + start: new Date(0), + end: new Date(), + }; +</script> + +<div class="flex flex-col gap-y-2 w-full h-20 justify-center ml-2"> + <div class="flex flex-row flex-wrap gap-x-2 gap-y-1.5 items-center"> + <Calendar size="16px" /> + <CanvasSuperPill + {allTimeRange} + selectedTimeRange={$selectedTimeRange} + activeTimeZone={$activeTimeZone} + /> + <CanvasComparisonPill + {allTimeRange} + selectedTimeRange={$selectedTimeRange} + selectedComparisonTimeRange={$selectedComparisonTimeRange} + /> + <CanvasGrainSelector + selectedTimeRange={$selectedTimeRange} + selectedComparisonTimeRange={$selectedComparisonTimeRange} + /> + </div> +</div> diff --git a/web-common/src/features/canvas/filters/CanvasGrainSelector.svelte b/web-common/src/features/canvas/filters/CanvasGrainSelector.svelte new file mode 100644 index 00000000000..f878e53e672 --- /dev/null +++ b/web-common/src/features/canvas/filters/CanvasGrainSelector.svelte @@ -0,0 +1,119 @@ +<script lang="ts"> + import Chip from "@rilldata/web-common/components/chip/core/Chip.svelte"; + import * as DropdownMenu from "@rilldata/web-common/components/dropdown-menu"; + import { getCanvasStateManagers } from "@rilldata/web-common/features/canvas/state-managers/state-managers"; + import { TIME_GRAIN } from "@rilldata/web-common/lib/time/config"; + import { + getAllowedTimeGrains, + isGrainBigger, + } from "@rilldata/web-common/lib/time/grains"; + import type { + AvailableTimeGrain, + DashboardTimeControls, + TimeGrain, + TimeRange, + } from "@rilldata/web-common/lib/time/types"; + import { V1TimeGrain } from "@rilldata/web-common/runtime-client"; + + export let selectedTimeRange: DashboardTimeControls | undefined; + export let selectedComparisonTimeRange: DashboardTimeControls | undefined; + + const { canvasEntity } = getCanvasStateManagers(); + + let timeGrainOptions: TimeGrain[]; + // TODO: Change this + let minTimeGrain = V1TimeGrain.TIME_GRAIN_UNSPECIFIED; + let open = false; + + $: timeGrainOptions = + selectedTimeRange?.start && selectedTimeRange?.end + ? getAllowedTimeGrains( + new Date(selectedTimeRange.start), + new Date(selectedTimeRange.end), + ) + : []; + + $: baseTimeRange = selectedTimeRange?.start && + selectedTimeRange?.end && { + name: selectedTimeRange?.name, + start: selectedTimeRange.start, + end: selectedTimeRange.end, + }; + + $: activeTimeGrain = selectedTimeRange?.interval; + $: activeTimeGrainLabel = + activeTimeGrain && TIME_GRAIN[activeTimeGrain as AvailableTimeGrain]?.label; + + $: capitalizedLabel = activeTimeGrainLabel + ?.split(" ") + .map((word) => { + return word.charAt(0).toUpperCase() + word.slice(1); + }) + .join(" "); + + $: timeGrains = minTimeGrain + ? timeGrainOptions + .filter((timeGrain) => !isGrainBigger(minTimeGrain, timeGrain.grain)) + .map((timeGrain) => { + return { + main: timeGrain.label, + key: timeGrain.grain, + }; + }) + : []; + + function onTimeGrainSelect(timeGrain: V1TimeGrain) { + if (baseTimeRange) { + makeTimeSeriesTimeRangeAndUpdateAppState( + baseTimeRange, + timeGrain, + selectedComparisonTimeRange, + ); + } + } + + function makeTimeSeriesTimeRangeAndUpdateAppState( + timeRange: TimeRange, + timeGrain: V1TimeGrain, + /** we should only reset the comparison range when the user has explicitly chosen a new + * time range. Otherwise, the current comparison state should continue to be the + * source of truth. + */ + comparisonTimeRange: DashboardTimeControls | undefined, + ) { + canvasEntity.timeControls.selectTimeRange( + timeRange, + timeGrain, + comparisonTimeRange, + ); + } +</script> + +{#if activeTimeGrain && timeGrainOptions.length && minTimeGrain} + <DropdownMenu.Root bind:open> + <DropdownMenu.Trigger asChild let:builder> + <Chip + type="time" + builders={[builder]} + active={open} + label="Select a time grain" + > + <div slot="body" class="flex gap-x-2 items-center"> + <span>by {capitalizedLabel}</span> + </div> + </Chip> + </DropdownMenu.Trigger> + <DropdownMenu.Content class="min-w-40" align="start"> + {#each timeGrains as option (option.key)} + <DropdownMenu.CheckboxItem + role="menuitem" + checked={option.key === activeTimeGrain} + class="text-xs cursor-pointer" + on:click={() => onTimeGrainSelect(option.key)} + > + {option.main} + </DropdownMenu.CheckboxItem> + {/each} + </DropdownMenu.Content> + </DropdownMenu.Root> +{/if} diff --git a/web-common/src/features/canvas/filters/CanvasSuperPill.svelte b/web-common/src/features/canvas/filters/CanvasSuperPill.svelte new file mode 100644 index 00000000000..6530a993d07 --- /dev/null +++ b/web-common/src/features/canvas/filters/CanvasSuperPill.svelte @@ -0,0 +1,255 @@ +<script lang="ts"> + import { getTimeRangeForCanvas } from "@rilldata/web-common/features/canvas/filters/util"; + import { getCanvasStateManagers } from "@rilldata/web-common/features/canvas/state-managers/state-managers"; + import { getPanRangeForTimeRange } from "@rilldata/web-common/features/dashboards/state-managers/selectors/charts"; + import { + ALL_TIME_RANGE_ALIAS, + CUSTOM_TIME_RANGE_ALIAS, + deriveInterval, + type ISODurationString, + type NamedRange, + type RangeBuckets, + } from "@rilldata/web-common/features/dashboards/time-controls/new-time-controls"; + import * as Elements from "@rilldata/web-common/features/dashboards/time-controls/super-pill/components"; + import { initLocalUserPreferenceStore } from "@rilldata/web-common/features/dashboards/user-preferences"; + import { DEFAULT_TIME_RANGES } from "@rilldata/web-common/lib/time/config"; + import { getDefaultTimeGrain } from "@rilldata/web-common/lib/time/grains"; + import { + TimeComparisonOption, + TimeRangePreset, + type DashboardTimeControls, + type TimeRange, + } from "@rilldata/web-common/lib/time/types"; + import type { V1TimeGrain } from "@rilldata/web-common/runtime-client"; + import { DateTime, Interval } from "luxon"; + + export let allTimeRange: TimeRange; + export let selectedTimeRange: DashboardTimeControls | undefined; + export let activeTimeZone: string; + + const ctx = getCanvasStateManagers(); + const { canvasName, canvasEntity } = ctx; + const { timeControls } = canvasEntity; + + $: localUserPreferences = initLocalUserPreferenceStore($canvasName); + + // $: canvasSpec = $validSpecStore.data; + + $: selectedRange = selectedTimeRange?.name ?? ALL_TIME_RANGE_ALIAS; + + // TODO: Add default timeRange to resource + // $: defaultTimeRange = $validSpecStore?.data?.defaultPreset?.timeRange; + let defaultTimeRange = "PT24H"; + + $: interval = selectedTimeRange + ? Interval.fromDateTimes( + DateTime.fromJSDate(selectedTimeRange.start).setZone(activeTimeZone), + DateTime.fromJSDate(selectedTimeRange.end).setZone(activeTimeZone), + ) + : Interval.fromDateTimes(allTimeRange.start, allTimeRange.end); + + // TODO: Add timezone key to resource + // $: availableTimeZones = canvasSpec?.timeZones ?? []; + let availableTimeZones = [ + "America/Los_Angeles", + "America/New_York", + "Europe/London", + "Asia/Kolkata", + ]; + + $: ({ + latestWindowTimeRanges, + periodToDateRanges, + previousCompleteDateRanges, + showDefaultItem, + } = getTimeRangeForCanvas(activeTimeZone)); + + $: ranges = <RangeBuckets>{ + latest: latestWindowTimeRanges.map((range) => ({ + range: range.name, + label: range.label, + })), + periodToDate: periodToDateRanges.map((range) => ({ + range: range.name, + label: range.label, + })), + previous: previousCompleteDateRanges.map((range) => ({ + range: range.name, + label: range.label, + })), + }; + + $: activeTimeGrain = selectedTimeRange?.interval; + + function onSelectTimeZone(timeZone: string) { + if (!interval.isValid) return; + + if (selectedRange === "CUSTOM") { + selectRange({ + name: TimeRangePreset.CUSTOM, + start: interval.start + ?.setZone(timeZone, { keepLocalTime: true }) + .toJSDate(), + end: interval.end + ?.setZone(timeZone, { keepLocalTime: true }) + .toJSDate(), + }); + } + + timeControls.setTimeZone(timeZone); + localUserPreferences.set({ timeZone }); + } + + function onSelectRange(name: NamedRange | ISODurationString) { + if (!allTimeRange?.end) { + return; + } + + if (name === ALL_TIME_RANGE_ALIAS) { + makeTimeSeriesTimeRangeAndUpdateAppState( + allTimeRange, + "TIME_GRAIN_DAY", + undefined, + ); + return; + } + + const interval = deriveInterval( + name, + DateTime.fromJSDate(allTimeRange.end), + ); + if (!interval?.isValid) return; + + const baseTimeRange: TimeRange = { + name: name as TimeRangePreset, + start: interval.start.toJSDate(), + end: interval.end.toJSDate(), + }; + + selectRange(baseTimeRange); + } + + function selectRange(range: TimeRange) { + const defaultTimeGrain = getDefaultTimeGrain(range.start, range.end).grain; + + const comparisonOption = DEFAULT_TIME_RANGES[range.name as TimeRangePreset] + ?.defaultComparison as TimeComparisonOption; + + // Get valid option for the new time range + const validComparison = allTimeRange && comparisonOption; + + makeTimeSeriesTimeRangeAndUpdateAppState(range, defaultTimeGrain, { + name: validComparison, + } as DashboardTimeControls); + } + + function makeTimeSeriesTimeRangeAndUpdateAppState( + timeRange: TimeRange, + timeGrain: V1TimeGrain, + /** we should only reset the comparison range when the user has explicitly chosen a new + * time range. Otherwise, the current comparison state should continue to be the + * source of truth. + */ + comparisonTimeRange: DashboardTimeControls | undefined, + ) { + timeControls.selectTimeRange(timeRange, timeGrain, comparisonTimeRange); + } + + function onPan(direction: "left" | "right") { + const getPanRange = getPanRangeForTimeRange( + selectedTimeRange, + activeTimeZone, + ); + const panRange = getPanRange(direction); + if (!panRange) return; + const { start, end } = panRange; + + const timeRange = { + name: CUSTOM_TIME_RANGE_ALIAS, + start: start, + end: end, + }; + + const comparisonTimeRange = { + name: TimeComparisonOption.CONTIGUOUS, + } as DashboardTimeControls; // FIXME wrong typecasting across application + + if (!activeTimeGrain) return; + timeControls.selectTimeRange( + timeRange as TimeRange, + activeTimeGrain, + comparisonTimeRange, + ); + } +</script> + +<div class="wrapper"> + <Elements.Nudge canPanLeft canPanRight {onPan} direction="left" /> + <Elements.Nudge canPanLeft canPanRight {onPan} direction="right" /> + {#if interval.isValid && activeTimeGrain} + <Elements.RangePicker + minDate={DateTime.fromJSDate(allTimeRange.start)} + maxDate={DateTime.fromJSDate(allTimeRange.end)} + {ranges} + {showDefaultItem} + {defaultTimeRange} + selected={selectedRange} + grain={activeTimeGrain} + {onSelectRange} + {interval} + zone={activeTimeZone} + applyCustomRange={(interval) => { + selectRange({ + name: TimeRangePreset.CUSTOM, + start: interval.start.toJSDate(), + end: interval.end.toJSDate(), + }); + }} + /> + {/if} + + {#if availableTimeZones.length} + <Elements.Zone + watermark={allTimeRange?.end ?? new Date()} + {activeTimeZone} + {availableTimeZones} + {onSelectTimeZone} + /> + {/if} +</div> + +<style lang="postcss"> + .wrapper { + @apply flex w-fit; + @apply h-[26px] rounded-full; + @apply overflow-hidden; + } + + :global(.wrapper > button) { + @apply border; + } + + :global(.wrapper > button:not(:first-child)) { + @apply -ml-[1px]; + } + + :global(.wrapper > button) { + @apply border; + @apply px-2 flex items-center justify-center bg-white; + } + + :global(.wrapper > button:first-child) { + @apply pl-2.5 rounded-l-full; + } + :global(.wrapper > button:last-child) { + @apply pr-2.5 rounded-r-full; + } + + :global(.wrapper > button:hover:not(:disabled)) { + @apply bg-gray-50 cursor-pointer; + } + + :global(.wrapper > [data-state="open"]) { + @apply bg-gray-50 border-gray-400 z-50; + } +</style> diff --git a/web-common/src/features/canvas/filters/util.ts b/web-common/src/features/canvas/filters/util.ts new file mode 100644 index 00000000000..b012ecbee47 --- /dev/null +++ b/web-common/src/features/canvas/filters/util.ts @@ -0,0 +1,107 @@ +import { + getAvailableComparisonsForTimeRange, + getComparisonRange, +} from "@rilldata/web-common/lib/time/comparisons"; +import { + LATEST_WINDOW_TIME_RANGES, + PERIOD_TO_DATE_RANGES, + PREVIOUS_COMPLETE_DATE_RANGES, +} from "@rilldata/web-common/lib/time/config"; +import { getChildTimeRanges } from "@rilldata/web-common/lib/time/ranges"; +import { + TimeComparisonOption, + TimeRangePreset, + type DashboardTimeControls, +} from "@rilldata/web-common/lib/time/types"; +import { V1TimeGrain } from "@rilldata/web-common/runtime-client"; + +export function getTimeRangeForCanvas( + selectedTimezone: string, + defaultTimeRange?: string, +) { + const allTimeRange = { + name: TimeRangePreset.ALL_TIME, + start: new Date(0), + end: new Date(), + }; + + const latestWindowTimeRanges = LATEST_WINDOW_TIME_RANGES; + const periodToDateRanges = PERIOD_TO_DATE_RANGES; + const previousCompleteDateRanges = PREVIOUS_COMPLETE_DATE_RANGES; + const hasDefaultInRanges = + !!defaultTimeRange && + (defaultTimeRange in LATEST_WINDOW_TIME_RANGES || + defaultTimeRange in PERIOD_TO_DATE_RANGES || + defaultTimeRange in PREVIOUS_COMPLETE_DATE_RANGES); + + return { + latestWindowTimeRanges: getChildTimeRanges( + allTimeRange.start, + allTimeRange.end, + latestWindowTimeRanges, + V1TimeGrain.TIME_GRAIN_UNSPECIFIED, + selectedTimezone, + ), + periodToDateRanges: getChildTimeRanges( + allTimeRange.start, + allTimeRange.end, + periodToDateRanges, + V1TimeGrain.TIME_GRAIN_UNSPECIFIED, + selectedTimezone, + ), + previousCompleteDateRanges: getChildTimeRanges( + allTimeRange.start, + allTimeRange.end, + previousCompleteDateRanges, + V1TimeGrain.TIME_GRAIN_UNSPECIFIED, + selectedTimezone, + ), + showDefaultItem: !!defaultTimeRange && !hasDefaultInRanges, + }; +} + +export function getComparisonOptionsForCanvas( + selectedTimeRange: DashboardTimeControls | undefined, +) { + if (!selectedTimeRange) { + return []; + } + const allTimeRange = { + name: TimeRangePreset.ALL_TIME, + start: new Date(0), + end: new Date(), + }; + + let allOptions = [...Object.values(TimeComparisonOption)]; + + if ( + selectedTimeRange?.name && + selectedTimeRange?.name in PREVIOUS_COMPLETE_DATE_RANGES + ) { + // Previous complete ranges should only have previous period. + // Other options dont make sense with our current wording of the comparison ranges. + allOptions = [TimeComparisonOption.CONTIGUOUS, TimeComparisonOption.CUSTOM]; + } + + const timeComparisonOptions = getAvailableComparisonsForTimeRange( + allTimeRange.start, + allTimeRange.end, + selectedTimeRange.start, + selectedTimeRange.end, + allOptions, + ); + + return timeComparisonOptions.map((co, i) => { + const comparisonTimeRange = getComparisonRange( + selectedTimeRange.start, + selectedTimeRange.end, + co, + ); + return { + name: co, + key: i, + start: comparisonTimeRange.start, + end: comparisonTimeRange.end, + }; + }); +} diff --git a/web-common/src/features/canvas/inspector/ChartTypeSelector.svelte b/web-common/src/features/canvas/inspector/ChartTypeSelector.svelte new file mode 100644 index 00000000000..81ad27ece35 --- /dev/null +++ b/web-common/src/features/canvas/inspector/ChartTypeSelector.svelte @@ -0,0 +1,51 @@ +<script lang="ts"> + import { Button } from "@rilldata/web-common/components/button"; + import InputLabel from "@rilldata/web-common/components/forms/InputLabel.svelte"; + + import Tooltip from "@rilldata/web-common/components/tooltip/Tooltip.svelte"; + import TooltipContent from "@rilldata/web-common/components/tooltip/TooltipContent.svelte"; + import type { ChartMetadata } from "@rilldata/web-common/features/canvas/components/charts/types"; + import { chartMetadata } from "@rilldata/web-common/features/canvas/components/charts/util"; + import { type CanvasComponentType } from "@rilldata/web-common/features/canvas/components/types"; + import { type CanvasComponentObj } from "@rilldata/web-common/features/canvas/components/util"; + + export let componentType: CanvasComponentType; + export let component: CanvasComponentObj; + + async function selectChartType(chartType: ChartMetadata) { + component.updateChartType(chartType.type); + } +</script> + +<div class="section"> + <InputLabel small label="Chart type" id="chart-components" /> + <div class="chart-icons"> + {#each chartMetadata as chart} + <Tooltip distance={8} location="right"> + <Button + square + small + type="secondary" + selected={componentType === chart.type} + on:click={() => selectChartType(chart)} + > + <svelte:component this={chart.icon} size="20px" /> + </Button> + <TooltipContent slot="tooltip-content"> + {chart.title} + </TooltipContent> + </Tooltip> + {/each} + </div> +</div> + +<style lang="postcss"> + .section { + @apply px-5 flex flex-col gap-y-2 pt-2; + @apply border-t border-gray-200; + } + + .chart-icons { + @apply flex border-2 px-2 py-1 gap-x-4; + } +</style> diff --git a/web-common/src/features/canvas/inspector/ComponentsEditor.svelte b/web-common/src/features/canvas/inspector/ComponentsEditor.svelte new file mode 100644 index 00000000000..ccbe0b90059 --- /dev/null +++ b/web-common/src/features/canvas/inspector/ComponentsEditor.svelte @@ -0,0 +1,47 @@ +<script lang="ts"> + import { + getHeaderForComponent, + isCanvasComponentType, + } from "@rilldata/web-common/features/canvas/components/util"; + import ParamMapper from "@rilldata/web-common/features/canvas/inspector/ParamMapper.svelte"; + import type { FileArtifact } from "@rilldata/web-common/features/entity-management/file-artifact"; + import { + ResourceKind, + useResourceV2, + } from "@rilldata/web-common/features/entity-management/resource-selectors"; + import SidebarWrapper from "@rilldata/web-common/features/visual-editing/SidebarWrapper.svelte"; + import { runtime } from "@rilldata/web-common/runtime-client/runtime-store"; + + export let selectedComponentName: string; + export let fileArtifact: FileArtifact; + + // TODO: Avoid resource query if possible + $: resourceQuery = useResourceV2( + $runtime.instanceId, + selectedComponentName, + ResourceKind.Component, + ); + + $: ({ data: componentResource } = $resourceQuery); + + $: ({ renderer, rendererProperties } = + componentResource?.component?.spec ?? {}); +</script> + +<SidebarWrapper + type="secondary" + disableHorizontalPadding + title={getHeaderForComponent(renderer)} +> + {#if isCanvasComponentType(renderer) && rendererProperties} + <ParamMapper + {fileArtifact} + componentType={renderer} + paramValues={rendererProperties} + /> + {:else} + <div> + Unknown Component {renderer} + </div> + {/if} +</SidebarWrapper> diff --git a/web-common/src/features/canvas/inspector/FieldSelectorDropdown.svelte b/web-common/src/features/canvas/inspector/FieldSelectorDropdown.svelte new file mode 100644 index 00000000000..6fa49e11c4c --- /dev/null +++ b/web-common/src/features/canvas/inspector/FieldSelectorDropdown.svelte @@ -0,0 +1,219 @@ +<script lang="ts"> + import { Chip } from "@rilldata/web-common/components/chip"; + import * as DropdownMenu from "@rilldata/web-common/components/dropdown-menu"; + import InputLabel from "@rilldata/web-common/components/forms/InputLabel.svelte"; + import Search from "@rilldata/web-common/components/search/Search.svelte"; + import { + getDimensionDisplayName, + getMeasureDisplayName, + } from "@rilldata/web-common/features/dashboards/filters/getDisplayName"; + import { runtime } from "@rilldata/web-common/runtime-client/runtime-store"; + import { MinusIcon, PlusIcon } from "lucide-svelte"; + import { + useAllDimensionFromMetric, + useAllSimpleMeasureFromMetric, + } from "./selectors"; + + export let metricName: string; + export let label: string | undefined = undefined; + export let id: string; + export let selectedItem: string | undefined = undefined; + export let type: "measure" | "dimension"; + export let searchableItems: string[] | undefined = undefined; + export let onSelect: (item: string) => void = () => {}; + export let onMultiSelect: (items: string[]) => void = () => {}; + export let multi = false; + export let selectedItems: string[] | undefined = undefined; + + $: allDimensions = useAllDimensionFromMetric($runtime.instanceId, metricName); + $: allFilteredMeasures = useAllSimpleMeasureFromMetric( + $runtime.instanceId, + metricName, + ); + + $: items = + type === "measure" + ? ($allFilteredMeasures?.data?.map((m) => m.name as string) ?? []) + : ($allDimensions?.data?.map((d) => d.name || (d.column as string)) ?? + []); + + $: displayMap = + type === "measure" + ? Object.fromEntries( + $allFilteredMeasures?.data?.map((m) => [ + m.name, + getMeasureDisplayName(m), + ]) ?? [], + ) + : Object.fromEntries( + $allDimensions?.data?.map((d) => [ + d.name || d.column, + getDimensionDisplayName(d), + ]) ?? [], + ); + + let open = false; + let searchValue = ""; + + // This Set keeps track of the “in-progress” selection while dropdown is open. + let selectedProxy = new Set(multi ? selectedItems : selectedItem); + + $: filteredItems = ( + searchableItems && searchValue ? searchableItems : items + ).filter((item) => { + const matchesSearch = + displayMap[item]?.toLowerCase().includes(searchValue.toLowerCase()) || + item.toLowerCase().includes(searchValue.toLowerCase()); + // For single-select, remove the already selected item from the list + if (!multi && selectedItem && item === selectedItem) return false; + return matchesSearch; + }); +</script> + +<div class="flex flex-col gap-y-2 pt-1"> + {#if !multi && label} + <div class="flex items-center gap-x-2"> + <InputLabel small {label} {id} /> + </div> + {/if} + + {#if multi} + <DropdownMenu.Root + bind:open + typeahead={false} + closeOnItemClick={true} + onOpenChange={() => { + // Reset our proxy whenever the menu opens (or closes) + if (!open) { + selectedProxy = new Set(selectedItems); + } + }} + > + <DropdownMenu.Trigger asChild let:builder> + <div class="flex justify-between gap-x-2"> + {#if label} + <InputLabel small {label} {id} /> + {/if} + <button use:builder.action {...builder} class="text-sm px-2 h-6"> + <PlusIcon size="14px" /> + </button> + </div> + </DropdownMenu.Trigger> + + <DropdownMenu.Content class="p-0 w-[300px]"> + <div class="p-3 pb-1"> + <Search bind:value={searchValue} autofocus={false} /> + </div> + + <div class="max-h-64 overflow-y-auto"> + {#each filteredItems as item (item)} + <DropdownMenu.CheckboxItem + checked={selectedProxy.has(item)} + class="pl-8 mx-1" + on:click={() => { + if (selectedProxy.has(item)) { + selectedProxy.delete(item); + } else { + selectedProxy.add(item); + } + selectedProxy = selectedProxy; + onMultiSelect(Array.from(selectedProxy)); + }} + > + <slot {item}> + {displayMap[item] || item} + </slot> + </DropdownMenu.CheckboxItem> + {:else} + {#if searchValue} + <div class="ui-copy-disabled text-center p-2 w-full"> + no results + </div> + {/if} + {/each} + </div> + </DropdownMenu.Content> + </DropdownMenu.Root> + {:else} + <DropdownMenu.Root + bind:open + typeahead={false} + closeOnItemClick={false} + onOpenChange={() => { + if (!open) { + selectedProxy = new Set(selectedItem); + } + }} + > + <DropdownMenu.Trigger asChild let:builder> + <Chip fullWidth caret {type} builders={[builder]}> + <span class="font-bold truncate" slot="body"> + {#if selectedItem} + {displayMap[selectedItem] || selectedItem} + {:else} + Select a {type} field + {/if} + </span> + </Chip> + </DropdownMenu.Trigger> + + <DropdownMenu.Content sameWidth class="p-0"> + <div class="p-3 pb-1"> + <Search bind:value={searchValue} autofocus={false} /> + </div> + <div class="max-h-64 overflow-y-auto"> + {#each filteredItems as item (item)} + <DropdownMenu.Item + class="pl-8 mx-1" + on:click={() => { + onSelect(item); + open = false; + }} + > + <slot {item}> + {displayMap[item] || item} + </slot> + </DropdownMenu.Item> + {:else} + {#if searchValue} + <div class="ui-copy-disabled text-center p-2 w-full"> + no results + </div> + {/if} + {/each} + </div> + </DropdownMenu.Content> + </DropdownMenu.Root> + {/if} + + {#if multi && selectedItems && selectedItems.length > 0} + <div class="flex flex-col gap-1"> + {#each selectedItems as item} + <div class="flex items-center justify-between gap-x-2"> + <div class="flex-1"> + <Chip fullWidth {type}> + <span class="font-bold truncate" slot="body"> + {displayMap[item] || item} + </span> + </Chip> + </div> + <button + class=" px-2 py-1 text-xs" + on:click={() => { + selectedProxy.delete(item); + onMultiSelect(Array.from(selectedProxy)); + }} + > + <MinusIcon size="14px" /> + </button> + </div> + {/each} + </div> + {/if} +</div> + +<style lang="postcss"> + .open { + @apply ring-2 ring-primary-100 border-primary-600; + } +</style> diff --git a/web-common/src/features/canvas/inspector/MarkSelector.svelte b/web-common/src/features/canvas/inspector/MarkSelector.svelte new file mode 100644 index 00000000000..b08bd9bd3fa --- /dev/null +++ b/web-common/src/features/canvas/inspector/MarkSelector.svelte @@ -0,0 +1,65 @@ +<script lang="ts"> + import ColorInput from "@rilldata/web-common/components/color-picker/ColorInput.svelte"; + import FieldSwitcher from "@rilldata/web-common/components/forms/FieldSwitcher.svelte"; + import InputLabel from "@rilldata/web-common/components/forms/InputLabel.svelte"; + import type { FieldConfig } from "../components/charts/types"; + import FieldSelectorDropdown from "./FieldSelectorDropdown.svelte"; + + export let key: string; + export let label: string; + export let metricsView: string; + export let value: FieldConfig | string; + export let onChange: (updatedConfig: FieldConfig | string) => void; + + $: selected = !value || typeof value === "string" ? 0 : 1; + + // TODO: Replace with theme primary color + $: color = typeof value === "string" ? value : "rgb(117, 126, 255)"; + + function updateFieldConfig(field: string) { + const updatedConfig: FieldConfig = { + field, + type: "nominal", + }; + onChange(updatedConfig); + } +</script> + +<div class="space-y-2"> + <InputLabel small {label} id={key} /> + + <FieldSwitcher + small + fields={["value", "Split by"]} + {selected} + onClick={(_, field) => { + if (field === "value") { + selected = 0; + onChange(color); + } else if (field === "Split by") { + selected = 1; + } + }} + /> + + {#if selected === 0} + <ColorInput + small + stringColor={color} + label="" + onChange={(color) => { + onChange(color); + }} + /> + {:else if selected === 1} + <FieldSelectorDropdown + metricName={metricsView} + id={`${key}-field`} + type="dimension" + selectedItem={typeof value === "string" ? undefined : value?.field} + onSelect={async (field) => { + updateFieldConfig(field); + }} + /> + {/if} +</div> diff --git a/web-common/src/features/canvas/inspector/MetricSelectorDropdown.svelte b/web-common/src/features/canvas/inspector/MetricSelectorDropdown.svelte new file mode 100644 index 00000000000..405aaa8f71e --- /dev/null +++ b/web-common/src/features/canvas/inspector/MetricSelectorDropdown.svelte @@ -0,0 +1,53 @@ +<script lang="ts"> + import Input from "@rilldata/web-common/components/forms/Input.svelte"; + import { type CanvasComponentObj } from "@rilldata/web-common/features/canvas/components/util"; + import type { ComponentInputParam } from "@rilldata/web-common/features/canvas/inspector/types"; + import { isString } from "@rilldata/web-common/features/canvas/util"; + import { + ResourceKind, + useFilteredResources, + } from "@rilldata/web-common/features/entity-management/resource-selectors"; + import { runtime } from "@rilldata/web-common/runtime-client/runtime-store"; + + export let component: CanvasComponentObj; + export let key: string; + export let inputParam: ComponentInputParam; + + $: ({ instanceId } = $runtime); + + $: spec = component.specStore; + + $: metricsViewsQuery = useFilteredResources( + instanceId, + ResourceKind.MetricsView, + ); + $: metricsViews = $metricsViewsQuery?.data ?? []; + + $: metricsViewNames = metricsViews + .map((view) => view.meta?.name?.name) + .filter(isString); + + $: metricsView = + "metrics_view" in $spec ? $spec.metrics_view : metricsViewNames[0]; +</script> + +<Input + hint="View documentation" + link="https://docs.rilldata.com/reference/project-files/metrics-view" + label={inputParam.label} + capitalizeLabel={false} + bind:value={metricsView} + sameWidth + size="sm" + labelGap={2} + options={metricsViewNames.map((name) => ({ + label: name, + value: name, + }))} + onBlur={() => { + component.updateProperty(key, metricsView); + }} + onChange={() => { + component.updateProperty(key, metricsView); + }} +/> diff --git a/web-common/src/features/canvas/inspector/PageEditor.svelte b/web-common/src/features/canvas/inspector/PageEditor.svelte new file mode 100644 index 00000000000..003cc3f499f --- /dev/null +++ b/web-common/src/features/canvas/inspector/PageEditor.svelte @@ -0,0 +1,119 @@ +<script lang="ts"> + import Input from "@rilldata/web-common/components/forms/Input.svelte"; + import { DASHBOARD_WIDTH } from "@rilldata/web-common/features/canvas/constants"; + import { getParsedDocument } from "@rilldata/web-common/features/canvas/inspector/selectors"; + import { getCanvasStateManagers } from "@rilldata/web-common/features/canvas/state-managers/state-managers"; + import type { FileArtifact } from "@rilldata/web-common/features/entity-management/file-artifact"; + import { + ResourceKind, + useFilteredResources, + } from "@rilldata/web-common/features/entity-management/resource-selectors"; + import SidebarWrapper from "@rilldata/web-common/features/visual-editing/SidebarWrapper.svelte"; + import ThemeInput from "@rilldata/web-common/features/visual-editing/ThemeInput.svelte"; + import { runtime } from "@rilldata/web-common/runtime-client/runtime-store"; + import { YAMLMap } from "yaml"; + + export let updateProperties: ( + newRecord: Record<string, unknown>, + removeProperties?: Array<string | string[]>, + ) => Promise<void>; + export let fileArtifact: FileArtifact; + + const { validSpecStore } = getCanvasStateManagers(); + + $: ({ instanceId } = $runtime); + + $: parsedDocument = getParsedDocument(fileArtifact); + + $: rawTitle = $parsedDocument.get("title"); + $: rawDisplayName = $parsedDocument.get("display_name"); + $: rawTheme = $parsedDocument.get("theme"); + $: maxWidth = DASHBOARD_WIDTH; //Add property + + $: title = stringGuard(rawTitle) || stringGuard(rawDisplayName); + + $: themesQuery = useFilteredResources(instanceId, ResourceKind.Theme); + + $: themeNames = ($themesQuery?.data ?? []) + .map((theme) => theme.meta?.name?.name ?? "") + .filter((string) => !string.endsWith("--theme")); + + $: theme = !rawTheme + ? undefined + : typeof rawTheme === "string" + ? rawTheme + : rawTheme instanceof YAMLMap + ? $validSpecStore?.data?.embeddedTheme + : undefined; + + function stringGuard(value: unknown | undefined): string { + return value && typeof value === "string" ? value : ""; + } +</script> + +<SidebarWrapper type="secondary" disableHorizontalPadding title="Canvas"> + <div class="page-param"> + <Input + hint="Shown in global header and when deployed to Rill Cloud" + capitalizeLabel={false} + size="sm" + labelGap={2} + label="Display name" + bind:value={title} + onBlur={async () => { + await updateProperties({ display_name: title }, ["title"]); + }} + onEnter={async () => { + await updateProperties({ display_name: title }); + }} + /> + </div> + <div class="page-param"> + <Input + hint="Max width for the canvas" + capitalizeLabel={false} + size="sm" + labelGap={2} + label="Max width" + inputType="number" + bind:value={maxWidth} + onBlur={async () => { + await updateProperties({ display_name: title }, ["title"]); + }} + onEnter={async () => { + await updateProperties({ display_name: title }); + }} + /> + </div> + <div class="page-param"> + <ThemeInput + small + {theme} + {themeNames} + onThemeChange={async (value) => { + if (!value) { + await updateProperties({}, ["theme"]); + } else { + await updateProperties({ theme: value }); + } + }} + onColorChange={async (primary, secondary) => { + await updateProperties({ + theme: { + colors: { + primary, + secondary, + }, + }, + }); + }} + /> + </div> +</SidebarWrapper> + +<style lang="postcss"> + .page-param { + @apply py-3 px-5; + @apply border-t border-gray-200; + } +</style> diff --git a/web-common/src/features/canvas/inspector/ParamMapper.svelte b/web-common/src/features/canvas/inspector/ParamMapper.svelte new file mode 100644 index 00000000000..cb437058ae3 --- /dev/null +++ b/web-common/src/features/canvas/inspector/ParamMapper.svelte @@ -0,0 +1,187 @@ +<script lang="ts"> + import Input from "@rilldata/web-common/components/forms/Input.svelte"; + import InputLabel from "@rilldata/web-common/components/forms/InputLabel.svelte"; + import Switch from "@rilldata/web-common/components/forms/Switch.svelte"; + import ChartTypeSelector from "@rilldata/web-common/features/canvas/inspector/ChartTypeSelector.svelte"; + import MetricSelectorDropdown from "@rilldata/web-common/features/canvas/inspector/MetricSelectorDropdown.svelte"; + import FieldSelectorDropdown from "./FieldSelectorDropdown.svelte"; + import PositionalFieldConfig from "./PositionalFieldConfig.svelte"; + + import { + getComponentObj, + isChartComponentType, + } from "@rilldata/web-common/features/canvas/components/util"; + import { getCanvasStateManagers } from "@rilldata/web-common/features/canvas/state-managers/state-managers"; + + import MarkSelector from "@rilldata/web-common/features/canvas/inspector/MarkSelector.svelte"; + import type { FileArtifact } from "@rilldata/web-common/features/entity-management/file-artifact"; + import { type V1ComponentSpecRendererProperties } from "@rilldata/web-common/runtime-client"; + import { onMount } from "svelte"; + import type { CanvasComponentType } from "../components/types"; + + export let componentType: CanvasComponentType; + export let paramValues: V1ComponentSpecRendererProperties; + export let fileArtifact: FileArtifact; + + const { canvasEntity } = getCanvasStateManagers(); + $: selectedComponentIndexStore = canvasEntity?.selectedComponentIndex; + $: selectedComponentIndex = $selectedComponentIndexStore ?? 0; + $: path = ["items", selectedComponentIndex, "component", componentType]; + + $: localParamValues = localParamValues || {}; + let oldParamValuesRef: V1ComponentSpecRendererProperties = {}; + + // TODO: Make this robust possibly a store. + $: if (JSON.stringify(paramValues) !== JSON.stringify(oldParamValuesRef)) { + localParamValues = structuredClone(paramValues) || {}; + oldParamValuesRef = paramValues; + } + + onMount(() => { + localParamValues = structuredClone(paramValues) || {}; + }); + + $: component = getComponentObj( + fileArtifact, + path, + componentType, + paramValues, + ); + $: inputParams = component.inputParams().component; + $: spec = component.specStore; + + $: metricsView = "metrics_view" in $spec ? $spec.metrics_view : null; +</script> + +{#if isChartComponentType(componentType)} + <ChartTypeSelector {component} {componentType} /> +{/if} + +{#key selectedComponentIndex} + <div> + {#each Object.entries(inputParams) as [key, config]} + {#if config.showInUI !== false} + <div class="component-param"> + <!-- TEXT, NUMBER, RILL_TIME --> + {#if config.type === "text" || config.type === "number" || config.type === "rill_time"} + <Input + inputType={config.type === "number" ? "number" : "text"} + capitalizeLabel={false} + textClass="text-sm" + size="sm" + labelGap={2} + optional={!!config.optional} + label={config.label ?? key} + bind:value={localParamValues[key]} + onBlur={async () => { + component.updateProperty(key, localParamValues[key]); + }} + onEnter={async () => { + component.updateProperty(key, localParamValues[key]); + }} + /> + + <!-- METRICS SELECTOR --> + {:else if config.type === "metrics"} + <MetricSelectorDropdown {component} {key} inputParam={config} /> + + <!-- MEASURE / DIMENSION --> + {:else if metricsView && (config.type === "measure" || config.type === "dimension")} + <FieldSelectorDropdown + label={config.label ?? key} + metricName={metricsView} + id={key} + type={config.type} + selectedItem={localParamValues[key]} + onSelect={async (field) => { + component.updateProperty(key, field); + }} + /> + + <!-- MULTIPLE MEASURE / MULTIPLE DIMENSION --> + {:else if metricsView && (config.type === "multi_measures" || config.type === "multi_dimensions")} + <FieldSelectorDropdown + multi + label={config.label ?? key} + metricName={metricsView} + id={key} + type={config.type === "multi_measures" ? "measure" : "dimension"} + selectedItems={localParamValues[key]} + onMultiSelect={async (field) => { + component.updateProperty(key, field); + }} + /> + + <!-- BOOLEAN SWITCH --> + {:else if config.type === "boolean"} + <div class="flex items-center justify-between py-2"> + <InputLabel + small + label={config.label ?? key} + optional={!!config.optional} + id={key} + /> + <Switch + bind:checked={localParamValues[key]} + on:click={async () => { + component.updateProperty(key, !paramValues[key]); + }} + small + /> + </div> + + <!-- TEXT AREA --> + {:else if config.type === "textArea"} + <InputLabel + small + label={config.label ?? key} + optional={!!config.optional} + id={key} + /> + <textarea + class="w-full p-2 border border-gray-300 rounded-sm" + rows="4" + bind:value={localParamValues[key]} + on:blur={async () => { + component.updateProperty(key, localParamValues[key]); + }} + placeholder={config.label ?? key} + /> + + <!-- POSITIONAL CONFIG --> + {:else if metricsView && config.type === "positional"} + <PositionalFieldConfig + {key} + {config} + {metricsView} + value={localParamValues[key] || {}} + onChange={(updatedConfig) => { + localParamValues[key] = updatedConfig; + component.updateProperty(key, updatedConfig); + }} + /> + <!-- COLOR CONFIG --> + {:else if metricsView && config.type === "mark"} + <MarkSelector + label={config.label ?? key} + {key} + {metricsView} + value={localParamValues[key] || {}} + onChange={(updatedConfig) => { + localParamValues[key] = updatedConfig; + component.updateProperty(key, updatedConfig); + }} + /> + {/if} + </div> + {/if} + {/each} + </div> +{/key} + +<style lang="postcss"> + .component-param { + @apply py-3 px-5; + @apply border-t border-gray-200; + } +</style> diff --git a/web-common/src/features/canvas/inspector/PositionalFieldConfig.svelte b/web-common/src/features/canvas/inspector/PositionalFieldConfig.svelte new file mode 100644 index 00000000000..ff18bd71279 --- /dev/null +++ b/web-common/src/features/canvas/inspector/PositionalFieldConfig.svelte @@ -0,0 +1,34 @@ +<script lang="ts"> + import type { FieldConfig } from "../components/charts/types"; + import FieldSelectorDropdown from "./FieldSelectorDropdown.svelte"; + + export let key: string; + export let config: { label?: string }; + export let metricsView: string; + export let value: FieldConfig; + export let onChange: (updatedConfig: FieldConfig) => void; + + $: isDimension = key === "x"; + + function updateFieldConfig(field: string) { + const updatedConfig: FieldConfig = { + ...value, + field, + type: isDimension ? "nominal" : "quantitative", + }; + onChange(updatedConfig); + } +</script> + +<div class="space-y-2"> + <FieldSelectorDropdown + label={config.label || key} + metricName={metricsView} + id={`${key}-field`} + type={isDimension ? "dimension" : "measure"} + selectedItem={value?.field} + onSelect={async (field) => { + updateFieldConfig(field); + }} + /> +</div> diff --git a/web-common/src/features/canvas/inspector/VisualCanvasEditing.svelte b/web-common/src/features/canvas/inspector/VisualCanvasEditing.svelte new file mode 100644 index 00000000000..efa4f864e10 --- /dev/null +++ b/web-common/src/features/canvas/inspector/VisualCanvasEditing.svelte @@ -0,0 +1,72 @@ +<script lang="ts"> + import { replaceState } from "$app/navigation"; + import ComponentsEditor from "@rilldata/web-common/features/canvas/inspector/ComponentsEditor.svelte"; + import PageEditor from "@rilldata/web-common/features/canvas/inspector/PageEditor.svelte"; + import { getCanvasStateManagers } from "@rilldata/web-common/features/canvas/state-managers/state-managers"; + import type { FileArtifact } from "@rilldata/web-common/features/entity-management/file-artifact"; + import { Inspector } from "@rilldata/web-common/layout/workspace"; + import { parseDocument } from "yaml"; + + export let fileArtifact: FileArtifact; + + const { validSpecStore, canvasEntity } = getCanvasStateManagers(); + + $: ({ + editorContent, + remoteContent, + updateEditorContent, + saveLocalContent, + path, + } = fileArtifact); + + $: parsedDocument = parseDocument($editorContent ?? $remoteContent ?? ""); + $: selectedComponentIndex = canvasEntity.selectedComponentIndex; + + $: selectedComponentName = + $selectedComponentIndex !== null + ? $validSpecStore?.data?.items?.[$selectedComponentIndex]?.component + : null; + + async function updateProperties( + newRecord: Record<string, unknown>, + removeProperties?: Array<string | string[]>, + ) { + Object.entries(newRecord).forEach(([property, value]) => { + if (!value) { + parsedDocument.delete(property); + } else { + parsedDocument.set(property, value); + } + }); + + if (removeProperties) { + removeProperties.forEach((prop) => { + try { + if (Array.isArray(prop)) { + parsedDocument.deleteIn(prop); + } else { + parsedDocument.delete(prop); + } + } catch (e) { + console.warn(e); + } + }); + } + + killState(); + updateEditorContent(parsedDocument.toString(), true); + await saveLocalContent(); + } + + function killState() { + replaceState(window.location.origin + window.location.pathname, {}); + } +</script> + +<Inspector minWidth={280} filePath={path}> + {#if selectedComponentName} + <ComponentsEditor {fileArtifact} {selectedComponentName} /> + {:else} + <PageEditor {fileArtifact} {updateProperties} /> + {/if} +</Inspector> diff --git a/web-common/src/features/canvas/inspector/selectors.ts b/web-common/src/features/canvas/inspector/selectors.ts new file mode 100644 index 00000000000..ea0705ed074 --- /dev/null +++ b/web-common/src/features/canvas/inspector/selectors.ts @@ -0,0 +1,37 @@ +import { useMetricsViewValidSpec } from "@rilldata/web-common/features/dashboards/selectors"; +import type { FileArtifact } from "@rilldata/web-common/features/entity-management/file-artifact"; +import { MetricsViewSpecMeasureType } from "@rilldata/web-common/runtime-client"; +import { derived } from "svelte/store"; +import { parseDocument } from "yaml"; + +export const useAllDimensionFromMetric = ( + instanceId: string, + metricsViewName: string, +) => + useMetricsViewValidSpec( + instanceId, + metricsViewName, + (meta) => meta?.dimensions, + ); + +export const useAllSimpleMeasureFromMetric = ( + instanceId: string, + metricsViewName: string, +) => + useMetricsViewValidSpec(instanceId, metricsViewName, (meta) => + meta?.measures?.filter( + (m) => + !m.window && + m.type !== MetricsViewSpecMeasureType.MEASURE_TYPE_TIME_COMPARISON, + ), + ); + +export function getParsedDocument(fileArtifact: FileArtifact) { + const { editorContent, remoteContent } = fileArtifact; + return derived( + [editorContent, remoteContent], + ([$localContent, $remoteContent]) => { + return parseDocument($localContent ?? $remoteContent ?? ""); + }, + ); +} diff --git a/web-common/src/features/canvas/inspector/types.ts b/web-common/src/features/canvas/inspector/types.ts new file mode 100644 index 00000000000..4f206b32efa --- /dev/null +++ b/web-common/src/features/canvas/inspector/types.ts @@ -0,0 +1,40 @@ +type NativeInputTypes = "text" | "number" | "boolean" | "textArea"; +type SemanticInputTypes = + | "metrics" + | "measure" + | "dimension" + | "multi_measures" + | "multi_dimensions"; +type ChartInputTypes = "positional" | "mark" | "tooltip"; +type CustomInputTypes = "rill_time"; + +export type InputType = + | NativeInputTypes + | SemanticInputTypes + | ChartInputTypes + | CustomInputTypes; + +export type FilterInputTypes = + | "time_range" + | "comparison_range" + | "grain" + | "dimension_filters"; + +export interface ComponentInputParam { + type: InputType; + label?: string; + showInUI?: boolean; // If not specified, can assume true + optional?: boolean; + description?: string; // Tooltip description for the input + meta?: Record<string, string>; // Any additional metadata +} + +export interface FilterInputParam { + type: FilterInputTypes; + label: string; +} + +export interface InputParams<T> { + component: Partial<Record<keyof T, ComponentInputParam>>; + filter: Partial<Record<FilterInputTypes, FilterInputParam>> | []; +} diff --git a/web-common/src/features/canvas/selector.ts b/web-common/src/features/canvas/selector.ts new file mode 100644 index 00000000000..834f324cb34 --- /dev/null +++ b/web-common/src/features/canvas/selector.ts @@ -0,0 +1,72 @@ +import type { CreateQueryOptions } from "@rilldata/svelte-query"; +import { + ResourceKind, + useFilteredResources, +} from "@rilldata/web-common/features/entity-management/resource-selectors"; +import { queryClient } from "@rilldata/web-common/lib/svelte-query/globalQueryClient"; +import { + createRuntimeServiceGetResource, + type RpcStatus, + type V1CanvasSpec, + type V1GetResourceResponse, +} from "@rilldata/web-common/runtime-client"; +import type { ErrorType } from "@rilldata/web-common/runtime-client/http-client"; + +export function useDefaultMetrics(instanceId: string) { + return useFilteredResources(instanceId, ResourceKind.MetricsView, (data) => { + const validMetricsViews = data?.resources?.filter( + (res) => !!res.metricsView?.state?.validSpec, + ); + + if (validMetricsViews && validMetricsViews?.length > 0) { + const firstMetricsView = + validMetricsViews[0].metricsView?.state?.validSpec; + const firstMetricName = validMetricsViews[0].meta?.name?.name as string; + const firstMeasure = firstMetricsView?.measures?.[0]?.name as string; + const firstDimension = + firstMetricsView?.dimensions?.[0]?.name || + (firstMetricsView?.dimensions?.[0]?.column as string); + + return { + metricsView: firstMetricName, + measure: firstMeasure, + dimension: firstDimension, + }; + } + + return null; + }); +} + +export function useCanvasValidSpec( + instanceId: string, + canvasName: string, + queryOptions?: CreateQueryOptions< + V1GetResourceResponse, + ErrorType<RpcStatus>, + V1CanvasSpec | undefined + >, +) { + const defaultQueryOptions: CreateQueryOptions< + V1GetResourceResponse, + ErrorType<RpcStatus>, + V1CanvasSpec | undefined + > = { + select: (data) => data?.resource?.canvas?.state?.validSpec, + queryClient, + enabled: !!canvasName, + }; + return createRuntimeServiceGetResource( + instanceId, + { + "name.kind": ResourceKind.Canvas, + "name.name": canvasName, + }, + { + query: { + ...defaultQueryOptions, + ...queryOptions, + }, + }, + ); +} diff --git a/web-common/src/features/canvas/state-managers/StateManagersProvider.svelte b/web-common/src/features/canvas/state-managers/StateManagersProvider.svelte new file mode 100644 index 00000000000..df368c764c2 --- /dev/null +++ b/web-common/src/features/canvas/state-managers/StateManagersProvider.svelte @@ -0,0 +1,27 @@ +<script lang="ts"> + import { createCanvasStateSync } from "@rilldata/web-common/features/canvas/stores/syncCanvasState"; + import DelayedSpinner from "@rilldata/web-common/features/entity-management/DelayedSpinner.svelte"; + import { useQueryClient } from "@tanstack/svelte-query"; + import { setContext } from "svelte"; + import { createStateManagers, DEFAULT_STORE_KEY } from "./state-managers"; + + export let canvasName: string; + + const queryClient = useQueryClient(); + const stateManagers = createStateManagers({ + queryClient, + canvasName, + }); + + const canvasStoreReady = createCanvasStateSync(canvasName); + + setContext(DEFAULT_STORE_KEY, stateManagers); +</script> + +{#if canvasStoreReady.isFetching} + <div class="grid place-items-center size-full"> + <DelayedSpinner isLoading={canvasStoreReady.isFetching} size="40px" /> + </div> +{:else} + <slot /> +{/if} diff --git a/web-common/src/features/canvas/state-managers/state-managers.ts b/web-common/src/features/canvas/state-managers/state-managers.ts new file mode 100644 index 00000000000..5c0421c0798 --- /dev/null +++ b/web-common/src/features/canvas/state-managers/state-managers.ts @@ -0,0 +1,56 @@ +import { useCanvasValidSpec } from "@rilldata/web-common/features/canvas/selector"; +import { + type RpcStatus, + type V1CanvasSpec, +} from "@rilldata/web-common/runtime-client"; +import type { Runtime } from "@rilldata/web-common/runtime-client/runtime-store"; +import { runtime } from "@rilldata/web-common/runtime-client/runtime-store"; +import type { QueryClient, QueryObserverResult } from "@tanstack/svelte-query"; +import { getContext } from "svelte"; +import { derived, writable, type Readable, type Writable } from "svelte/store"; +import { useCanvasEntity } from "../stores/canvas-entities"; +import type { CanvasEntity } from "../stores/canvas-entity"; + +export type StateManagers = { + runtime: Writable<Runtime>; + canvasName: Writable<string>; + canvasEntity: CanvasEntity; + validSpecStore: Readable< + QueryObserverResult<V1CanvasSpec | undefined, RpcStatus> + >; + queryClient: QueryClient; +}; + +export const DEFAULT_STORE_KEY = Symbol("canvas-state-managers"); + +export function getCanvasStateManagers(): StateManagers { + return getContext(DEFAULT_STORE_KEY); +} + +export function createStateManagers({ + queryClient, + canvasName, +}: { + queryClient: QueryClient; + canvasName: string; +}): StateManagers { + const canvasNameStore = writable(canvasName); + + const canvasEntity = useCanvasEntity(canvasName); + + const validSpecStore: Readable< + QueryObserverResult<V1CanvasSpec | undefined, RpcStatus> + > = derived([runtime, canvasNameStore], ([r, canvasName], set) => + useCanvasValidSpec(r.instanceId, canvasName, { queryClient }).subscribe( + set, + ), + ); + + return { + runtime: runtime, + canvasName: canvasNameStore, + canvasEntity, + validSpecStore, + queryClient, + }; +} diff --git a/web-common/src/features/canvas/stores/canvas-entities.ts b/web-common/src/features/canvas/stores/canvas-entities.ts new file mode 100644 index 00000000000..324c32556e9 --- /dev/null +++ b/web-common/src/features/canvas/stores/canvas-entities.ts @@ -0,0 +1,36 @@ +import { CanvasEntity } from "./canvas-entity"; + +export class CanvasEntities { + private entities: Map<string, CanvasEntity> = new Map(); + + addCanvas(name: string) { + if (!this.entities.has(name)) { + this.entities.set(name, new CanvasEntity(name)); + } + } + + removeCanvas(name: string) { + this.entities.delete(name); + } + + hasCanvas(name: string) { + return this.entities.has(name); + } + + getCanvas(name: string) { + let canvasEntity = this.entities.get(name); + + if (!canvasEntity) { + canvasEntity = new CanvasEntity(name); + this.entities.set(name, canvasEntity); + } + + return canvasEntity; + } +} + +export const canvasEntities = new CanvasEntities(); + +export function useCanvasEntity(name: string) { + return canvasEntities.getCanvas(name); +} diff --git a/web-common/src/features/canvas/stores/canvas-entity.ts b/web-common/src/features/canvas/stores/canvas-entity.ts new file mode 100644 index 00000000000..063eeb4e390 --- /dev/null +++ b/web-common/src/features/canvas/stores/canvas-entity.ts @@ -0,0 +1,25 @@ +import { writable, type Writable } from "svelte/store"; +import { CanvasTimeControls } from "./canvas-time-control"; + +export class CanvasEntity { + name: string; + /** + * Time controls for the canvas entity containing various + * time related writables + */ + timeControls: CanvasTimeControls; + /** + * Index of the component higlighted or selected in the canvas + */ + selectedComponentIndex: Writable<number | null>; + + constructor(name: string) { + this.name = name; + this.timeControls = new CanvasTimeControls(); + this.selectedComponentIndex = writable(null); + } + + setSelectedComponentIndex(index: number | null) { + this.selectedComponentIndex.set(index); + } +} diff --git a/web-common/src/features/canvas/stores/canvas-time-control.ts b/web-common/src/features/canvas/stores/canvas-time-control.ts new file mode 100644 index 00000000000..8b601a018c4 --- /dev/null +++ b/web-common/src/features/canvas/stores/canvas-time-control.ts @@ -0,0 +1,57 @@ +import { + TimeRangePreset, + type DashboardTimeControls, + type TimeRange, +} from "@rilldata/web-common/lib/time/types"; +import { V1TimeGrain } from "@rilldata/web-common/runtime-client"; +import { writable, type Writable } from "svelte/store"; + +export class CanvasTimeControls { + selectedTimeRange: Writable<DashboardTimeControls>; + selectedComparisonTimeRange: Writable<DashboardTimeControls | undefined>; + showTimeComparison: Writable<boolean>; + selectedTimezone: Writable<string>; + + constructor() { + this.selectedTimeRange = writable({ + name: TimeRangePreset.ALL_TIME, + start: new Date(0), + end: new Date(), + interval: V1TimeGrain.TIME_GRAIN_DAY, + }); + this.selectedComparisonTimeRange = writable(undefined); + this.showTimeComparison = writable(false); + this.selectedTimezone = writable("UTC"); + } + + setTimeZone(timezone: string) { + this.selectedTimezone.set(timezone); + } + + selectTimeRange( + timeRange: TimeRange, + timeGrain: V1TimeGrain, + comparisonTimeRange: DashboardTimeControls | undefined, + ) { + if (!timeRange.name) return; + + if (timeRange.name === TimeRangePreset.ALL_TIME) { + this.showTimeComparison.set(false); + } + + this.selectedTimeRange.set({ + ...timeRange, + interval: timeGrain, + }); + + this.selectedComparisonTimeRange.set(comparisonTimeRange); + } + + setSelectedComparisonRange(comparisonTimeRange: DashboardTimeControls) { + this.selectedComparisonTimeRange.set(comparisonTimeRange); + } + + displayTimeComparison(showTimeComparison: boolean) { + this.showTimeComparison.set(showTimeComparison); + } +} diff --git a/web-common/src/features/canvas/stores/syncCanvasState.ts b/web-common/src/features/canvas/stores/syncCanvasState.ts new file mode 100644 index 00000000000..28e47e17b5f --- /dev/null +++ b/web-common/src/features/canvas/stores/syncCanvasState.ts @@ -0,0 +1,12 @@ +import { canvasEntities } from "@rilldata/web-common/features/canvas/stores/canvas-entities"; + +export function createCanvasStateSync(canvasName: string) { + if (canvasEntities.hasCanvas(canvasName)) { + // TODO: Add sync method if required + return { isFetching: false, error: false }; + } else { + // Running for the 1st time. Initialise the canvas store. + canvasEntities.addCanvas(canvasName); + return { isFetching: false, error: false }; + } +} diff --git a/web-common/src/features/canvas/util.ts b/web-common/src/features/canvas/util.ts index 2c67ad44fed..eefc9205fb0 100644 --- a/web-common/src/features/canvas/util.ts +++ b/web-common/src/features/canvas/util.ts @@ -17,3 +17,7 @@ export const vector = { return [vector[0] / divisor[0], vector[1] / divisor[1]]; }, }; + +export function isString(value: unknown): value is string { + return typeof value === "string"; +} diff --git a/web-common/src/features/dashboards/filters/FilterButton.svelte b/web-common/src/features/dashboards/filters/FilterButton.svelte index b10cb959b6a..f72c0fe7088 100644 --- a/web-common/src/features/dashboards/filters/FilterButton.svelte +++ b/web-common/src/features/dashboards/filters/FilterButton.svelte @@ -1,13 +1,13 @@ <script lang="ts"> + import * as DropdownMenu from "@rilldata/web-common/components/dropdown-menu"; import Add from "@rilldata/web-common/components/icons/Add.svelte"; import type { SearchableFilterSelectableGroup } from "@rilldata/web-common/components/searchable-filter-menu/SearchableFilterSelectableItem"; + import SearchableMenuContent from "@rilldata/web-common/components/searchable-filter-menu/SearchableMenuContent.svelte"; import Tooltip from "@rilldata/web-common/components/tooltip/Tooltip.svelte"; import TooltipContent from "@rilldata/web-common/components/tooltip/TooltipContent.svelte"; import { getDimensionDisplayName } from "@rilldata/web-common/features/dashboards/filters/getDisplayName"; import { getStateManagers } from "../state-managers/state-managers"; import { getMeasureDisplayName } from "./getDisplayName"; - import SearchableMenuContent from "@rilldata/web-common/components/searchable-filter-menu/SearchableMenuContent.svelte"; - import * as DropdownMenu from "@rilldata/web-common/components/dropdown-menu"; const { selectors: { dimensions: { allDimensions }, diff --git a/web-common/src/features/dashboards/selectors.ts b/web-common/src/features/dashboards/selectors.ts index 3444b1f69d8..0e9b3c62487 100644 --- a/web-common/src/features/dashboards/selectors.ts +++ b/web-common/src/features/dashboards/selectors.ts @@ -132,15 +132,6 @@ export function useMetricsViewTimeRange( ); } -export const useMetricsViewSpecMeasure = ( - instanceId: string, - metricsViewName: string, - measureName: string, -) => - useMetricsViewValidSpec(instanceId, metricsViewName, (meta) => - meta?.measures?.find((measure) => measure.name === measureName), - ); - export function getFiltersForOtherDimensions( whereFilter: V1Expression, dimName: string, diff --git a/web-common/src/features/dashboards/state-managers/selectors/charts.ts b/web-common/src/features/dashboards/state-managers/selectors/charts.ts index 7ea7910a05b..b93e15ad1de 100644 --- a/web-common/src/features/dashboards/state-managers/selectors/charts.ts +++ b/web-common/src/features/dashboards/state-managers/selectors/charts.ts @@ -4,7 +4,10 @@ import { getOffset, getTimeWidth, } from "@rilldata/web-common/lib/time/transforms"; -import { TimeOffsetType } from "@rilldata/web-common/lib/time/types"; +import { + TimeOffsetType, + type DashboardTimeControls, +} from "@rilldata/web-common/lib/time/types"; import type { DashboardDataSources } from "./types"; export const chartSelectors = { @@ -27,26 +30,30 @@ export const chartSelectors = { }, getNewPanRange: (dashData: DashboardDataSources) => { const timeControls = timeControlsState(dashData); + const timeZone = dashData.dashboard?.selectedTimezone; + return getPanRangeForTimeRange(timeControls.selectedTimeRange, timeZone); + }, +}; - return (direction: "left" | "right") => { - const selectedTimeRange = timeControls?.selectedTimeRange; - if (!selectedTimeRange) return; - - const timeZone = dashData?.dashboard?.selectedTimezone || "UTC"; - const { start, end } = selectedTimeRange; +export function getPanRangeForTimeRange( + timeRange: DashboardTimeControls | undefined, + timeZone: string, +) { + return (direction: "left" | "right") => { + if (!timeRange) return; + const { start, end } = timeRange; - if (!start || !end) return; + if (!start || !end) return; - const offsetType = - direction === "left" ? TimeOffsetType.SUBTRACT : TimeOffsetType.ADD; + const offsetType = + direction === "left" ? TimeOffsetType.SUBTRACT : TimeOffsetType.ADD; - const currentRangeWidth = getTimeWidth(start, end); - const panAmount = getDurationFromMS(currentRangeWidth); + const currentRangeWidth = getTimeWidth(start, end); + const panAmount = getDurationFromMS(currentRangeWidth); - const newStart = getOffset(start, panAmount, offsetType, timeZone); - const newEnd = getOffset(end, panAmount, offsetType, timeZone); + const newStart = getOffset(start, panAmount, offsetType, timeZone); + const newEnd = getOffset(end, panAmount, offsetType, timeZone); - return { start: newStart, end: newEnd }; - }; - }, -}; + return { start: newStart, end: newEnd }; + }; +} diff --git a/web-common/src/features/dashboards/tab-bar/TabBar.svelte b/web-common/src/features/dashboards/tab-bar/TabBar.svelte index 97dd959a045..cdaa6d575d8 100644 --- a/web-common/src/features/dashboards/tab-bar/TabBar.svelte +++ b/web-common/src/features/dashboards/tab-bar/TabBar.svelte @@ -9,8 +9,8 @@ MetricsEventScreenName, MetricsEventSpace, } from "@rilldata/web-common/metrics/service/MetricsTypes"; - import Tab from "./Tab.svelte"; import type { ComponentType } from "svelte"; + import Tab from "./Tab.svelte"; type TabName = MetricsEventScreenName.Pivot | MetricsEventScreenName.Explore; type TabData = { label: string; Icon: ComponentType; beta?: true }; diff --git a/web-common/src/features/dashboards/time-dimension-details/charts/TDDAlternateChart.svelte b/web-common/src/features/dashboards/time-dimension-details/charts/TDDAlternateChart.svelte index 151873bfeb7..f5e8aa13dbb 100644 --- a/web-common/src/features/dashboards/time-dimension-details/charts/TDDAlternateChart.svelte +++ b/web-common/src/features/dashboards/time-dimension-details/charts/TDDAlternateChart.svelte @@ -1,11 +1,11 @@ <script lang="ts"> - import VegaLiteRenderer from "@rilldata/web-common/features/canvas-components/render/VegaLiteRenderer.svelte"; - import VegaRenderer from "@rilldata/web-common/features/canvas-components/render/VegaRenderer.svelte"; import { resolveSignalField, resolveSignalIntervalField, resolveSignalTimeField, - } from "@rilldata/web-common/features/canvas-components/render/vega-signals"; + } from "@rilldata/web-common/components/vega/vega-signals"; + import VegaLiteRenderer from "@rilldata/web-common/components/vega/VegaLiteRenderer.svelte"; + import VegaRenderer from "@rilldata/web-common/components/vega/VegaRenderer.svelte"; import { getStateManagers } from "@rilldata/web-common/features/dashboards/state-managers/state-managers"; import { tableInteractionStore } from "@rilldata/web-common/features/dashboards/time-dimension-details/time-dimension-data-store"; import type { DimensionDataItem } from "@rilldata/web-common/features/dashboards/time-series/multiple-dimension-queries"; diff --git a/web-common/src/features/dashboards/time-dimension-details/charts/utils.ts b/web-common/src/features/dashboards/time-dimension-details/charts/utils.ts index 9e77f4bf7b1..0d2f37e08c4 100644 --- a/web-common/src/features/dashboards/time-dimension-details/charts/utils.ts +++ b/web-common/src/features/dashboards/time-dimension-details/charts/utils.ts @@ -1,4 +1,4 @@ -import { TDDChartMap } from "@rilldata/web-common/features/canvas-components/types"; +import { TDDChartMap } from "@rilldata/web-common/components/vega/types"; import type { DimensionDataItem } from "@rilldata/web-common/features/dashboards/time-series/multiple-dimension-queries"; import { type ChartField, diff --git a/web-common/src/features/entity-management/AddAssetButton.svelte b/web-common/src/features/entity-management/AddAssetButton.svelte index c7ecaa53dd0..36d1ba74c71 100644 --- a/web-common/src/features/entity-management/AddAssetButton.svelte +++ b/web-common/src/features/entity-management/AddAssetButton.svelte @@ -19,7 +19,6 @@ } from "../../runtime-client"; import { runtime } from "../../runtime-client/runtime-store"; import { useIsModelingSupportedForDefaultOlapDriver } from "../connectors/olap/selectors"; - import { featureFlags } from "../feature-flags"; import { directoryState } from "../file-explorer/directory-store"; import { createResourceFile } from "../file-explorer/new-files"; import { addSourceModal } from "../sources/modal/add-source-visibility"; @@ -41,7 +40,6 @@ const createFile = createRuntimeServicePutFile(); const createFolder = createRuntimeServiceCreateDirectory(); - const { customDashboards } = featureFlags; $: ({ instanceId } = $runtime); $: currentFile = $page.params.file; @@ -229,6 +227,20 @@ /> Explore dashboard </DropdownMenu.Item> + <DropdownMenu.Item + class="flex gap-x-2" + on:click={async () => { + const newFilePath = await createResourceFile(ResourceKind.Canvas); + await wrapNavigation(newFilePath); + }} + > + <svelte:component + this={resourceIconMapping[ResourceKind.Canvas]} + color={resourceColorMapping[ResourceKind.Canvas]} + size="16px" + /> + Canvas dashboard + </DropdownMenu.Item> {/if} <DropdownMenu.Separator /> <DropdownMenu.Sub> @@ -253,32 +265,7 @@ API <DropdownMenu.Separator /> </DropdownMenu.Item> - {#if $customDashboards} - <DropdownMenu.Separator /> - <DropdownMenu.Item - class="flex gap-x-2" - on:click={() => handleAddResource(ResourceKind.Component)} - > - <svelte:component - this={resourceIconMapping[ResourceKind.Component]} - color={resourceColorMapping[ResourceKind.Component]} - size="16px" - /> - Component - </DropdownMenu.Item> - <DropdownMenu.Item - class="flex gap-x-2" - on:click={() => handleAddResource(ResourceKind.Canvas)} - > - <svelte:component - this={resourceIconMapping[ResourceKind.Canvas]} - color={resourceColorMapping[ResourceKind.Canvas]} - size="16px" - /> - Canvas dashboard - </DropdownMenu.Item> - <DropdownMenu.Separator /> - {/if} + <DropdownMenu.Separator /> <DropdownMenu.Item class="flex gap-x-2" on:click={() => handleAddResource(ResourceKind.Theme)} diff --git a/web-common/src/features/entity-management/CreateExploreDialog.svelte b/web-common/src/features/entity-management/CreateExploreDialog.svelte index 2d8bd9a120c..b59d5e48ace 100644 --- a/web-common/src/features/entity-management/CreateExploreDialog.svelte +++ b/web-common/src/features/entity-management/CreateExploreDialog.svelte @@ -1,10 +1,10 @@ <script lang="ts"> import * as AlertDialog from "@rilldata/web-common/components/alert-dialog"; - import Select from "@rilldata/web-common/components/forms/Select.svelte"; - import { ResourceKind } from "./resource-selectors"; import Button from "@rilldata/web-common/components/button/Button.svelte"; - import { createResourceFile } from "../file-explorer/new-files"; + import Select from "@rilldata/web-common/components/forms/Select.svelte"; import type { V1Resource } from "@rilldata/web-common/runtime-client"; + import { createResourceFile } from "../file-explorer/new-files"; + import { ResourceKind } from "./resource-selectors"; export let open = false; export let metricsViews: V1Resource[]; diff --git a/web-common/src/features/explores/PreviewButton.svelte b/web-common/src/features/explores/PreviewButton.svelte index 947e25059c5..bf223ccb7dc 100644 --- a/web-common/src/features/explores/PreviewButton.svelte +++ b/web-common/src/features/explores/PreviewButton.svelte @@ -1,6 +1,6 @@ <script lang="ts"> - import { Button } from "@rilldata/web-common/components/button"; import { navigating } from "$app/stores"; + import { Button } from "@rilldata/web-common/components/button"; import Tooltip from "@rilldata/web-common/components/tooltip/Tooltip.svelte"; import TooltipContent from "@rilldata/web-common/components/tooltip/TooltipContent.svelte"; import { clearExploreSessionStore } from "@rilldata/web-common/features/dashboards/url-state/explore-web-view-store"; diff --git a/web-common/src/features/file-explorer/FileExplorer.svelte b/web-common/src/features/file-explorer/FileExplorer.svelte index 944a749ecd1..44083dbb93d 100644 --- a/web-common/src/features/file-explorer/FileExplorer.svelte +++ b/web-common/src/features/file-explorer/FileExplorer.svelte @@ -1,7 +1,6 @@ <script lang="ts"> import { goto } from "$app/navigation"; import { page } from "$app/stores"; - import GenerateChartYAMLPrompt from "@rilldata/web-common/features/canvas-components/prompt/GenerateChartYAMLPrompt.svelte"; import RenameAssetModal from "@rilldata/web-common/features/entity-management/RenameAssetModal.svelte"; import { deleteFileArtifact, @@ -113,26 +112,6 @@ } } - let showGenerateChartModal = false; - let generateChartTable: string; - let generateChartConnector: string; - let generateChartMetricsView: string; - - function onGenerateChart({ - table, - connector, - metricsView, - }: { - table?: string; - connector?: string; - metricsView?: string; - }) { - showGenerateChartModal = true; - generateChartTable = table ?? ""; - generateChartConnector = connector ?? ""; - generateChartMetricsView = metricsView ?? ""; - } - const { dragData, position } = navEntryDragDropStore; async function handleDropSuccess(fromPath: string, toDir: string) { @@ -188,7 +167,6 @@ {onRename} {onDuplicate} {onDelete} - {onGenerateChart} onMouseDown={(e, dragData) => navEntryDragDropStore.onMouseDown(e, dragData)} /> @@ -203,13 +181,6 @@ /> {/if} -<GenerateChartYAMLPrompt - bind:open={showGenerateChartModal} - connector={generateChartConnector} - metricsView={generateChartMetricsView} - table={generateChartTable} -/> - {#if $dragData} <NavEntryPortal position={$position} dragData={$dragData} /> {/if} diff --git a/web-common/src/features/file-explorer/NavDirectory.svelte b/web-common/src/features/file-explorer/NavDirectory.svelte index 53d9192a5de..f9bf6aac339 100644 --- a/web-common/src/features/file-explorer/NavDirectory.svelte +++ b/web-common/src/features/file-explorer/NavDirectory.svelte @@ -12,11 +12,6 @@ export let onRename: (filePath: string, isDir: boolean) => void; export let onDuplicate: (filePath: string, isDir: boolean) => void; export let onDelete: (filePath: string, isDir: boolean) => void; - export let onGenerateChart: (data: { - table?: string; - connector?: string; - metricsView?: string; - }) => void; export let onMouseDown: (e: MouseEvent, dragData: NavDragData) => void; $: expanded = $directoryState[directory.path]; @@ -48,7 +43,6 @@ {onRename} {onDuplicate} {onDelete} - {onGenerateChart} {onMouseDown} /> {/each} @@ -57,14 +51,7 @@ {#each directory.files as file (file)} {@const filePath = directory.path === "/" ? `/${file}` : `${directory.path}/${file}`} - <NavFile - {filePath} - {onRename} - {onDuplicate} - {onDelete} - {onGenerateChart} - {onMouseDown} - /> + <NavFile {filePath} {onRename} {onDuplicate} {onDelete} {onMouseDown} /> {/each} {/if} </ul> diff --git a/web-common/src/features/file-explorer/NavFile.svelte b/web-common/src/features/file-explorer/NavFile.svelte index 30ef5409373..c5d3e37dc80 100644 --- a/web-common/src/features/file-explorer/NavFile.svelte +++ b/web-common/src/features/file-explorer/NavFile.svelte @@ -43,11 +43,6 @@ export let onRename: (filePath: string, isDir: boolean) => void; export let onDuplicate: (filePath: string, isDir: boolean) => void; export let onDelete: (filePath: string, isDir: boolean) => void; - export let onGenerateChart: (data: { - table?: string; - connector?: string; - metricsView?: string; - }) => void; export let onMouseDown: (e: MouseEvent, dragData: NavDragData) => void; let contextMenuOpen = false; @@ -159,22 +154,13 @@ > {#if resourceKind} {#if resourceKind === ResourceKind.Source} - <SourceMenuItems - {filePath} - on:generate-chart={({ detail }) => onGenerateChart(detail)} - /> + <SourceMenuItems {filePath} /> <NavigationMenuSeparator /> {:else if resourceKind === ResourceKind.Model} - <ModelMenuItems - {filePath} - on:generate-chart={({ detail }) => onGenerateChart(detail)} - /> + <ModelMenuItems {filePath} /> <NavigationMenuSeparator /> {:else if resourceKind === ResourceKind.MetricsView} - <MetricsViewMenuItems - {filePath} - on:generate-chart={({ detail }) => onGenerateChart(detail)} - /> + <MetricsViewMenuItems {filePath} /> <NavigationMenuSeparator /> {/if} {/if} diff --git a/web-common/src/features/file-explorer/new-files.ts b/web-common/src/features/file-explorer/new-files.ts index 5b025356a88..2fe5a79f9d3 100644 --- a/web-common/src/features/file-explorer/new-files.ts +++ b/web-common/src/features/file-explorer/new-files.ts @@ -247,16 +247,10 @@ vega_lite: | case ResourceKind.Canvas: return `type: canvas title: "Canvas Dashboard" -columns: 24 -gap: 2 - items: - component: markdown: content: "First Component" - css: - font-size: "40px" - background-color: "#fff" width: 4 height: 3 x: 2 diff --git a/web-common/src/features/metrics-views/editor/MetricsEditor.svelte b/web-common/src/features/metrics-views/editor/MetricsEditor.svelte index f36dbf811f8..7257b5a62a2 100644 --- a/web-common/src/features/metrics-views/editor/MetricsEditor.svelte +++ b/web-common/src/features/metrics-views/editor/MetricsEditor.svelte @@ -9,11 +9,11 @@ import { FileArtifact } from "@rilldata/web-common/features/entity-management/file-artifact"; import { fileArtifacts } from "@rilldata/web-common/features/entity-management/file-artifacts"; import { ResourceKind } from "@rilldata/web-common/features/entity-management/resource-selectors"; + import WorkspaceEditorContainer from "@rilldata/web-common/layout/workspace/WorkspaceEditorContainer.svelte"; import { yamlSchema } from "codemirror-json-schema/yaml"; import type { JSONSchema7 } from "json-schema"; import { createPlaceholder } from "./create-placeholder"; import metricsSchema from "./metrics-schema.json"; - import WorkspaceEditorContainer from "@rilldata/web-common/layout/workspace/WorkspaceEditorContainer.svelte"; export let filePath: string; export let metricsViewName: string; diff --git a/web-common/src/features/templates/TemplateRenderer.svelte b/web-common/src/features/templates/TemplateRenderer.svelte deleted file mode 100644 index 7ae61d055c5..00000000000 --- a/web-common/src/features/templates/TemplateRenderer.svelte +++ /dev/null @@ -1,59 +0,0 @@ -<script lang="ts"> - import Chart from "@rilldata/web-common/features/canvas/Chart.svelte"; - import { useVariableInputParams } from "@rilldata/web-common/features/canvas/variables-store"; - import Image from "@rilldata/web-common/features/templates/image/Image.svelte"; - import KPITemplate from "@rilldata/web-common/features/templates/kpi/KPITemplate.svelte"; - import Markdown from "@rilldata/web-common/features/templates/markdown/Markdown.svelte"; - import Select from "@rilldata/web-common/features/templates/select/Select.svelte"; - import Switch from "@rilldata/web-common/features/templates/switch/Switch.svelte"; - import TableTemplate from "@rilldata/web-common/features/templates/table/TableTemplate.svelte"; - - import { - createQueryServiceResolveComponent, - type V1ComponentSpecRendererProperties, - type V1ComponentSpecResolverProperties, - type V1ComponentVariable, - } from "@rilldata/web-common/runtime-client"; - import { runtime } from "@rilldata/web-common/runtime-client/runtime-store"; - import { getContext } from "svelte"; - - export let chartView: boolean; - export let renderer: string; - export let componentName: string; - export let input: V1ComponentVariable[] | undefined; - export let output: V1ComponentVariable | undefined; - export let resolverProperties: V1ComponentSpecResolverProperties | undefined; - - const canvasName = getContext("rill::canvas:name") as string; - - $: ({ instanceId } = $runtime); - - $: inputVariableParams = useVariableInputParams(canvasName, input); - $: componentQuery = createQueryServiceResolveComponent( - instanceId, - componentName, - { args: $inputVariableParams }, - ); - $: componentData = $componentQuery?.data; - $: rendererProperties = - componentData?.rendererProperties as V1ComponentSpecRendererProperties; - $: data = componentData?.data; -</script> - -{#if rendererProperties} - {#if renderer === "kpi"} - <KPITemplate {rendererProperties} /> - {:else if renderer === "table"} - <TableTemplate {rendererProperties} /> - {:else if renderer === "markdown"} - <Markdown {rendererProperties} /> - {:else if renderer === "image"} - <Image {rendererProperties} /> - {:else if renderer === "select"} - <Select {data} {componentName} {output} {rendererProperties} /> - {:else if renderer === "switch"} - <Switch {output} {rendererProperties} /> - {:else if resolverProperties} - <Chart {componentName} {chartView} {input} /> - {/if} -{/if} diff --git a/web-common/src/features/templates/charts/build-template.ts b/web-common/src/features/templates/charts/build-template.ts index 3124f8832f9..e9f6e8b71d1 100644 --- a/web-common/src/features/templates/charts/build-template.ts +++ b/web-common/src/features/templates/charts/build-template.ts @@ -1,4 +1,4 @@ -import { ChartType } from "@rilldata/web-common/features/canvas-components/types"; +import { ChartType } from "@rilldata/web-common/components/vega/types"; import type { VisualizationSpec } from "svelte-vega"; import { buildArea } from "./area"; import { buildGroupedBar } from "./grouped-bar"; diff --git a/web-common/src/features/templates/charts/utils.ts b/web-common/src/features/templates/charts/utils.ts index 49181b5d114..58a7c80886b 100644 --- a/web-common/src/features/templates/charts/utils.ts +++ b/web-common/src/features/templates/charts/utils.ts @@ -1,7 +1,5 @@ -import { ChartType } from "@rilldata/web-common/features/canvas-components/types"; -import type { ChartProperties } from "@rilldata/web-common/features/templates/types"; +import { ChartType } from "@rilldata/web-common/components/vega/types"; import type { VisualizationSpec } from "svelte-vega"; -import { buildVegaLiteSpec } from "./build-template"; export function singleLayerBaseSpec() { const baseSpec: VisualizationSpec = { @@ -45,21 +43,3 @@ export const templateNameToChartEnumMap = { area_chart: ChartType.AREA, stacked_area_chart: ChartType.STACKED_AREA, }; - -export function getSpecFromTemplateProperties( - renderer: string, - properties: ChartProperties, -) { - if (!properties.x || !properties.y) { - return undefined; - } - const chartType = templateNameToChartEnumMap[renderer]; - - if (!chartType) return undefined; - - const timeFields = [{ name: properties.x, label: properties.x }]; - const quantitativeFields = [{ name: properties.y, label: properties.y }]; - - const spec = buildVegaLiteSpec(chartType, timeFields, quantitativeFields, []); - return spec; -} diff --git a/web-common/src/features/templates/kpi/KPITemplate.svelte b/web-common/src/features/templates/kpi/KPITemplate.svelte deleted file mode 100644 index e784d6e5ba8..00000000000 --- a/web-common/src/features/templates/kpi/KPITemplate.svelte +++ /dev/null @@ -1,139 +0,0 @@ -<script lang="ts"> - import { SimpleDataGraphic } from "@rilldata/web-common/components/data-graphic/elements"; - import { ChunkedLine } from "@rilldata/web-common/components/data-graphic/marks"; - import { extent } from "d3-array"; - import MeasureBigNumber from "@rilldata/web-common/features/dashboards/big-number/MeasureBigNumber.svelte"; - import { useMetricsViewSpecMeasure } from "@rilldata/web-common/features/dashboards/selectors"; - import { - MainAreaColorGradientDark, - MainAreaColorGradientLight, - MainLineColor, - } from "@rilldata/web-common/features/dashboards/time-series/chart-colors"; - import { EntityStatus } from "@rilldata/web-common/features/entity-management/types"; - import { - useKPIComparisonTotal, - useKPISparkline, - useKPITotals, - } from "@rilldata/web-common/features/templates/kpi/selector"; - import type { KPIProperties } from "@rilldata/web-common/features/templates/types"; - import { humaniseISODuration } from "@rilldata/web-common/lib/time/ranges/iso-ranges"; - import type { V1ComponentSpecRendererProperties } from "@rilldata/web-common/runtime-client"; - import { runtime } from "@rilldata/web-common/runtime-client/runtime-store"; - import { queryClient } from "@rilldata/web-common/lib/svelte-query/globalQueryClient"; - - export let rendererProperties: V1ComponentSpecRendererProperties; - - let containerWidth: number; - - $: ({ instanceId } = $runtime); - $: kpiProperties = rendererProperties as KPIProperties; - - $: ({ - metrics_view: metricsViewName, - filter: whereSql, - measure: measureName, - time_range: timeRange, - comparison_range: comparisonTimeRange, - } = kpiProperties); - - $: measure = useMetricsViewSpecMeasure( - instanceId, - metricsViewName, - measureName, - ); - - $: measureValue = useKPITotals( - instanceId, - metricsViewName, - measureName, - timeRange.toUpperCase(), - whereSql, - ); - - $: comparisonValue = useKPIComparisonTotal( - instanceId, - metricsViewName, - measureName, - comparisonTimeRange?.toUpperCase(), - timeRange.toUpperCase(), - whereSql, - queryClient, - ); - - $: sparkline = useKPISparkline( - instanceId, - metricsViewName, - measureName, - timeRange.toUpperCase(), - whereSql, - queryClient, - ); - - $: sparkData = $sparkline?.data || []; - - const focusedAreaGradient: [string, string] = [ - MainAreaColorGradientDark, - MainAreaColorGradientLight, - ]; - - $: [yMin, yMax] = extent(sparkData, (d) => d[measureName]); - $: [xMin, xMax] = extent(sparkData, (d) => d["ts"]); -</script> - -<div - bind:clientWidth={containerWidth} - class="flex flex-row h-full w-full items-center bg-white" -> - {#if $measure.data && $measureValue.data} - <MeasureBigNumber - measure={$measure.data} - value={$measureValue.data} - withTimeseries={false} - showComparison - comparisonValue={$comparisonValue?.data} - status={$measureValue?.isFetching - ? EntityStatus.Running - : EntityStatus.Idle} - isMeasureExpanded={true} - /> - {/if} - - <div> - {#if sparkData.length} - <SimpleDataGraphic - height={comparisonTimeRange ? 70 : 65} - width={containerWidth - 160} - overflowHidden={false} - top={10} - bottom={0} - right={10} - left={0} - {xMin} - {xMax} - {yMin} - {yMax} - > - <ChunkedLine - lineColor={MainLineColor} - areaGradientColors={focusedAreaGradient} - data={sparkData} - xAccessor="ts" - yAccessor={measureName} - /> - </SimpleDataGraphic> - {/if} - - {#if comparisonTimeRange} - <div class="comparison-value"> - vs last {humaniseISODuration(comparisonTimeRange.toUpperCase(), false)} - </div> - {/if} - </div> -</div> - -<style lang="postcss"> - .comparison-value { - font-size: 0.8rem; - @apply ui-copy-muted pl-1 pt-0.5; - } -</style> diff --git a/web-common/src/features/templates/select/Select.svelte b/web-common/src/features/templates/select/Select.svelte deleted file mode 100644 index cfde9844a8f..00000000000 --- a/web-common/src/features/templates/select/Select.svelte +++ /dev/null @@ -1,53 +0,0 @@ -<script lang="ts"> - import Select from "@rilldata/web-common/components/forms/Select.svelte"; - import { - canvasVariablesStore, - useVariable, - } from "@rilldata/web-common/features/canvas/variables-store"; - import type { SelectProperties } from "@rilldata/web-common/features/templates/types"; - import type { - V1ComponentSpecRendererProperties, - V1ComponentVariable, - } from "@rilldata/web-common/runtime-client"; - import { getContext } from "svelte"; - - const MAX_OPTIONS = 250; - const canvasName = getContext("rill::canvas:name") as string; - - export let componentName: string; - export let data: any[] | undefined; - export let rendererProperties: V1ComponentSpecRendererProperties; - export let output: V1ComponentVariable | undefined; - - $: outputVariableName = output?.name || ""; - $: outputVariableValue = useVariable(canvasName, outputVariableName); - $: selectProperties = rendererProperties as SelectProperties; - - $: value = (value || $outputVariableValue || output?.defaultValue) as string; - - $: selectOptions = (data || []) - .map((v) => ({ - value: String(v[selectProperties.valueField]), - label: String( - v[selectProperties?.labelField || selectProperties.valueField], - ), - })) - .slice(0, MAX_OPTIONS); -</script> - -<div> - <Select - on:change={(e) => - canvasVariablesStore.updateVariable( - canvasName, - outputVariableName, - e.detail, - )} - bind:value - id={componentName} - tooltip={selectProperties.tooltip || ""} - label={selectProperties.label || ""} - options={selectOptions} - placeholder={selectProperties.placeholder || ""} - /> -</div> diff --git a/web-common/src/features/templates/switch/Switch.svelte b/web-common/src/features/templates/switch/Switch.svelte deleted file mode 100644 index da910cdff66..00000000000 --- a/web-common/src/features/templates/switch/Switch.svelte +++ /dev/null @@ -1,52 +0,0 @@ -<script lang="ts"> - import { Switch } from "@rilldata/web-common/components/button"; - import Tooltip from "@rilldata/web-common/components/tooltip/Tooltip.svelte"; - import TooltipContent from "@rilldata/web-common/components/tooltip/TooltipContent.svelte"; - import { - canvasVariablesStore, - useVariable, - } from "@rilldata/web-common/features/canvas/variables-store"; - import type { SwitchProperties } from "@rilldata/web-common/features/templates/types"; - import type { - V1ComponentSpecRendererProperties, - V1ComponentVariable, - } from "@rilldata/web-common/runtime-client"; - import { getContext } from "svelte"; - - export let rendererProperties: V1ComponentSpecRendererProperties; - export let output: V1ComponentVariable | undefined; - - $: canvasName = getContext("rill::canvas:name") as string; - $: outputVariableName = output?.name || ""; - $: outputVariableValue = useVariable(canvasName, outputVariableName); - $: switchProperties = rendererProperties as SwitchProperties; - - $: value = (value || $outputVariableValue || output?.defaultValue) as boolean; -</script> - -<Tooltip - distance={8} - location="bottom" - alignment="start" - suppress={!switchProperties?.tooltip} -> - <slot name="tooltip" /> - <div class="m-1 p-1 flex items-center h-full"> - <Switch - checked={value} - on:click={() => { - value = !value; - canvasVariablesStore.updateVariable( - canvasName, - outputVariableName, - value, - ); - }} - > - {switchProperties.label} - </Switch> - </div> - <TooltipContent slot="tooltip-content"> - {switchProperties?.tooltip} - </TooltipContent> -</Tooltip> diff --git a/web-common/src/features/templates/types.ts b/web-common/src/features/templates/types.ts index a0cf2983f32..af9fd418797 100644 --- a/web-common/src/features/templates/types.ts +++ b/web-common/src/features/templates/types.ts @@ -3,35 +3,6 @@ interface DataProperties { filter?: string; } -export interface ChartProperties { - x: string; - y: string; - xLabel?: string; - yLabel?: string; - color?: string; -} - -interface LineChart { - line_chart: ChartProperties; -} - -interface BarChart { - bar_chart: ChartProperties; -} - -interface StackedBarChart { - stacked_bar_chart: ChartProperties; -} - -export interface KPIProperties extends DataProperties { - measure: string; - time_range: string; - comparison_range?: string; -} -export interface KPITemplateT { - kpi: KPIProperties; -} - export interface TableProperties extends DataProperties { time_range: string; measures: string[]; @@ -83,11 +54,7 @@ export interface ImageTemplateT { image: ImageProperties; } -type ChartTemplates = LineChart | BarChart | StackedBarChart; - export type TemplateSpec = - | ChartTemplates - | KPITemplateT | TableTemplateT | MarkdownTemplateT | ImageTemplateT diff --git a/web-common/src/features/visual-editing/SidebarWrapper.svelte b/web-common/src/features/visual-editing/SidebarWrapper.svelte index a23e0d283cf..f8230ffb26c 100644 --- a/web-common/src/features/visual-editing/SidebarWrapper.svelte +++ b/web-common/src/features/visual-editing/SidebarWrapper.svelte @@ -1,14 +1,18 @@ <script lang="ts"> export let title: string; + export let type: "primary" | "secondary" = "primary"; + export let disableHorizontalPadding = false; </script> <div class="size-full bg-background flex-none flex flex-col select-none rounded-[2px] w-full" > - <h1>{title}</h1> + <h1 class={type}>{title}</h1> <div - class="px-5 flex flex-col gap-y-3 w-full h-full overflow-y-auto overflow-x-visible" + class="{disableHorizontalPadding + ? '' + : 'px-5'} flex flex-col gap-y-3 w-full h-full overflow-y-auto overflow-x-visible" > <slot /> </div> @@ -17,12 +21,14 @@ </div> <style lang="postcss"> - h1 { - @apply text-lg font-semibold mb-2; + .primary { + @apply text-lg font-semibold; @apply pt-6 px-5 mb-2; } - /* h2 { - @apply text-sm font-medium; - } */ + .secondary { + @apply text-sm font-semibold; + @apply bg-slate-50; + @apply px-5 py-2; + } </style> diff --git a/web-common/src/features/visual-editing/ThemeInput.svelte b/web-common/src/features/visual-editing/ThemeInput.svelte index f8617a3f6be..be2fa681dee 100644 --- a/web-common/src/features/visual-editing/ThemeInput.svelte +++ b/web-common/src/features/visual-editing/ThemeInput.svelte @@ -1,15 +1,15 @@ <script lang="ts"> import ColorInput from "@rilldata/web-common/components/color-picker/ColorInput.svelte"; + import FieldSwitcher from "@rilldata/web-common/components/forms/FieldSwitcher.svelte"; import InputLabel from "@rilldata/web-common/components/forms/InputLabel.svelte"; import Select from "@rilldata/web-common/components/forms/Select.svelte"; + import type { V1ThemeSpec } from "@rilldata/web-common/runtime-client"; + import { runtime } from "@rilldata/web-common/runtime-client/runtime-store"; import { defaultPrimaryColors, defaultSecondaryColors, } from "../themes/color-config"; - import type { V1ThemeSpec } from "@rilldata/web-common/runtime-client"; import { useTheme } from "../themes/selectors"; - import { runtime } from "@rilldata/web-common/runtime-client/runtime-store"; - import FieldSwitcher from "@rilldata/web-common/components/forms/FieldSwitcher.svelte"; const defaultTheme: V1ThemeSpec = { primaryColorRaw: `hsl(${defaultPrimaryColors[500].split(" ").join(",")})`, @@ -25,6 +25,7 @@ export let theme: string | V1ThemeSpec | undefined; export let onThemeChange: (themeName: string | undefined) => void; export let onColorChange: (primary: string, secondary: string) => void; + export let small = false; let themeProxy: V1ThemeSpec = typeof theme === "string" || theme === undefined @@ -46,14 +47,16 @@ $: presetMode = theme === undefined || typeof theme === "string"; </script> -<div class="flex flex-col gap-y-1"> +<div class="flex flex-col {small ? 'gap-y-2' : 'gap-y-1'}"> <InputLabel label="Theme" + {small} id="visual-explore-theme" hint="Colors may be adjusted for legibility" /> <FieldSwitcher + {small} fields={["Presets", "Custom"]} selected={presetMode ? 0 : 1} onClick={(_, field) => { @@ -71,7 +74,8 @@ <div class="gap-y-2 flex flex-col"> {#if typeof theme === "string" || theme === undefined} <Select - fontSize={14} + size={small ? "sm" : "lg"} + fontSize={small ? 12 : 14} sameWidth onChange={(value) => { if (value === "Default") { @@ -92,6 +96,7 @@ {/if} <ColorInput + {small} stringColor={currentTheme.primaryColorRaw} label="Primary" disabled={presetMode} @@ -101,6 +106,7 @@ }} /> <ColorInput + {small} stringColor={currentTheme.secondaryColorRaw} label="Secondary" disabled={presetMode} diff --git a/web-common/src/features/visual-editing/TimeRangeInput.svelte b/web-common/src/features/visual-editing/TimeRangeInput.svelte new file mode 100644 index 00000000000..3d404857be5 --- /dev/null +++ b/web-common/src/features/visual-editing/TimeRangeInput.svelte @@ -0,0 +1,87 @@ +<script lang="ts"> + import FieldSwitcher from "@rilldata/web-common/components/forms/FieldSwitcher.svelte"; + import InputLabel from "@rilldata/web-common/components/forms/InputLabel.svelte"; + import { + PERIOD_TO_DATE_RANGES, + LATEST_WINDOW_TIME_RANGES, + PREVIOUS_COMPLETE_DATE_RANGES, + DEFAULT_TIME_RANGES, + } from "@rilldata/web-common/lib/time/config"; + import SelectionDropdown from "./SelectionDropdown.svelte"; + + const ranges = [ + ...Object.keys(LATEST_WINDOW_TIME_RANGES), + ...Object.keys(PERIOD_TO_DATE_RANGES), + ...Object.keys(PREVIOUS_COMPLETE_DATE_RANGES), + ]; + + const defaultSet = new Set(ranges); + + export let selectedItems: Set<string>; + export let keyNotSet: boolean; + export let onSelectCustomItem: (item: string) => void; + export let setTimeRanges: (timeRanges: string[]) => void; + + let hasDefaultsSelected = + keyNotSet || + (defaultSet.size === selectedItems.size && + defaultSet.isSubsetOf(selectedItems)); + + let selected: 0 | 1 = hasDefaultsSelected ? 0 : 1; + + let selectedProxy = new Set(selectedItems); + + $: if (keyNotSet) { + selected = 0; + } +</script> + +<div class="flex flex-col gap-y-1"> + <InputLabel + capitalize={false} + label="Time ranges" + id="visual-explore-range" + hint="Time range shortcuts available via the dashboard filter bar" + /> + <FieldSwitcher + fields={["default", "custom"]} + {selected} + onClick={(_, field) => { + if (field === "custom") { + selected = 1; + setTimeRanges(Array.from(selectedProxy)); + } else if (field === "default") { + selected = 0; + setTimeRanges(ranges); + } + }} + /> + + {#if selected === 1} + <SelectionDropdown + allItems={defaultSet} + {selectedItems} + onSelect={(item) => { + const deleted = selectedProxy.delete(item); + if (!deleted) { + selectedProxy.add(item); + } + + selectedProxy = selectedProxy; + + onSelectCustomItem(item); + }} + setItems={(ranges) => { + selectedProxy = new Set(ranges); + setTimeRanges(ranges); + }} + let:item + type="time ranges" + > + {DEFAULT_TIME_RANGES[item]?.label ?? item} + </SelectionDropdown> + {/if} +</div> + +<style lang="postcss"> +</style> diff --git a/web-common/src/features/visual-editing/TimeZoneInput.svelte b/web-common/src/features/visual-editing/TimeZoneInput.svelte new file mode 100644 index 00000000000..8cc722356dd --- /dev/null +++ b/web-common/src/features/visual-editing/TimeZoneInput.svelte @@ -0,0 +1,75 @@ +<script lang="ts"> + import FieldSwitcher from "@rilldata/web-common/components/forms/FieldSwitcher.svelte"; + import InputLabel from "@rilldata/web-common/components/forms/InputLabel.svelte"; + import { DEFAULT_TIMEZONES } from "@rilldata/web-common/lib/time/config"; + import ZoneDisplay from "../dashboards/time-controls/super-pill/components/ZoneDisplay.svelte"; + import SelectionDropdown from "./SelectionDropdown.svelte"; + + const defaultSet = new Set(DEFAULT_TIMEZONES); + const searchableItems = Intl.supportedValuesOf("timeZone"); + + export let selectedItems: Set<string>; + export let keyNotSet: boolean; + export let onSelectCustomItem: (item: string) => void; + export let setTimeZones: (timeZones: string[]) => void; + + let hasDefaultsSelected = + keyNotSet || + (defaultSet.size === selectedItems.size && + defaultSet.isSubsetOf(selectedItems)); + + let selected: 0 | 1 = hasDefaultsSelected ? 0 : 1; + + let selectedProxy = new Set(selectedItems); +</script> + +<div class="flex flex-col gap-y-1"> + <InputLabel + capitalize={false} + label="Time zones" + id="visual-explore-zone" + hint="Time zones selectable via the dashboard filter bar" + /> + <FieldSwitcher + fields={["default", "custom"]} + {selected} + onClick={(_, field) => { + if (field === "custom") { + selected = 1; + setTimeZones(Array.from(selectedProxy)); + } else if (field === "default") { + selected = 0; + setTimeZones(DEFAULT_TIMEZONES); + } + }} + /> + + {#if selected === 1} + <SelectionDropdown + {searchableItems} + allItems={defaultSet} + {selectedItems} + onSelect={(item) => { + const deleted = selectedProxy.delete(item); + if (!deleted) { + selectedProxy.add(item); + } + + selectedProxy = selectedProxy; + + onSelectCustomItem(item); + }} + setItems={(ranges) => { + selectedProxy = new Set(ranges); + setTimeZones(ranges); + }} + let:item + type="time zones" + > + <ZoneDisplay iana={item} /> + </SelectionDropdown> + {/if} +</div> + +<style lang="postcss"> +</style> diff --git a/web-common/src/features/workspaces/CanvasDashboardWorkspace.svelte b/web-common/src/features/workspaces/CanvasDashboardWorkspace.svelte deleted file mode 100644 index ec4311dc2ce..00000000000 --- a/web-common/src/features/workspaces/CanvasDashboardWorkspace.svelte +++ /dev/null @@ -1,336 +0,0 @@ -<script lang="ts"> - import { goto } from "$app/navigation"; - import type { EditorView } from "@codemirror/view"; - import Label from "@rilldata/web-common/components/forms/Label.svelte"; - import Switch from "@rilldata/web-common/components/forms/Switch.svelte"; - import ComponentsEditor from "@rilldata/web-common/features/canvas-components/editor/ComponentsEditor.svelte"; - import ComponentsEditorContainer from "@rilldata/web-common/features/canvas-components/editor/ComponentsEditorContainer.svelte"; - import AddComponentMenu from "@rilldata/web-common/features/canvas/AddComponentMenu.svelte"; - import CanvasDashboardPreview from "@rilldata/web-common/features/canvas/CanvasDashboardPreview.svelte"; - import ViewSelector from "@rilldata/web-common/features/visual-editing/ViewSelector.svelte"; - import type { Vector } from "@rilldata/web-common/features/canvas/types"; - import Editor from "@rilldata/web-common/features/editor/Editor.svelte"; - import { FileExtensionToEditorExtension } from "@rilldata/web-common/features/editor/getExtensionsForFile"; - import { getNameFromFile } from "@rilldata/web-common/features/entity-management/entity-mappers"; - import type { FileArtifact } from "@rilldata/web-common/features/entity-management/file-artifact"; - import { fileArtifacts } from "@rilldata/web-common/features/entity-management/file-artifacts"; - import { ResourceKind } from "@rilldata/web-common/features/entity-management/resource-selectors"; - import { handleEntityRename } from "@rilldata/web-common/features/entity-management/ui-actions"; - import Resizer from "@rilldata/web-common/layout/Resizer.svelte"; - import { - WorkspaceContainer, - WorkspaceHeader, - } from "@rilldata/web-common/layout/workspace"; - import { queryClient } from "@rilldata/web-common/lib/svelte-query/globalQueryClient"; - import type { V1CanvasSpec } from "@rilldata/web-common/runtime-client"; - import { runtime } from "@rilldata/web-common/runtime-client/runtime-store"; - import { setContext } from "svelte"; - import Button from "web-common/src/components/button/Button.svelte"; - import { parseDocument } from "yaml"; - import { - resourceColorMapping, - resourceIconMapping, - } from "../entity-management/resource-icon-mapping"; - import PreviewButton from "../explores/PreviewButton.svelte"; - - export let fileArtifact: FileArtifact; - - let canvasDashboardName: string; - let selectedComponentFileArtifact: FileArtifact | undefined; - let selectedView: "split" | "code" | "viz"; - let showGrid = true; - let showComponentEditor = false; - let containerWidth: number; - let containerHeight: number; - let editorPercentage = 0.5; - let editor: EditorView; - let selectedIndex: number | null = null; - let componentEditorPercentage = 0.4; - let selectedComponentName: string | null = null; - let spec: V1CanvasSpec = { - columns: 20, - gap: 4, - items: [], - }; - - $: canvasDashboardName = getNameFromFile(filePath); - $: setContext("rill::canvas:name", canvasDashboardName); - - $: ({ instanceId } = $runtime); - - $: errorsQuery = fileArtifact.getAllErrors(queryClient, instanceId); - $: errors = $errorsQuery; - - $: ({ - saveLocalContent: updateComponentFile, - autoSave, - path: filePath, - fileName, - updateEditorContent, - editorContent, - hasUnsavedChanges, - } = fileArtifact); - - $: resourceQuery = fileArtifact.getResource(queryClient, instanceId); - - $: spec = structuredClone($resourceQuery.data?.canvas?.spec ?? spec); - - $: ({ items = [], columns = 20, gap = 4, variables = [] } = spec); - $: if ( - items.filter( - (item) => - !item.definedInCanvas && item.component === selectedComponentName, - ).length - ) { - selectedComponentFileArtifact = fileArtifacts.findFileArtifact( - ResourceKind.Component, - selectedComponentName ?? "", - ); - } else { - selectedComponentName = null; - selectedComponentFileArtifact = undefined; - showComponentEditor = false; - } - $: selectedComponentFilePath = selectedComponentFileArtifact?.path; - $: editorWidth = editorPercentage * containerWidth; - $: componentEditorHeight = componentEditorPercentage * containerHeight; - - async function onChangeCallback(newTitle: string) { - const newRoute = await handleEntityRename( - instanceId, - newTitle, - filePath, - fileName, - ); - if (newRoute) await goto(newRoute); - } - - async function handlePreviewUpdate( - e: CustomEvent<{ - index: number; - position: Vector; - dimensions: Vector; - }>, - ) { - const parsedDocument = parseDocument($editorContent ?? ""); - const items = parsedDocument.get("items") as any; - - const node = items.get(e.detail.index); - - node.set("width", e.detail.dimensions[0]); - node.set("height", e.detail.dimensions[1]); - node.set("x", e.detail.position[0]); - node.set("y", e.detail.position[1]); - - updateEditorContent(parsedDocument.toString()); - - if ($autoSave) await updateComponentFile(); - } - - async function addComponent(componentName: string) { - const newComponent = { - component: componentName, - height: 4, - width: 4, - x: 0, - y: 0, - }; - const parsedDocument = parseDocument($editorContent ?? ""); - - const items = parsedDocument.get("items") as any; - - if (!items) { - parsedDocument.set("items", [newComponent]); - } else { - items.add(newComponent); - } - - updateEditorContent(parsedDocument.toString(), true); - - if ($autoSave) await updateComponentFile(); - } - - async function handleDeleteEvent( - e: CustomEvent<{ - index: number; - }>, - ) { - if (!e.detail.index) return; - await deleteComponent(e.detail.index); - } - - async function deleteComponent(index: number) { - const parsedDocument = parseDocument($editorContent ?? ""); - - const items = parsedDocument.get("items") as any; - - if (!items) return; - - items.delete(index); - - updateEditorContent(parsedDocument.toString(), true); - - if ($autoSave) await updateComponentFile(); - } -</script> - -<svelte:window - on:keydown={async (e) => { - if (e.target !== document.body || selectedIndex === null) return; - if (e.key === "Delete" || e.key === "Backspace") { - await deleteComponent(selectedIndex); - } - }} -/> - -<WorkspaceContainer - bind:height={containerHeight} - bind:width={containerWidth} - inspector={false} -> - <WorkspaceHeader - slot="header" - {filePath} - resourceKind={ResourceKind.Canvas} - hasUnsavedChanges={$hasUnsavedChanges} - showInspectorToggle={false} - titleInput={fileName} - onTitleChange={onChangeCallback} - > - <div class="flex gap-x-2 items-center" slot="workspace-controls"> - <PreviewButton - href="/custom/{canvasDashboardName}" - disabled={errors?.length > 0} - /> - - <AddComponentMenu {addComponent} /> - <ViewSelector bind:selectedView /> - </div> - </WorkspaceHeader> - - <div class="flex w-full h-full flex-row overflow-hidden" slot="body"> - {#if selectedView === "code" || selectedView === "split"} - <div - class="relative h-full flex-shrink-0 w-full" - class:!w-full={selectedView === "code"} - style:width="{editorPercentage * 100}%" - > - <div class="flex flex-col h-full overflow-hidden"> - <section class="size-full flex flex-col flex-shrink overflow-hidden"> - <ComponentsEditorContainer error={errors[0]}> - <Editor - bind:editor - {fileArtifact} - extensions={FileExtensionToEditorExtension[".yaml"]} - autoSave - showSaveBar={false} - onRevert={() => { - spec = structuredClone(spec); - }} - /> - </ComponentsEditorContainer> - </section> - - {#if selectedComponentName || showComponentEditor} - <section - style:height="{componentEditorPercentage * 100}%" - class:!h-12={!showComponentEditor} - class="size-full flex flex-col flex-none flex-shrink-0 relative !min-h-12" - > - <Resizer - direction="NS" - dimension={componentEditorHeight} - min={80} - max={0.85 * containerHeight} - onUpdate={(height) => - (componentEditorPercentage = height / containerHeight)} - /> - <header - class="flex justify-between items-center pr-2 bg-gray-100 flex-none py-2" - > - <h1 - class="font-semibold text-xl truncate flex items-center gap-x-2" - > - {#if selectedComponentName} - <svelte:component - this={resourceIconMapping[ResourceKind.Component]} - size="18px" - color={resourceColorMapping[ResourceKind.Component]} - /> - {selectedComponentName}.yaml - {/if} - </h1> - - <Button - type="subtle" - on:click={() => (showComponentEditor = !showComponentEditor)} - > - {showComponentEditor ? "Close" : "Open"} - </Button> - </header> - - {#if showComponentEditor} - <div class="size-full overflow-hidden"> - {#if selectedComponentFilePath} - <ComponentsEditor filePath={selectedComponentFilePath} /> - {/if} - </div> - {/if} - </section> - {/if} - </div> - </div> - {/if} - - {#if selectedView === "split"} - <Resizer - absolute={false} - direction="EW" - side="right" - dimension={editorWidth} - min={300} - max={0.65 * containerWidth} - onUpdate={(width) => (editorPercentage = width / containerWidth)} - /> - {/if} - - {#if selectedView === "viz" || selectedView === "split"} - <section - class="size-full flex flex-col relative overflow-hidden border border-gray-300 rounded-[2px]" - > - <CanvasDashboardPreview - {canvasDashboardName} - {gap} - {items} - {columns} - {showGrid} - {variables} - bind:selectedComponentName - bind:selectedIndex - on:update={handlePreviewUpdate} - on:delete={handleDeleteEvent} - /> - - <div class="floating-grid-wrapper"> - <Switch small id="grid" bind:checked={showGrid} /> - <Label for="grid" class="font-medium text-xs text-gray-600"> - Grid - </Label> - </div> - </section> - {/if} - </div> -</WorkspaceContainer> - -<style lang="postcss"> - .floating-grid-wrapper { - @apply transition-all; - @apply opacity-50 shadow-lg border border-slate-200 bg-slate-100; - @apply flex gap-x-1 flex-none py-1 px-2 items-center h-fit rounded-full; - @apply absolute bottom-2 right-2; - } - - .floating-grid-wrapper:hover { - @apply opacity-100; - } -</style> diff --git a/web-common/src/features/workspaces/CanvasWorkspace.svelte b/web-common/src/features/workspaces/CanvasWorkspace.svelte new file mode 100644 index 00000000000..ccb80a45e28 --- /dev/null +++ b/web-common/src/features/workspaces/CanvasWorkspace.svelte @@ -0,0 +1,196 @@ +<script lang="ts"> + import { goto } from "$app/navigation"; + import ErrorPage from "@rilldata/web-common/components/ErrorPage.svelte"; + import Canvas from "@rilldata/web-common/features/canvas/Canvas.svelte"; + import CanvasEditor from "@rilldata/web-common/features/canvas/CanvasEditor.svelte"; + import CanvasThemeProvider from "@rilldata/web-common/features/canvas/CanvasThemeProvider.svelte"; + import AddComponentMenu from "@rilldata/web-common/features/canvas/components/AddComponentMenu.svelte"; + import type { CanvasComponentType } from "@rilldata/web-common/features/canvas/components/types"; + import { getComponentRegistry } from "@rilldata/web-common/features/canvas/components/util"; + import VisualCanvasEditing from "@rilldata/web-common/features/canvas/inspector/VisualCanvasEditing.svelte"; + import { useDefaultMetrics } from "@rilldata/web-common/features/canvas/selector"; + import StateManagersProvider from "@rilldata/web-common/features/canvas/state-managers/StateManagersProvider.svelte"; + import DelayedSpinner from "@rilldata/web-common/features/entity-management/DelayedSpinner.svelte"; + import { getNameFromFile } from "@rilldata/web-common/features/entity-management/entity-mappers"; + import type { FileArtifact } from "@rilldata/web-common/features/entity-management/file-artifact"; + import { + resourceIsLoading, + ResourceKind, + } from "@rilldata/web-common/features/entity-management/resource-selectors"; + import { handleEntityRename } from "@rilldata/web-common/features/entity-management/ui-actions"; + import { mapParseErrorsToLines } from "@rilldata/web-common/features/metrics-views/errors"; + import ViewSelector from "@rilldata/web-common/features/visual-editing/ViewSelector.svelte"; + import { + WorkspaceContainer, + WorkspaceHeader, + } from "@rilldata/web-common/layout/workspace"; + import { workspaces } from "@rilldata/web-common/layout/workspace/workspace-stores"; + import WorkspaceEditorContainer from "@rilldata/web-common/layout/workspace/WorkspaceEditorContainer.svelte"; + import { queryClient } from "@rilldata/web-common/lib/svelte-query/globalQueryClient"; + import { runtime } from "@rilldata/web-common/runtime-client/runtime-store"; + import { parseDocument } from "yaml"; + import PreviewButton from "../explores/PreviewButton.svelte"; + + export let fileArtifact: FileArtifact; + + let canvasName: string; + let selectedView: "split" | "code" | "viz"; + + const componentRegistry = getComponentRegistry(fileArtifact); + + $: ({ + saveLocalContent: updateComponentFile, + autoSave, + path: filePath, + fileName, + updateEditorContent, + editorContent, + getResource, + getAllErrors, + remoteContent, + hasUnsavedChanges, + } = fileArtifact); + + $: resourceQuery = getResource(queryClient, instanceId); + + $: ({ data } = $resourceQuery); + + $: allErrorsQuery = getAllErrors(queryClient, instanceId); + $: allErrors = $allErrorsQuery; + + $: resourceIsReconciling = resourceIsLoading(data); + + $: workspace = workspaces.get(filePath); + $: selectedViewStore = workspace.view; + $: selectedView = $selectedViewStore ?? "code"; + + $: canvasResource = data?.canvas; + $: canvasName = getNameFromFile(filePath); + + $: metricsViewQuery = useDefaultMetrics(instanceId); + + $: ({ instanceId } = $runtime); + + $: lineBasedRuntimeErrors = mapParseErrorsToLines( + allErrors, + $remoteContent ?? "", + ); + + $: mainError = lineBasedRuntimeErrors?.at(0); + + async function onChangeCallback(newTitle: string) { + const newRoute = await handleEntityRename( + $runtime.instanceId, + newTitle, + filePath, + fileName, + ); + if (newRoute) await goto(newRoute); + } + + async function addComponent(componentName: CanvasComponentType) { + const defaultMetrics = $metricsViewQuery?.data; + if (!defaultMetrics) return; + + const newSpec = componentRegistry[componentName].newComponentSpec( + defaultMetrics.metricsView, + defaultMetrics.measure, + defaultMetrics.dimension, + ); + + const { width, height } = componentRegistry[componentName].defaultSize; + const newComponent = { + component: { [componentName]: newSpec }, + height, + width, + x: 0, + y: 0, + }; + const parsedDocument = parseDocument( + $editorContent ?? $remoteContent ?? "", + ); + + const items = parsedDocument.get("items") as any; + + if (!items) { + parsedDocument.set("items", [newComponent]); + } else { + items.add(newComponent); + } + + updateEditorContent(parsedDocument.toString(), true); + await updateComponentFile(); + } +</script> + +{#if canvasResource && fileArtifact} + {#key canvasName} + <StateManagersProvider {canvasName}> + <CanvasThemeProvider> + <WorkspaceContainer> + <WorkspaceHeader + slot="header" + {filePath} + hasUnsavedChanges={$hasUnsavedChanges} + titleInput={fileName} + onTitleChange={onChangeCallback} + resourceKind={ResourceKind.Canvas} + > + <div class="flex gap-x-2" slot="cta"> + <PreviewButton + href="/canvas/{canvasName}" + disabled={allErrors.length > 0 || resourceIsReconciling} + reconciling={resourceIsReconciling} + /> + + <AddComponentMenu {addComponent} /> + <ViewSelector + allowSplit={false} + bind:selectedView={$selectedViewStore} + /> + </div> + </WorkspaceHeader> + + <WorkspaceEditorContainer + slot="body" + error={mainError} + showError={!!$remoteContent && selectedView === "code"} + > + {#if selectedView === "code"} + <CanvasEditor + bind:autoSave={$autoSave} + {canvasName} + {fileArtifact} + {lineBasedRuntimeErrors} + /> + {:else if selectedView === "viz"} + {#if mainError} + <ErrorPage + body={mainError.message} + fatal + header="Unable to load dashboard preview" + statusCode={404} + /> + {:else if canvasResource} + <Canvas {fileArtifact} /> + {/if} + {/if} + </WorkspaceEditorContainer> + + <VisualCanvasEditing {fileArtifact} slot="inspector" /> + </WorkspaceContainer> + </CanvasThemeProvider> + </StateManagersProvider> + {/key} +{:else if allErrors.length} + <ErrorPage + body="Please fix the errors in the code editor before previewing the dashboard." + header="Unable to load dashboard preview" + detail={allErrors.map((error) => error.message).join("\n")} + statusCode={404} + /> +{:else} + <div class="grid place-items-center size-full"> + <DelayedSpinner isLoading={true} size="40px" /> + </div> +{/if} diff --git a/web-common/src/features/workspaces/ComponentWorkspace.svelte b/web-common/src/features/workspaces/ComponentWorkspace.svelte deleted file mode 100644 index f6c8a640957..00000000000 --- a/web-common/src/features/workspaces/ComponentWorkspace.svelte +++ /dev/null @@ -1,106 +0,0 @@ -<script lang="ts"> - import ComponentDataDisplay from "@rilldata/web-common/features/canvas-components/ComponentDataDisplay.svelte"; - import ComponentStatusDisplay from "@rilldata/web-common/features/canvas-components/ComponentStatusDisplay.svelte"; - import ComponentsHeader from "@rilldata/web-common/features/canvas-components/ComponentsHeader.svelte"; - import ComponentsEditor from "@rilldata/web-common/features/canvas-components/editor/ComponentsEditor.svelte"; - import CanvasDashboardEmbed from "@rilldata/web-common/features/canvas/CanvasDashboardEmbed.svelte"; - import { getNameFromFile } from "@rilldata/web-common/features/entity-management/entity-mappers"; - import type { FileArtifact } from "@rilldata/web-common/features/entity-management/file-artifact"; - import { - ResourceKind, - useResource, - } from "@rilldata/web-common/features/entity-management/resource-selectors"; - import Resizer from "@rilldata/web-common/layout/Resizer.svelte"; - import { WorkspaceContainer } from "@rilldata/web-common/layout/workspace"; - import { runtime } from "@rilldata/web-common/runtime-client/runtime-store"; - import { getContext } from "svelte"; - - export let fileArtifact: FileArtifact; - - const canvasName = getContext("rill::canvas:name") as string; - - let containerWidth: number; - let containerHeight: number; - let editorPercentage = 0.55; - let tablePercentage = 0.45; - - $: ({ instanceId } = $runtime); - - $: ({ hasUnsavedChanges, path: filePath } = fileArtifact); - $: componentName = getNameFromFile(filePath); - - $: editorWidth = editorPercentage * containerWidth; - - $: resourceQuery = useResource( - instanceId, - componentName, - ResourceKind.Component, - ); - - $: ({ data: componentResource, isFetching } = $resourceQuery); - - $: ({ resolverProperties, input } = componentResource?.component?.spec ?? {}); - - $: tableHeight = tablePercentage * containerHeight; -</script> - -<WorkspaceContainer - inspector={false} - bind:width={containerWidth} - bind:height={containerHeight} -> - <ComponentsHeader - slot="header" - {filePath} - hasUnsavedChanges={$hasUnsavedChanges} - /> - <div slot="body" class="flex size-full"> - <section style:width="{editorPercentage * 100}%"> - <ComponentsEditor {filePath} /> - </section> - - <Resizer - absolute={false} - direction="EW" - side="right" - dimension={editorWidth} - min={300} - max={0.65 * containerWidth} - onUpdate={(width) => (editorPercentage = width / containerWidth)} - /> - - <section class="size-full flex-col flex overflow-hidden"> - <div - class="size-full overflow-hidden border border-gray-300 rounded-[2px]" - > - <ComponentStatusDisplay {isFetching} {componentName}> - <CanvasDashboardEmbed - {canvasName} - chartView - gap={8} - columns={10} - items={[ - { width: 10, height: 10, x: 0, y: 0, component: componentName }, - ]} - /> - </ComponentStatusDisplay> - </div> - - <Resizer - absolute={false} - direction="NS" - dimension={tableHeight} - min={100} - max={0.65 * containerHeight} - onUpdate={(height) => (tablePercentage = height / containerHeight)} - /> - - <ComponentDataDisplay - {componentName} - {tablePercentage} - {input} - {resolverProperties} - /> - </section> - </div> -</WorkspaceContainer> diff --git a/web-common/src/features/workspaces/ExploreWorkspace.svelte b/web-common/src/features/workspaces/ExploreWorkspace.svelte index f2e3ff93957..a97dc2709df 100644 --- a/web-common/src/features/workspaces/ExploreWorkspace.svelte +++ b/web-common/src/features/workspaces/ExploreWorkspace.svelte @@ -1,5 +1,6 @@ <script lang="ts"> import { goto } from "$app/navigation"; + import ErrorPage from "@rilldata/web-common/components/ErrorPage.svelte"; import { initLocalUserPreferenceStore } from "@rilldata/web-common/features/dashboards/user-preferences"; import { getNameFromFile } from "@rilldata/web-common/features/entity-management/entity-mappers"; import type { FileArtifact } from "@rilldata/web-common/features/entity-management/file-artifact"; @@ -9,20 +10,19 @@ } from "@rilldata/web-common/features/entity-management/resource-selectors"; import { handleEntityRename } from "@rilldata/web-common/features/entity-management/ui-actions"; import ExploreEditor from "@rilldata/web-common/features/explores/ExploreEditor.svelte"; + import ViewSelector from "@rilldata/web-common/features/visual-editing/ViewSelector.svelte"; + import { workspaces } from "@rilldata/web-common/layout/workspace/workspace-stores"; import WorkspaceContainer from "@rilldata/web-common/layout/workspace/WorkspaceContainer.svelte"; + import WorkspaceEditorContainer from "@rilldata/web-common/layout/workspace/WorkspaceEditorContainer.svelte"; import WorkspaceHeader from "@rilldata/web-common/layout/workspace/WorkspaceHeader.svelte"; import { queryClient } from "@rilldata/web-common/lib/svelte-query/globalQueryClient"; + import { createRuntimeServiceGetExplore } from "@rilldata/web-common/runtime-client"; import { runtime } from "@rilldata/web-common/runtime-client/runtime-store"; + import DashboardWithProviders from "../dashboards/workspace/DashboardWithProviders.svelte"; + import Spinner from "../entity-management/Spinner.svelte"; import PreviewButton from "../explores/PreviewButton.svelte"; - import { workspaces } from "@rilldata/web-common/layout/workspace/workspace-stores"; - import ViewSelector from "@rilldata/web-common/features/visual-editing/ViewSelector.svelte"; - import VisualExploreEditing from "./VisualExploreEditing.svelte"; import { mapParseErrorsToLines } from "../metrics-views/errors"; - import ErrorPage from "@rilldata/web-common/components/ErrorPage.svelte"; - import { createRuntimeServiceGetExplore } from "@rilldata/web-common/runtime-client"; - import Spinner from "../entity-management/Spinner.svelte"; - import DashboardWithProviders from "../dashboards/workspace/DashboardWithProviders.svelte"; - import WorkspaceEditorContainer from "@rilldata/web-common/layout/workspace/WorkspaceEditorContainer.svelte"; + import VisualExploreEditing from "./VisualExploreEditing.svelte"; export let fileArtifact: FileArtifact; diff --git a/web-common/src/layout/workspace/Inspector.svelte b/web-common/src/layout/workspace/Inspector.svelte index 8c624b896ca..9e7350c0895 100644 --- a/web-common/src/layout/workspace/Inspector.svelte +++ b/web-common/src/layout/workspace/Inspector.svelte @@ -1,11 +1,12 @@ <script lang="ts"> + import { slide } from "svelte/transition"; import Resizer from "../Resizer.svelte"; import { workspaces } from "./workspace-stores"; - import { slide } from "svelte/transition"; export let filePath: string; export let resizable = true; export let fixedWidth: number | undefined = undefined; + export let minWidth = 320; let resizing = false; @@ -28,7 +29,7 @@ absolute={false} direction="EW" side="left" - min={fixedWidth ?? 320} + min={fixedWidth ?? minWidth} max={fixedWidth ?? 420} dimension={fixedWidth ?? width} onUpdate={(newWidth) => { diff --git a/web-common/src/proto/gen/rill/runtime/v1/queries_pb.ts b/web-common/src/proto/gen/rill/runtime/v1/queries_pb.ts index 09cf9f558d5..aacbb12fa73 100644 --- a/web-common/src/proto/gen/rill/runtime/v1/queries_pb.ts +++ b/web-common/src/proto/gen/rill/runtime/v1/queries_pb.ts @@ -3384,7 +3384,7 @@ export class ResolveComponentRequest extends Message<ResolveComponentRequest> { component = ""; /** - * Optional args to pass to the data resolver and for resolving templating in the renderer properties + * Optional args for resolving templating in the renderer properties * * @generated from field: google.protobuf.Struct args = 3; */ @@ -3432,24 +3432,10 @@ export class ResolveComponentResponse extends Message<ResolveComponentResponse> */ show = false; - /** - * Schema of the resolved component data - * - * @generated from field: rill.runtime.v1.StructType schema = 2; - */ - schema?: StructType; - - /** - * Resolved component data - * - * @generated from field: repeated google.protobuf.Struct data = 3; - */ - data: Struct[] = []; - /** * Renderer properties with templating resolved for the provided args * - * @generated from field: google.protobuf.Struct renderer_properties = 4; + * @generated from field: google.protobuf.Struct renderer_properties = 2; */ rendererProperties?: Struct; @@ -3462,9 +3448,7 @@ export class ResolveComponentResponse extends Message<ResolveComponentResponse> static readonly typeName = "rill.runtime.v1.ResolveComponentResponse"; static readonly fields: FieldList = proto3.util.newFieldList(() => [ { no: 1, name: "show", kind: "scalar", T: 8 /* ScalarType.BOOL */ }, - { no: 2, name: "schema", kind: "message", T: StructType }, - { no: 3, name: "data", kind: "message", T: Struct, repeated: true }, - { no: 4, name: "renderer_properties", kind: "message", T: Struct }, + { no: 2, name: "renderer_properties", kind: "message", T: Struct }, ]); static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): ResolveComponentResponse { diff --git a/web-common/src/proto/gen/rill/runtime/v1/resources_pb.ts b/web-common/src/proto/gen/rill/runtime/v1/resources_pb.ts index 3a0cdb0cfd5..09df2c60d6a 100644 --- a/web-common/src/proto/gen/rill/runtime/v1/resources_pb.ts +++ b/web-common/src/proto/gen/rill/runtime/v1/resources_pb.ts @@ -4263,16 +4263,6 @@ export class ComponentSpec extends Message<ComponentSpec> { */ description = ""; - /** - * @generated from field: string resolver = 2; - */ - resolver = ""; - - /** - * @generated from field: google.protobuf.Struct resolver_properties = 3; - */ - resolverProperties?: Struct; - /** * @generated from field: string renderer = 4; */ @@ -4315,8 +4305,6 @@ export class ComponentSpec extends Message<ComponentSpec> { static readonly fields: FieldList = proto3.util.newFieldList(() => [ { no: 1, name: "display_name", kind: "scalar", T: 9 /* ScalarType.STRING */ }, { no: 7, name: "description", kind: "scalar", T: 9 /* ScalarType.STRING */ }, - { no: 2, name: "resolver", kind: "scalar", T: 9 /* ScalarType.STRING */ }, - { no: 3, name: "resolver_properties", kind: "message", T: Struct }, { no: 4, name: "renderer", kind: "scalar", T: 9 /* ScalarType.STRING */ }, { no: 5, name: "renderer_properties", kind: "message", T: Struct }, { no: 8, name: "input", kind: "message", T: ComponentVariable, repeated: true }, @@ -4481,14 +4469,19 @@ export class CanvasSpec extends Message<CanvasSpec> { displayName = ""; /** - * @generated from field: uint32 columns = 2; + * @generated from field: uint32 max_width = 2; + */ + maxWidth = 0; + + /** + * @generated from field: string theme = 7; */ - columns = 0; + theme = ""; /** - * @generated from field: uint32 gap = 3; + * @generated from field: rill.runtime.v1.ThemeSpec embedded_theme = 8; */ - gap = 0; + embeddedTheme?: ThemeSpec; /** * @generated from field: repeated rill.runtime.v1.ComponentVariable variables = 5; @@ -4514,8 +4507,9 @@ export class CanvasSpec extends Message<CanvasSpec> { static readonly typeName = "rill.runtime.v1.CanvasSpec"; static readonly fields: FieldList = proto3.util.newFieldList(() => [ { no: 1, name: "display_name", kind: "scalar", T: 9 /* ScalarType.STRING */ }, - { no: 2, name: "columns", kind: "scalar", T: 13 /* ScalarType.UINT32 */ }, - { no: 3, name: "gap", kind: "scalar", T: 13 /* ScalarType.UINT32 */ }, + { no: 2, name: "max_width", kind: "scalar", T: 13 /* ScalarType.UINT32 */ }, + { no: 7, name: "theme", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 8, name: "embedded_theme", kind: "message", T: ThemeSpec }, { no: 5, name: "variables", kind: "message", T: ComponentVariable, repeated: true }, { no: 4, name: "items", kind: "message", T: CanvasItem, repeated: true }, { no: 6, name: "security_rules", kind: "message", T: SecurityRule, repeated: true }, diff --git a/web-common/src/runtime-client/gen/index.schemas.ts b/web-common/src/runtime-client/gen/index.schemas.ts index 08999c4ba74..dd13b652268 100644 --- a/web-common/src/runtime-client/gen/index.schemas.ts +++ b/web-common/src/runtime-client/gen/index.schemas.ts @@ -582,6 +582,12 @@ export interface V1TimeSeriesValue { records?: V1TimeSeriesValueRecords; } +export interface V1TimeSeriesTimeRange { + start?: string; + end?: string; + interval?: V1TimeGrain; +} + export interface V1TimeSeriesResponse { results?: V1TimeSeriesValue[]; spark?: V1TimeSeriesValue[]; @@ -610,12 +616,6 @@ export const V1TimeGrain = { TIME_GRAIN_YEAR: "TIME_GRAIN_YEAR", } as const; -export interface V1TimeSeriesTimeRange { - start?: string; - end?: string; - interval?: V1TimeGrain; -} - export interface V1TimeRange { start?: string; end?: string; @@ -833,17 +833,20 @@ export type V1ResolveComponentResponseRendererProperties = { [key: string]: any; }; -export type V1ResolveComponentResponseDataItem = { [key: string]: any }; - export interface V1ResolveComponentResponse { /** Show property with templating resolved for the provided args. If it resolves to false, the other fields are not set. */ show?: boolean; - schema?: V1StructType; - data?: V1ResolveComponentResponseDataItem[]; rendererProperties?: V1ResolveComponentResponseRendererProperties; } +export interface V1ReportState { + nextRunOn?: string; + currentExecution?: V1ReportExecution; + executionHistory?: V1ReportExecution[]; + executionCount?: number; +} + export type V1ReportSpecAnnotations = { [key: string]: string }; export interface V1ReportSpec { @@ -872,13 +875,6 @@ export interface V1ReportExecution { finishedOn?: string; } -export interface V1ReportState { - nextRunOn?: string; - currentExecution?: V1ReportExecution; - executionHistory?: V1ReportExecution[]; - executionCount?: number; -} - export interface V1Report { spec?: V1ReportSpec; state?: V1ReportState; @@ -1353,6 +1349,10 @@ export interface V1MetricsViewSort { ascending?: boolean; } +export interface V1MetricsViewSearchResponse { + results?: MetricsViewSearchResponseSearchResult[]; +} + export interface V1MetricsViewSchemaResponse { schema?: V1StructType; } @@ -1833,6 +1833,11 @@ export const V1ExploreWebView = { EXPLORE_WEB_VIEW_CANVAS: "EXPLORE_WEB_VIEW_CANVAS", } as const; +export interface V1ExploreTimeRange { + range?: string; + comparisonTimeRanges?: V1ExploreComparisonTimeRange[]; +} + export interface V1ExploreSpec { displayName?: string; description?: string; @@ -1885,11 +1890,6 @@ If not specified, it should fallback to the range of the base time range. */ range?: string; } -export interface V1ExploreTimeRange { - range?: string; - comparisonTimeRanges?: V1ExploreComparisonTimeRange[]; -} - export type V1ExploreComparisonMode = (typeof V1ExploreComparisonMode)[keyof typeof V1ExploreComparisonMode]; @@ -2081,13 +2081,9 @@ export interface V1ComponentVariable { export type V1ComponentSpecRendererProperties = { [key: string]: any }; -export type V1ComponentSpecResolverProperties = { [key: string]: any }; - export interface V1ComponentSpec { displayName?: string; description?: string; - resolver?: string; - resolverProperties?: V1ComponentSpecResolverProperties; renderer?: string; rendererProperties?: V1ComponentSpecRendererProperties; input?: V1ComponentVariable[]; @@ -2283,8 +2279,9 @@ export interface V1CanvasItem { export interface V1CanvasSpec { displayName?: string; - columns?: number; - gap?: number; + maxWidth?: number; + theme?: string; + embeddedTheme?: V1ThemeSpec; variables?: V1ComponentVariable[]; items?: V1CanvasItem[]; securityRules?: V1SecurityRule[]; @@ -2675,10 +2672,6 @@ export interface MetricsViewSearchResponseSearchResult { value?: unknown; } -export interface V1MetricsViewSearchResponse { - results?: MetricsViewSearchResponseSearchResult[]; -} - export interface MetricsViewFilterCond { name?: string; in?: unknown[]; diff --git a/web-local/src/routes/(application)/(workspace)/files/[...file]/+page.svelte b/web-local/src/routes/(application)/(workspace)/files/[...file]/+page.svelte index d92d414af35..68c6835234c 100644 --- a/web-local/src/routes/(application)/(workspace)/files/[...file]/+page.svelte +++ b/web-local/src/routes/(application)/(workspace)/files/[...file]/+page.svelte @@ -7,8 +7,8 @@ import { getExtensionsForFile } from "@rilldata/web-common/features/editor/getExtensionsForFile"; import { ResourceKind } from "@rilldata/web-common/features/entity-management/resource-selectors"; import { directoryState } from "@rilldata/web-common/features/file-explorer/directory-store"; - import CanvasDashboardWorkspace from "@rilldata/web-common/features/workspaces/CanvasDashboardWorkspace.svelte"; - import ComponentWorkspace from "@rilldata/web-common/features/workspaces/ComponentWorkspace.svelte"; + import { mapParseErrorsToLines } from "@rilldata/web-common/features/metrics-views/errors"; + import CanvasWorkspace from "@rilldata/web-common/features/workspaces/CanvasWorkspace.svelte"; import ExploreWorkspace from "@rilldata/web-common/features/workspaces/ExploreWorkspace.svelte"; import MetricsWorkspace from "@rilldata/web-common/features/workspaces/MetricsWorkspace.svelte"; import ModelWorkspace from "@rilldata/web-common/features/workspaces/ModelWorkspace.svelte"; @@ -16,18 +16,16 @@ import WorkspaceContainer from "@rilldata/web-common/layout/workspace/WorkspaceContainer.svelte"; import WorkspaceEditorContainer from "@rilldata/web-common/layout/workspace/WorkspaceEditorContainer.svelte"; import { queryClient } from "@rilldata/web-common/lib/svelte-query/globalQueryClient.js"; - import { onMount } from "svelte"; import { runtime } from "@rilldata/web-common/runtime-client/runtime-store"; + import { onMount } from "svelte"; import type { PageData } from "./$types"; - import { mapParseErrorsToLines } from "@rilldata/web-common/features/metrics-views/errors"; const workspaces = new Map([ [ResourceKind.Source, SourceWorkspace], [ResourceKind.Model, ModelWorkspace], [ResourceKind.MetricsView, MetricsWorkspace], [ResourceKind.Explore, ExploreWorkspace], - [ResourceKind.Component, ComponentWorkspace], - [ResourceKind.Canvas, CanvasDashboardWorkspace], + [ResourceKind.Canvas, CanvasWorkspace], [null, null], [undefined, null], ]); diff --git a/web-local/src/routes/(viz)/canvas/[name]/+page.svelte b/web-local/src/routes/(viz)/canvas/[name]/+page.svelte new file mode 100644 index 00000000000..c02204b58ce --- /dev/null +++ b/web-local/src/routes/(viz)/canvas/[name]/+page.svelte @@ -0,0 +1,22 @@ +<script lang="ts"> + import CanvasDashboardEmbed from "@rilldata/web-common/features/canvas/CanvasDashboardEmbed.svelte"; + import CanvasThemeProvider from "@rilldata/web-common/features/canvas/CanvasThemeProvider.svelte"; + import StateManagersProvider from "@rilldata/web-common/features/canvas/state-managers/StateManagersProvider.svelte"; + import type { PageData } from "./$types"; + + export let data: PageData; + + let columns = 20; + let gap = 1; + $: canvasName = data.dashboardName; +</script> + +<StateManagersProvider {canvasName}> + <CanvasThemeProvider> + <CanvasDashboardEmbed + items={data.dashboard.spec?.items || []} + {columns} + {gap} + /> + </CanvasThemeProvider> +</StateManagersProvider> diff --git a/web-local/src/routes/(viz)/custom/[name]/+page.ts b/web-local/src/routes/(viz)/canvas/[name]/+page.ts similarity index 96% rename from web-local/src/routes/(viz)/custom/[name]/+page.ts rename to web-local/src/routes/(viz)/canvas/[name]/+page.ts index 58fc4407176..d88b2f7fa98 100644 --- a/web-local/src/routes/(viz)/custom/[name]/+page.ts +++ b/web-local/src/routes/(viz)/canvas/[name]/+page.ts @@ -44,9 +44,7 @@ export const load = async ({ params, depends }) => { return { dashboardName, - dashboard: { - ...dashboard.spec, - }, + dashboard, }; } catch (e) { console.error(e); diff --git a/web-local/src/routes/(viz)/custom/[name]/+page.svelte b/web-local/src/routes/(viz)/custom/[name]/+page.svelte deleted file mode 100644 index 4a4e85f1f6d..00000000000 --- a/web-local/src/routes/(viz)/custom/[name]/+page.svelte +++ /dev/null @@ -1,16 +0,0 @@ -<script lang="ts"> - import CanvasDashboardEmbed from "@rilldata/web-common/features/canvas/CanvasDashboardEmbed.svelte"; - import type { PageData } from "./$types"; - - export let data: PageData; - - $: ({ items = [], columns, gap, variables } = data.dashboard); -</script> - -<CanvasDashboardEmbed - canvasName={data.dashboardName} - {items} - {columns} - {gap} - {variables} -/>