@metabase/custom-viz 0.0.1-alpha.2 → 0.0.1-alpha.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -1,39 +1,54 @@
1
1
  #!/usr/bin/env node
2
- import { existsSync as e } from "node:fs";
3
- import { mkdir as t, writeFile as n } from "node:fs/promises";
4
- import { join as r } from "node:path";
5
- import { Command as i } from "commander";
2
+ import { existsSync as e, readFileSync as t } from "node:fs";
3
+ import { mkdir as n, writeFile as r } from "node:fs/promises";
4
+ import { dirname as i, join as a } from "node:path";
5
+ import { Command as o } from "commander";
6
+ import { fileURLToPath as s } from "node:url";
6
7
  //#region package.json
7
- var a = "0.0.1-alpha.2", o = "node_modules/\n.DS_Store\n# dist must be committed\n", s = "import type {\n CreateCustomVisualization,\n CustomStaticVisualizationProps,\n CustomVisualizationProps,\n} from \"@metabase/custom-viz\";\n\ntype Settings = {\n threshold?: number;\n};\n\nconst createVisualization: CreateCustomVisualization<Settings> = () => {\n return {\n id: \"__CUSTOM_VIZ_NAME__\",\n getName: () => \"__CUSTOM_VIZ_NAME__\",\n minSize: { width: 1, height: 1 },\n defaultSize: { width: 2, height: 2 },\n isSensible({ cols, rows }) {\n return cols.length === 1 && rows.length === 1 && typeof rows[0][0] === \"number\";\n },\n checkRenderable(series, settings) {\n if (series.length !== 1) {\n throw new Error(\"Only 1 series is supported\");\n }\n\n const [\n {\n data: { cols, rows },\n },\n ] = series;\n\n if (cols.length !== 1) {\n throw new Error(\"Query results should only have 1 column\");\n }\n\n if (rows.length !== 1) {\n throw new Error(\"Query results should only have 1 row\");\n }\n\n if (typeof rows[0][0] !== \"number\") {\n throw new Error(\"Result is not a number\");\n }\n\n if (typeof settings.threshold !== \"number\") {\n throw new Error(\"Threshold setting is not set\");\n }\n },\n settings: {\n threshold: {\n id: \"1\",\n title: \"Threshold\",\n widget: \"number\",\n getDefault() {\n return 0;\n },\n getProps() {\n return {\n options: {\n isInteger: false,\n isNonNegative: false,\n },\n placeholder: \"Set threshold\",\n };\n },\n },\n },\n VisualizationComponent,\n StaticVisualizationComponent,\n };\n};\n\nconst VisualizationComponent = (props: CustomVisualizationProps<Settings>) => {\n const { height, series, settings, width } = props;\n const { threshold } = settings;\n const value = series[0].data.rows[0][0];\n\n if (typeof value !== \"number\" || typeof threshold !== \"number\") {\n throw new Error(\"Value and threshold need to be numbers\");\n }\n\n const emoji = value >= threshold ? \"👍\" : \"👎\";\n\n return (\n <div\n style={{\n display: \"flex\",\n justifyContent: \"center\",\n alignItems: \"center\",\n width,\n height,\n fontSize: \"10rem\",\n }}\n >\n {emoji}\n </div>\n );\n};\n\nconst StaticVisualizationComponent = (\n props: CustomStaticVisualizationProps<Settings>,\n) => {\n const width = 540;\n const height = 360;\n const { series, settings } = props;\n const { threshold } = settings;\n const value = series[0].data.rows[0][0];\n\n if (typeof value !== \"number\" || typeof threshold !== \"number\") {\n throw new Error(\"Value and threshold need to be numbers\");\n }\n\n const emoji =\n value >= threshold ? (\n <img src=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKAAAACgCAYAAACLz2ctAAAA0mVYSWZJSSoACAAAAAoAAAEEAAEAAACgAAAAAQEEAAEAAACgAAAAAgEDAAMAAACGAAAAEgEDAAEAAAABAAAAGgEFAAEAAACMAAAAGwEFAAEAAACUAAAAKAEDAAEAAAACAAAAMQECAA8AAACcAAAAMgECABQAAACsAAAAaYcEAAEAAADAAAAAAAAAAAgACAAIACwBAAABAAAALAEAAAEAAABHSU1QIDMuMC4wLVJDMQAAMjAyNjowMzoxOCAxNjoyNzo1OQABAAGgAwABAAAAAQAAAAAAAAD8VR8dAAABhWlDQ1BJQ0MgcHJvZmlsZQAAeJx9kb9Lw0AcxV9bpSoVQTuIPyBDdbKLijjWKhShQqgVWnUwufQXNGlIUlwcBdeCgz8Wqw4uzro6uAqC4A8Q/wBxUnSREr+XFFrEeHDch3f3HnfvAH+9zFSzIwaommWkEnEhk10Vgq8IoB/dGMaoxEx9ThST8Bxf9/Dx9S7Ks7zP/Tl6lZzJAJ9AHGO6YRFvEM9sWjrnfeIwK0oK8TnxhEEXJH7kuuzyG+eCw36eGTbSqXniMLFQaGO5jVnRUImniSOKqlG+P+OywnmLs1qusuY9+QtDOW1lmes0R5DAIpYgQoCMKkoow0KUVo0UEynaj3v4hxy/SC6ZXCUwciygAhWS4wf/g9/dmvmpSTcpFAc6X2z7YwwI7gKNmm1/H9t24wQIPANXWstfqQOzn6TXWlrkCOjbBi6uW5q8B1zuAINPumRIjhSg6c/ngfcz+qYsMHAL9Ky5vTX3cfoApKmr5A1wcAiMFyh73ePdXe29/Xum2d8PeZVyqWZhNiAAAA16aVRYdFhNTDpjb20uYWRvYmUueG1wAAAAAAA8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9Ilc1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCI/Pgo8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJYTVAgQ29yZSA0LjQuMC1FeGl2MiI+CiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogIDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiCiAgICB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIKICAgIHhtbG5zOnN0RXZ0PSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VFdmVudCMiCiAgICB4bWxuczpHSU1QPSJodHRwOi8vd3d3LmdpbXAub3JnL3htcC8iCiAgICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgICB4bWxuczp0aWZmPSJodHRwOi8vbnMuYWRvYmUuY29tL3RpZmYvMS4wLyIKICAgIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIKICAgeG1wTU06RG9jdW1lbnRJRD0iZ2ltcDpkb2NpZDpnaW1wOjUyMGY3ZWIzLTNiNjktNDlkMy04NjZjLWIwOWI4YzQ4MzgwZSIKICAgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDozZDFlNjVmZS1kYWQ5LTQ4MjQtYmE5MS1hNGMyYzhmOWNjMmIiCiAgIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDo4YzU1Zjg3MC02NjE4LTQ1MjAtYTE2Yy0wZmVlYWJjODE4ZTIiCiAgIEdJTVA6QVBJPSIzLjAiCiAgIEdJTVA6UGxhdGZvcm09IkxpbnV4IgogICBHSU1QOlRpbWVTdGFtcD0iMTc3MzgyNjA4MDI4Mzg3NSIKICAgR0lNUDpWZXJzaW9uPSIzLjAuMC1SQzEiCiAgIGRjOkZvcm1hdD0iaW1hZ2UvcG5nIgogICB0aWZmOk9yaWVudGF0aW9uPSIxIgogICB4bXA6Q3JlYXRvclRvb2w9IkdJTVAiCiAgIHhtcDpNZXRhZGF0YURhdGU9IjIwMjY6MDM6MThUMTY6Mjc6NTkrMDc6MDAiCiAgIHhtcDpNb2RpZnlEYXRlPSIyMDI2OjAzOjE4VDE2OjI3OjU5KzA3OjAwIj4KICAgPHhtcE1NOkhpc3Rvcnk+CiAgICA8cmRmOlNlcT4KICAgICA8cmRmOmxpCiAgICAgIHN0RXZ0OmFjdGlvbj0ic2F2ZWQiCiAgICAgIHN0RXZ0OmNoYW5nZWQ9Ii8iCiAgICAgIHN0RXZ0Omluc3RhbmNlSUQ9InhtcC5paWQ6YTc4M2Q4MzktMTY2Yy00MTM2LWI3ZDgtMWJlNGU1ZTcxNjFjIgogICAgICBzdEV2dDpzb2Z0d2FyZUFnZW50PSJHSU1QIDMuMC4wLVJDMSAoTGludXgpIgogICAgICBzdEV2dDp3aGVuPSIyMDI2LTAzLTE4VDE2OjI4OjAwKzA3OjAwIi8+CiAgICA8L3JkZjpTZXE+CiAgIDwveG1wTU06SGlzdG9yeT4KICA8L3JkZjpEZXNjcmlwdGlvbj4KIDwvcmRmOlJERj4KPC94OnhtcG1ldGE+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAKPD94cGFja2V0IGVuZD0idyI/PlfBSK4AAAAGYktHRAAAAEgAkHfF9EMAAAAJcEhZcwAALiMAAC4jAXilP3YAAAAHdElNRQfqAxIJHAAvHRFSAAAAGXRFWHRDb21tZW50AENyZWF0ZWQgd2l0aCBHSU1QV4EOFwAACzdJREFUeNrtnXuQ1lUZxz/LLrHcZLnIgoYNN02oNGAyCUqUS2o6aRenZlKwEawxGa0ZJhswrZFwYsCKGqapyHEatYYIzUshTWqCFGCajFxWwEkEgWW5yHXh7Y/z21iWRZ7zvuf3vr/L9zNzZvjj8J7fec53z/08TxWiFGqBScBEYCQwCKgDCkAjsAFYC7wAPA/slMlECHoCDwC7IrFZ0olIjPcDQ2RCUSw3A7s9hNdeOg48BlwgcwornYDflii8tmk/MEWmFWejM/BcYPG1TrNlYnEmOgBLYhRfS5olU4v2uKcM4mtZpFwtc4vWXAwcKZMAC8A2oFueDFwtjb0viyIRlovuwHu4fUORcy6JhsVCmdO2PHUMHaSzMzIF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\" />\n ) : (\n <img src=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKAAAACgCAYAAACLz2ctAAAA0mVYSWZJSSoACAAAAAoAAAEEAAEAAACgAAAAAQEEAAEAAACgAAAAAgEDAAMAAACGAAAAEgEDAAEAAAABAAAAGgEFAAEAAACMAAAAGwEFAAEAAACUAAAAKAEDAAEAAAACAAAAMQECAA8AAACcAAAAMgECABQAAACsAAAAaYcEAAEAAADAAAAAAAAAAAgACAAIACwBAAABAAAALAEAAAEAAABHSU1QIDMuMC4wLVJDMQAAMjAyNjowMzoxOCAxNjoyODowOAABAAGgAwABAAAAAQAAAAAAAABiEXj2AAABhWlDQ1BJQ0MgcHJvZmlsZQAAeJx9kb9Lw0AcxV9bpSoVQTuIPyBDdbKLijjWKhShQqgVWnUwufQXNGlIUlwcBdeCgz8Wqw4uzro6uAqC4A8Q/wBxUnSREr+XFFrEeHDch3f3HnfvAH+9zFSzIwaommWkEnEhk10Vgq8IoB/dGMaoxEx9ThST8Bxf9/Dx9S7Ks7zP/Tl6lZzJAJ9AHGO6YRFvEM9sWjrnfeIwK0oK8TnxhEEXJH7kuuzyG+eCw36eGTbSqXniMLFQaGO5jVnRUImniSOKqlG+P+OywnmLs1qusuY9+QtDOW1lmes0R5DAIpYgQoCMKkoow0KUVo0UEynaj3v4hxy/SC6ZXCUwciygAhWS4wf/g9/dmvmpSTcpFAc6X2z7YwwI7gKNmm1/H9t24wQIPANXWstfqQOzn6TXWlrkCOjbBi6uW5q8B1zuAINPumRIjhSg6c/ngfcz+qYsMHAL9Ky5vTX3cfoApKmr5A1wcAiMFyh73ePdXe29/Xum2d8PeZVyqWZhNiAAAA16aVRYdFhNTDpjb20uYWRvYmUueG1wAAAAAAA8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9Ilc1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCI/Pgo8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJYTVAgQ29yZSA0LjQuMC1FeGl2MiI+CiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogIDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiCiAgICB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIKICAgIHhtbG5zOnN0RXZ0PSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VFdmVudCMiCiAgICB4bWxuczpHSU1QPSJodHRwOi8vd3d3LmdpbXAub3JnL3htcC8iCiAgICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgICB4bWxuczp0aWZmPSJodHRwOi8vbnMuYWRvYmUuY29tL3RpZmYvMS4wLyIKICAgIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIKICAgeG1wTU06RG9jdW1lbnRJRD0iZ2ltcDpkb2NpZDpnaW1wOmI5OGQ1OTk1LTRkZjktNDdkMS1hMGRmLTJjYWJhOTU2NjFjZSIKICAgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo4MzNlNzUzYS0zZDhmLTRhNTAtODA1NC0wNmQ0N2JhNzQ1NWMiCiAgIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDoyYzJiM2I3Zi04OTU0LTQyZTgtOWNkOS1lOTc3Y2ExZmMwMGYiCiAgIEdJTVA6QVBJPSIzLjAiCiAgIEdJTVA6UGxhdGZvcm09IkxpbnV4IgogICBHSU1QOlRpbWVTdGFtcD0iMTc3MzgyNjA4OTM4NzIzMiIKICAgR0lNUDpWZXJzaW9uPSIzLjAuMC1SQzEiCiAgIGRjOkZvcm1hdD0iaW1hZ2UvcG5nIgogICB0aWZmOk9yaWVudGF0aW9uPSIxIgogICB4bXA6Q3JlYXRvclRvb2w9IkdJTVAiCiAgIHhtcDpNZXRhZGF0YURhdGU9IjIwMjY6MDM6MThUMTY6Mjg6MDgrMDc6MDAiCiAgIHhtcDpNb2RpZnlEYXRlPSIyMDI2OjAzOjE4VDE2OjI4OjA4KzA3OjAwIj4KICAgPHhtcE1NOkhpc3Rvcnk+CiAgICA8cmRmOlNlcT4KICAgICA8cmRmOmxpCiAgICAgIHN0RXZ0OmFjdGlvbj0ic2F2ZWQiCiAgICAgIHN0RXZ0OmNoYW5nZWQ9Ii8iCiAgICAgIHN0RXZ0Omluc3RhbmNlSUQ9InhtcC5paWQ6NDM0NWQ1MjktYzlmYi00NjQ5LTlmZDctYmVkMDNiYjMzNjUzIgogICAgICBzdEV2dDpzb2Z0d2FyZUFnZW50PSJHSU1QIDMuMC4wLVJDMSAoTGludXgpIgogICAgICBzdEV2dDp3aGVuPSIyMDI2LTAzLTE4VDE2OjI4OjA5KzA3OjAwIi8+CiAgICA8L3JkZjpTZXE+CiAgIDwveG1wTU06SGlzdG9yeT4KICA8L3JkZjpEZXNjcmlwdGlvbj4KIDwvcmRmOlJERj4KPC94OnhtcG1ldGE+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAKPD94cGFja2V0IGVuZD0idyI/PkUgIFwAAAAGYktHRAAAAEgAkHfF9EMAAAAJcEhZcwAALiMAAC4jAXilP3YAAAAHdElNRQfqAxIJHAlWwan2AAAAGXRFWHRDb21tZW50AENyZWF0ZWQgd2l0aCBHSU1QV4EOFwAACwtJREFUeNrtnXuwVlUZh5+DAnI9ykWBJC9cdHAgRSUh1Kwhi6KG0TTorpjTDScNRm1Kx/5wqhHTAjRMssbRaaBxiDIgyUKHSASV0FIUUFFB4CBXhQNff6x1GOZ08Lzr+9be3778npk1wMzi23ut97fXfb1vA6ItOgBDgHP9nwOBk/2fXYDjfb4TMvbe7wI7gCZgC7AaeBpYAbwks2abYcB0YCmwE6gULD0L3AR8UKbODgOBHwHrCii4o6X9wL0SYn0ZAywAmkskvNbpPeAHwLGSQ3qMAh4rsejaSsuB0ySNZOnvu52DElyb6S1gpGQSn+P8wHuXRNZu2gmMlWTiMaFkk4sYaatfdhI1MBR4VGKqOv0X6CEZhdML+Jmf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\" />\n );\n\n return (\n <div\n style={{\n display: \"flex\",\n justifyContent: \"center\",\n alignItems: \"center\",\n width,\n height,\n fontSize: \"10rem\",\n }}\n >\n {emoji}\n </div>\n );\n};\n\nexport default createVisualization;\n", c = "{\n \"name\": \"__CUSTOM_VIZ_NAME__\",\n \"version\": \"0.0.1\",\n \"private\": true,\n \"type\": \"module\",\n \"scripts\": {\n \"build\": \"vite build\",\n \"dev\": \"vite build --watch & vite preview\",\n \"type-check\": \"tsc --noEmit\"\n },\n \"devDependencies\": {\n \"@metabase/custom-viz\": \"__CUSTOM_VIZ_VERSION__\",\n \"@types/react\": \"^19.2.14\",\n \"react\": \"^19.1.0\",\n \"typescript\": \"^5.9.3\",\n \"vite\": \"^8.0.0\"\n }\n}\n", l = "{\n \"compilerOptions\": {\n \"target\": \"ES2020\",\n \"module\": \"ESNext\",\n \"moduleResolution\": \"bundler\",\n \"jsx\": \"react-jsx\",\n \"strict\": true,\n \"esModuleInterop\": true,\n \"skipLibCheck\": true,\n \"outDir\": \"dist\",\n \"declaration\": true\n },\n \"include\": [\"src\"]\n}\n", u = "import { resolve } from \"path\";\nimport { createServer } from \"http\";\nimport { defineConfig } from \"vite\";\n\n/**\n * Vite plugin that replaces `react` and `react/jsx-runtime` imports with\n * virtual modules that read from Metabase's `window.__METABASE_VIZ_API__`.\n *\n * This is necessary because the ES module output format cannot use\n * `output.globals`, and bare `import 'react'` would fail in the browser.\n */\nfunction metabaseVizExternals() {\n const VIRTUAL_REACT = \"\\0virtual:react\";\n const VIRTUAL_JSX_RUNTIME = \"\\0virtual:react/jsx-runtime\";\n\n return {\n name: \"metabase-viz-externals\",\n enforce: \"pre\" as const,\n\n resolveId(source) {\n if (source === \"react\") {\n return VIRTUAL_REACT;\n }\n if (source === \"react/jsx-runtime\") {\n return VIRTUAL_JSX_RUNTIME;\n }\n return null;\n },\n\n load(id) {\n if (id === VIRTUAL_REACT) {\n return [\n \"const React = window.__METABASE_VIZ_API__.React;\",\n \"export default React;\",\n \"export const { useState, useEffect, useRef, useCallback, useMemo, useReducer, useContext, createElement, Fragment } = React;\",\n ].join(\"\\n\");\n }\n if (id === VIRTUAL_JSX_RUNTIME) {\n return [\n \"const jsxRuntime = window.__METABASE_VIZ_API__.jsxRuntime;\",\n \"export const { jsx, jsxs, Fragment } = jsxRuntime;\",\n ].join(\"\\n\");\n }\n return null;\n },\n };\n}\n\nconst NOTIFY_PORT = 5175;\n\n/**\n * Vite plugin that starts a tiny SSE server and sends a \"reload\" event\n * to all connected clients after each rebuild completes.\n * Metabase's frontend connects to this to live-reload the custom viz.\n */\nfunction metabaseNotifyReload() {\n const clients = new Set<import(\"http\").ServerResponse>();\n let server: ReturnType<typeof createServer> | null = null;\n\n return {\n name: \"metabase-notify-reload\",\n\n buildStart() {\n if (server) {\n return;\n }\n server = createServer((req, res) => {\n res.writeHead(200, {\n \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n Connection: \"keep-alive\",\n \"Access-Control-Allow-Origin\": \"*\",\n });\n clients.add(res);\n req.on(\"close\", () => clients.delete(res));\n });\n server.listen(NOTIFY_PORT, () => {\n console.log(\n `[metabase-notify] SSE server listening on http://localhost:${NOTIFY_PORT}`,\n );\n });\n },\n\n closeBundle() {\n for (const client of clients) {\n client.write(\"data: reload\\n\\n\");\n }\n console.log(\n `[metabase-notify] Build complete, notified ${clients.size} client(s)`,\n );\n },\n };\n}\n\nconst isWatch = process.argv.includes(\"--watch\");\n\nexport default defineConfig({\n plugins: [metabaseVizExternals(), ...(isWatch ? [metabaseNotifyReload()] : [])],\n build: {\n outDir: \"dist\",\n lib: {\n entry: resolve(__dirname, \"src/index.tsx\"),\n formats: [\"iife\"],\n fileName: () => \"index.js\",\n name: \"__customVizPlugin__\",\n },\n },\n preview: {\n port: 5174,\n host: true,\n cors: true,\n },\n});\n", d = "__CUSTOM_VIZ_NAME__", f = "__CUSTOM_VIZ_VERSION__";
8
- function p(e, t) {
9
- return e.split(d).join(t);
8
+ var c = "0.0.1-alpha.3", l = "node_modules/\n.DS_Store\n# dist must be committed\n", u = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\" ry=\"2\"/>\n <line x1=\"3\" y1=\"9\" x2=\"21\" y2=\"9\"/>\n <line x1=\"9\" y1=\"21\" x2=\"9\" y2=\"9\"/>\n</svg>\n", d = "import type {\n CreateCustomVisualization,\n CustomStaticVisualizationProps,\n CustomVisualizationProps,\n} from \"@metabase/custom-viz\";\n\ntype Settings = {\n threshold?: number;\n};\n\nconst createVisualization: CreateCustomVisualization<Settings> = ({\n getAssetUrl,\n}) => {\n return {\n id: \"__CUSTOM_VIZ_NAME__\",\n getName: () => \"__CUSTOM_VIZ_NAME__\",\n minSize: { width: 1, height: 1 },\n defaultSize: { width: 2, height: 2 },\n isSensible({ cols, rows }) {\n return cols.length === 1 && rows.length === 1 && typeof rows[0][0] === \"number\";\n },\n checkRenderable(series, settings) {\n if (series.length !== 1) {\n throw new Error(\"Only 1 series is supported\");\n }\n\n const [\n {\n data: { cols, rows },\n },\n ] = series;\n\n if (cols.length !== 1) {\n throw new Error(\"Query results should only have 1 column\");\n }\n\n if (rows.length !== 1) {\n throw new Error(\"Query results should only have 1 row\");\n }\n\n if (typeof rows[0][0] !== \"number\") {\n throw new Error(\"Result is not a number\");\n }\n\n if (typeof settings.threshold !== \"number\") {\n throw new Error(\"Threshold setting is not set\");\n }\n },\n settings: {\n threshold: {\n id: \"1\",\n title: \"Threshold\",\n widget: \"number\",\n getDefault() {\n return 0;\n },\n getProps() {\n return {\n options: {\n isInteger: false,\n isNonNegative: false,\n },\n placeholder: \"Set threshold\",\n };\n },\n },\n },\n VisualizationComponent: makeVisualizationComponent(getAssetUrl),\n StaticVisualizationComponent: makeStaticVisualizationComponent(getAssetUrl),\n };\n};\n\nconst makeVisualizationComponent = (getAssetUrl: (path: string) => string) => (props: CustomVisualizationProps<Settings>) => {\n const { height, series, settings, width } = props;\n const { threshold } = settings;\n const value = series[0].data.rows[0][0];\n\n if (typeof value !== \"number\" || typeof threshold !== \"number\") {\n throw new Error(\"Value and threshold need to be numbers\");\n }\n\n const emoji = value >= threshold ? \"👍\" : \"👎\";\n\n return (\n <div\n style={{\n display: \"flex\",\n justifyContent: \"center\",\n alignItems: \"center\",\n width,\n height,\n fontSize: \"10rem\",\n }}\n >\n {emoji}\n </div>\n );\n};\n\nconst makeStaticVisualizationComponent = (getAssetUrl: (path: string) => string) => (\n props: CustomStaticVisualizationProps<Settings>,\n) => {\n const width = 540;\n const height = 360;\n const { series, settings } = props;\n const { threshold } = settings;\n const value = series[0].data.rows[0][0];\n\n if (typeof value !== \"number\" || typeof threshold !== \"number\") {\n throw new Error(\"Value and threshold need to be numbers\");\n }\n\n const emoji =\n value >= threshold ? (\n <img src={getAssetUrl(\"thumbs-up.png\")} />\n ) : (\n <img src={getAssetUrl(\"thumbs-down.png\")} />\n );\n\n return (\n <div\n style={{\n display: \"flex\",\n justifyContent: \"center\",\n alignItems: \"center\",\n width,\n height,\n fontSize: \"10rem\",\n }}\n >\n {emoji}\n </div>\n );\n};\n\nexport default createVisualization;\n", f = "{\n \"name\": \"__CUSTOM_VIZ_NAME__\",\n \"icon\": \"icon.svg\",\n \"assets\": [\"icon.svg\", \"thumbs-up.png\", \"thumbs-down.png\"],\n \"metabase\": {\n \"version\": \">=59\"\n }\n}\n", p = "{\n \"name\": \"__CUSTOM_VIZ_NAME__\",\n \"version\": \"0.0.1\",\n \"private\": true,\n \"type\": \"module\",\n \"scripts\": {\n \"build\": \"vite build\",\n \"dev\": \"vite build --watch & vite preview\",\n \"type-check\": \"tsc --noEmit\"\n },\n \"devDependencies\": {\n \"@metabase/custom-viz\": \"__CUSTOM_VIZ_VERSION__\",\n \"@types/react\": \"^19.2.14\",\n \"react\": \"^19.1.0\",\n \"typescript\": \"^5.9.3\",\n \"vite\": \"^8.0.0\"\n }\n}\n", m = "{\n \"compilerOptions\": {\n \"target\": \"ES2020\",\n \"module\": \"ESNext\",\n \"moduleResolution\": \"bundler\",\n \"jsx\": \"react-jsx\",\n \"strict\": true,\n \"esModuleInterop\": true,\n \"skipLibCheck\": true,\n \"outDir\": \"dist\",\n \"declaration\": true\n },\n \"include\": [\"src\"]\n}\n", h = "import { resolve } from \"path\";\nimport { createServer } from \"http\";\nimport { watch, cpSync } from \"fs\";\nimport { defineConfig } from \"vite\";\n\n/**\n * Vite plugin that replaces `react` and `react/jsx-runtime` imports with\n * virtual modules that read from Metabase's `window.__METABASE_VIZ_API__`.\n *\n * This is necessary because the ES module output format cannot use\n * `output.globals`, and bare `import 'react'` would fail in the browser.\n */\nfunction metabaseVizExternals() {\n const VIRTUAL_REACT = \"\\0virtual:react\";\n const VIRTUAL_JSX_RUNTIME = \"\\0virtual:react/jsx-runtime\";\n const VIRTUAL_CUSTOM_VIZ = \"\\0virtual:@metabase/custom-viz\";\n\n return {\n name: \"metabase-viz-externals\",\n enforce: \"pre\" as const,\n\n resolveId(source) {\n if (source === \"react\") {\n return VIRTUAL_REACT;\n }\n if (source === \"react/jsx-runtime\") {\n return VIRTUAL_JSX_RUNTIME;\n }\n if (source === \"@metabase/custom-viz\") {\n return VIRTUAL_CUSTOM_VIZ;\n }\n return null;\n },\n\n load(id) {\n if (id === VIRTUAL_REACT) {\n return [\n \"const React = window.__METABASE_VIZ_API__.React;\",\n \"export default React;\",\n \"export const { useState, useEffect, useRef, useCallback, useMemo, useReducer, useContext, createElement, Fragment } = React;\",\n ].join(\"\\n\");\n }\n if (id === VIRTUAL_JSX_RUNTIME) {\n return [\n \"const jsxRuntime = window.__METABASE_VIZ_API__.jsxRuntime;\",\n \"export const { jsx, jsxs, Fragment } = jsxRuntime;\",\n ].join(\"\\n\");\n }\n if (id === VIRTUAL_CUSTOM_VIZ) {\n return [\n \"const ct = window.__METABASE_VIZ_API__.columnTypes;\",\n \"export const { isDate, isNumeric, isInteger, isBoolean, isString, isStringLike, isSummable, isNumericBaseType, isDateWithoutTime, isNumber, isFloat, isTime, isFK, isPK, isEntityName, isTitle, isProduct, isSource, isAddress, isScore, isQuantity, isCategory, isAny, isState, isCountry, isCoordinate, isLatitude, isLongitude, isCurrency, isPercentage, isID, isURL, isEmail, isAvatarURL, isImageURL, hasLatitudeAndLongitudeColumns } = ct;\",\n \"export const formatValue = window.__METABASE_VIZ_API__.formatValue;\",\n ].join(\"\\n\");\n }\n return null;\n },\n };\n}\n\nconst NOTIFY_PORT = 5175;\n\n/**\n * Vite plugin that starts a tiny SSE server and sends a \"reload\" event\n * to all connected clients after each rebuild completes.\n * Metabase's frontend connects to this to live-reload the custom viz.\n */\nfunction metabaseNotifyReload() {\n const clients = new Set<import(\"http\").ServerResponse>();\n let server: ReturnType<typeof createServer> | null = null;\n\n return {\n name: \"metabase-notify-reload\",\n\n buildStart() {\n if (server) {\n return;\n }\n server = createServer((req, res) => {\n res.writeHead(200, {\n \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n Connection: \"keep-alive\",\n \"Access-Control-Allow-Origin\": \"*\",\n });\n clients.add(res);\n req.on(\"close\", () => clients.delete(res));\n });\n server.listen(NOTIFY_PORT, () => {\n console.log(\n `[metabase-notify] SSE server listening on http://localhost:${NOTIFY_PORT}`,\n );\n });\n\n // Watch public/assets/ for changes — copy to dist/assets/ and notify\n const assetsDir = resolve(__dirname, \"public/assets\");\n watch(assetsDir, { recursive: true }, (_event, filename) => {\n if (!filename) {\n return;\n }\n cpSync(resolve(assetsDir, filename), resolve(__dirname, \"dist/assets\", filename));\n for (const client of clients) {\n client.write(\"data: reload\\n\\n\");\n }\n console.log(`[metabase-notify] Asset changed: ${filename}, notified ${clients.size} client(s)`);\n });\n },\n\n closeBundle() {\n for (const client of clients) {\n client.write(\"data: reload\\n\\n\");\n }\n console.log(\n `[metabase-notify] Build complete, notified ${clients.size} client(s)`,\n );\n },\n };\n}\n\nconst isWatch = process.argv.includes(\"--watch\");\n\nexport default defineConfig({\n plugins: [metabaseVizExternals(), ...(isWatch ? [metabaseNotifyReload()] : [])],\n publicDir: \"public\",\n build: {\n outDir: \"dist\",\n lib: {\n entry: resolve(__dirname, \"src/index.tsx\"),\n formats: [\"iife\"],\n fileName: () => \"index.js\",\n name: \"__customVizPlugin__\",\n },\n },\n preview: {\n port: 5174,\n host: true,\n cors: true,\n },\n});\n", g = "__CUSTOM_VIZ_NAME__", _ = "__CUSTOM_VIZ_VERSION__";
9
+ function v(e, t) {
10
+ return e.split(g).join(t);
10
11
  }
11
- function m(e) {
12
- return p(c, e).split(f).join(a);
12
+ function y(e) {
13
+ return v(p, e).split(_).join(c);
13
14
  }
14
- function h() {
15
- return u;
15
+ function b() {
16
+ return h;
16
17
  }
17
- function g() {
18
- return l;
18
+ function x() {
19
+ return m;
19
20
  }
20
- function _(e) {
21
- return p(s, e);
21
+ function S(e) {
22
+ return v(d, e);
22
23
  }
23
- function v() {
24
- return o;
24
+ function C(e) {
25
+ return v(f, e);
26
+ }
27
+ function w() {
28
+ return u;
29
+ }
30
+ var T = a(i(s(import.meta.url)), "templates");
31
+ function E(e) {
32
+ return t(a(T, e));
33
+ }
34
+ function D() {
35
+ return l;
25
36
  }
26
37
  //#endregion
27
38
  //#region src/cli.ts
28
- var y = new i();
29
- y.name("metabase-custom-viz").description("CLI for creating custom visualizations for Metabase").version("0.0.1"), y.command("init").description("Scaffold a new custom visualization").argument("<name>", "Name of the custom visualization").action(async (i) => {
30
- let a = i.trim().replace(/\s+/g, "-").toLowerCase();
31
- (!a || !/^[a-z0-9@][a-z0-9._\-/]*$/.test(a)) && (console.error(`Error: "${i}" is not a valid project name. Use letters, numbers, hyphens, and dots.`), process.exit(1)), e(a) && (console.error(`Error: Directory "${a}" already exists.`), process.exit(1)), console.log(`Scaffolding custom visualization: ${a}\n`), await t(r(a, "src"), { recursive: !0 }), await Promise.all([
32
- n(r(a, "package.json"), m(a)),
33
- n(r(a, "vite.config.ts"), h()),
34
- n(r(a, "tsconfig.json"), g()),
35
- n(r(a, "src", "index.tsx"), _(a)),
36
- n(r(a, ".gitignore"), v())
37
- ]), console.log("Created files:"), console.log(` ${a}/package.json`), console.log(` ${a}/vite.config.ts`), console.log(` ${a}/tsconfig.json`), console.log(` ${a}/src/index.tsx`), console.log(` ${a}/.gitignore`), console.log(), console.log("Next steps:"), console.log(` cd ${a}`), console.log(" npm install"), console.log(" npm run dev # Watch mode"), console.log(" npm run build # Production build");
38
- }), y.parse();
39
+ var O = new o();
40
+ O.name("metabase-custom-viz").description("CLI for creating custom visualizations for Metabase").version("0.0.1"), O.command("init").description("Scaffold a new custom visualization").argument("<name>", "Name of the custom visualization").action(async (t) => {
41
+ let i = t.trim().replace(/\s+/g, "-").toLowerCase();
42
+ (!i || !/^[a-z0-9@][a-z0-9._\-/]*$/.test(i)) && (console.error(`Error: "${t}" is not a valid project name. Use letters, numbers, hyphens, and dots.`), process.exit(1)), e(i) && (console.error(`Error: Directory "${i}" already exists.`), process.exit(1)), console.log(`Scaffolding custom visualization: ${i}\n`), await Promise.all([n(a(i, "src"), { recursive: !0 }), n(a(i, "public", "assets"), { recursive: !0 })]), await Promise.all([
43
+ r(a(i, "package.json"), y(i)),
44
+ r(a(i, "vite.config.ts"), b()),
45
+ r(a(i, "tsconfig.json"), x()),
46
+ r(a(i, "src", "index.tsx"), S(i)),
47
+ r(a(i, "metabase-plugin.json"), C(i)),
48
+ r(a(i, "public", "assets", "icon.svg"), w()),
49
+ r(a(i, "public", "assets", "thumbs-up.png"), E("thumbs-up.png")),
50
+ r(a(i, "public", "assets", "thumbs-down.png"), E("thumbs-down.png")),
51
+ r(a(i, ".gitignore"), D())
52
+ ]), console.log("Created files:"), console.log(` ${i}/package.json`), console.log(` ${i}/vite.config.ts`), console.log(` ${i}/tsconfig.json`), console.log(` ${i}/src/index.tsx`), console.log(` ${i}/metabase-plugin.json`), console.log(` ${i}/public/assets/icon.svg`), console.log(` ${i}/public/assets/thumbs-up.png`), console.log(` ${i}/public/assets/thumbs-down.png`), console.log(` ${i}/.gitignore`), console.log(), console.log("Next steps:"), console.log(` cd ${i}`), console.log(" npm install"), console.log(" npm run dev # Watch mode"), console.log(" npm run build # Production build");
53
+ }), O.parse();
39
54
  //#endregion
@@ -0,0 +1,40 @@
1
+ import { ColumnPredicate, ColumnTypes } from './types/column-types';
2
+ import { Column } from './types/data';
3
+ export declare const isDate: ColumnPredicate;
4
+ export declare const isNumeric: ColumnPredicate;
5
+ export declare const isInteger: ColumnPredicate;
6
+ export declare const isBoolean: ColumnPredicate;
7
+ export declare const isString: ColumnPredicate;
8
+ export declare const isStringLike: ColumnPredicate;
9
+ export declare const isSummable: ColumnPredicate;
10
+ export declare const isNumericBaseType: ColumnPredicate;
11
+ export declare const isDateWithoutTime: ColumnPredicate;
12
+ export declare const isNumber: ColumnPredicate;
13
+ export declare const isFloat: ColumnPredicate;
14
+ export declare const isTime: ColumnPredicate;
15
+ export declare const isFK: ColumnPredicate;
16
+ export declare const isPK: ColumnPredicate;
17
+ export declare const isEntityName: ColumnPredicate;
18
+ export declare const isTitle: ColumnPredicate;
19
+ export declare const isProduct: ColumnPredicate;
20
+ export declare const isSource: ColumnPredicate;
21
+ export declare const isAddress: ColumnPredicate;
22
+ export declare const isScore: ColumnPredicate;
23
+ export declare const isQuantity: ColumnPredicate;
24
+ export declare const isCategory: ColumnPredicate;
25
+ export declare const isAny: ColumnPredicate;
26
+ export declare const isState: ColumnPredicate;
27
+ export declare const isCountry: ColumnPredicate;
28
+ export declare const isCoordinate: ColumnPredicate;
29
+ export declare const isLatitude: ColumnPredicate;
30
+ export declare const isLongitude: ColumnPredicate;
31
+ export declare const isCurrency: ColumnPredicate;
32
+ export declare const isPercentage: ColumnPredicate;
33
+ export declare const isID: ColumnPredicate;
34
+ export declare const isURL: ColumnPredicate;
35
+ export declare const isEmail: ColumnPredicate;
36
+ export declare const isAvatarURL: ColumnPredicate;
37
+ export declare const isImageURL: ColumnPredicate;
38
+ export declare const hasLatitudeAndLongitudeColumns: (cols: Column[]) => boolean;
39
+ export type { ColumnPredicate, ColumnTypes };
40
+ //# sourceMappingURL=column-types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"column-types.d.ts","sourceRoot":"","sources":["../src/column-types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACzE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAI3C,eAAO,MAAM,MAAM,iBAAO,CAAC;AAC3B,eAAO,MAAM,SAAS,iBAAO,CAAC;AAC9B,eAAO,MAAM,SAAS,iBAAO,CAAC;AAC9B,eAAO,MAAM,SAAS,iBAAO,CAAC;AAC9B,eAAO,MAAM,QAAQ,iBAAO,CAAC;AAC7B,eAAO,MAAM,YAAY,iBAAO,CAAC;AACjC,eAAO,MAAM,UAAU,iBAAO,CAAC;AAC/B,eAAO,MAAM,iBAAiB,iBAAO,CAAC;AACtC,eAAO,MAAM,iBAAiB,iBAAO,CAAC;AACtC,eAAO,MAAM,QAAQ,iBAAO,CAAC;AAC7B,eAAO,MAAM,OAAO,iBAAO,CAAC;AAC5B,eAAO,MAAM,MAAM,iBAAO,CAAC;AAC3B,eAAO,MAAM,IAAI,iBAAO,CAAC;AACzB,eAAO,MAAM,IAAI,iBAAO,CAAC;AACzB,eAAO,MAAM,YAAY,iBAAO,CAAC;AACjC,eAAO,MAAM,OAAO,iBAAO,CAAC;AAC5B,eAAO,MAAM,SAAS,iBAAO,CAAC;AAC9B,eAAO,MAAM,QAAQ,iBAAO,CAAC;AAC7B,eAAO,MAAM,SAAS,iBAAO,CAAC;AAC9B,eAAO,MAAM,OAAO,iBAAO,CAAC;AAC5B,eAAO,MAAM,UAAU,iBAAO,CAAC;AAC/B,eAAO,MAAM,UAAU,iBAAO,CAAC;AAC/B,eAAO,MAAM,KAAK,iBAAO,CAAC;AAC1B,eAAO,MAAM,OAAO,iBAAO,CAAC;AAC5B,eAAO,MAAM,SAAS,iBAAO,CAAC;AAC9B,eAAO,MAAM,YAAY,iBAAO,CAAC;AACjC,eAAO,MAAM,UAAU,iBAAO,CAAC;AAC/B,eAAO,MAAM,WAAW,iBAAO,CAAC;AAChC,eAAO,MAAM,UAAU,iBAAO,CAAC;AAC/B,eAAO,MAAM,YAAY,iBAAO,CAAC;AACjC,eAAO,MAAM,IAAI,iBAAO,CAAC;AACzB,eAAO,MAAM,KAAK,iBAAO,CAAC;AAC1B,eAAO,MAAM,OAAO,iBAAO,CAAC;AAC5B,eAAO,MAAM,WAAW,iBAAO,CAAC;AAChC,eAAO,MAAM,UAAU,iBAAO,CAAC;AAC/B,eAAO,MAAM,8BAA8B,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,OACpD,CAAC;AAEd,YAAY,EAAE,eAAe,EAAE,WAAW,EAAE,CAAC"}
@@ -0,0 +1,4 @@
1
+ import { FormatValue, FormatValueOptions } from './types/format';
2
+ export declare const formatValue: FormatValue;
3
+ export type { FormatValue, FormatValueOptions };
4
+ //# sourceMappingURL=format.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../src/format.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAEtE,eAAO,MAAM,WAAW,EAAE,WAAsB,CAAC;AAEjD,YAAY,EAAE,WAAW,EAAE,kBAAkB,EAAE,CAAC"}
package/dist/index.d.ts CHANGED
@@ -1,2 +1,4 @@
1
1
  export * from './types';
2
+ export * from './column-types';
3
+ export * from './format';
2
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,UAAU,CAAC"}
package/dist/index.js CHANGED
@@ -16,6 +16,6 @@ var e = [
16
16
  "week-of-year",
17
17
  "month-of-year",
18
18
  "quarter-of-year"
19
- ], n = [...e, ...t];
19
+ ], n = [...e, ...t], r = () => !1, i = r, a = r, o = r, s = r, c = r, l = r, u = r, d = r, f = r, p = r, m = r, h = r, g = r, _ = r, v = r, y = r, b = r, x = r, S = r, C = r, w = r, T = r, E = r, D = r, O = r, k = r, A = r, j = r, M = r, N = r, P = r, F = r, I = r, L = r, R = r, z = () => !1, B = () => "";
20
20
  //#endregion
21
- export { e as dateTimeAbsoluteUnits, t as dateTimeRelativeUnits, n as dateTimeUnits };
21
+ export { e as dateTimeAbsoluteUnits, t as dateTimeRelativeUnits, n as dateTimeUnits, B as formatValue, z as hasLatitudeAndLongitudeColumns, S as isAddress, E as isAny, L as isAvatarURL, s as isBoolean, T as isCategory, k as isCoordinate, O as isCountry, M as isCurrency, i as isDate, f as isDateWithoutTime, I as isEmail, v as isEntityName, g as isFK, m as isFloat, P as isID, R as isImageURL, o as isInteger, A as isLatitude, j as isLongitude, p as isNumber, a as isNumeric, d as isNumericBaseType, _ as isPK, N as isPercentage, b as isProduct, w as isQuantity, C as isScore, x as isSource, D as isState, c as isString, l as isStringLike, u as isSummable, h as isTime, y as isTitle, F as isURL };
@@ -0,0 +1,5 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
2
+ <rect x="3" y="3" width="18" height="18" rx="2" ry="2"/>
3
+ <line x1="3" y1="9" x2="21" y2="9"/>
4
+ <line x1="9" y1="21" x2="9" y2="9"/>
5
+ </svg>
@@ -0,0 +1,136 @@
1
+ import type {
2
+ CreateCustomVisualization,
3
+ CustomStaticVisualizationProps,
4
+ CustomVisualizationProps,
5
+ } from "@metabase/custom-viz";
6
+
7
+ type Settings = {
8
+ threshold?: number;
9
+ };
10
+
11
+ const createVisualization: CreateCustomVisualization<Settings> = ({
12
+ getAssetUrl,
13
+ }) => {
14
+ return {
15
+ id: "__CUSTOM_VIZ_NAME__",
16
+ getName: () => "__CUSTOM_VIZ_NAME__",
17
+ minSize: { width: 1, height: 1 },
18
+ defaultSize: { width: 2, height: 2 },
19
+ isSensible({ cols, rows }) {
20
+ return cols.length === 1 && rows.length === 1 && typeof rows[0][0] === "number";
21
+ },
22
+ checkRenderable(series, settings) {
23
+ if (series.length !== 1) {
24
+ throw new Error("Only 1 series is supported");
25
+ }
26
+
27
+ const [
28
+ {
29
+ data: { cols, rows },
30
+ },
31
+ ] = series;
32
+
33
+ if (cols.length !== 1) {
34
+ throw new Error("Query results should only have 1 column");
35
+ }
36
+
37
+ if (rows.length !== 1) {
38
+ throw new Error("Query results should only have 1 row");
39
+ }
40
+
41
+ if (typeof rows[0][0] !== "number") {
42
+ throw new Error("Result is not a number");
43
+ }
44
+
45
+ if (typeof settings.threshold !== "number") {
46
+ throw new Error("Threshold setting is not set");
47
+ }
48
+ },
49
+ settings: {
50
+ threshold: {
51
+ id: "1",
52
+ title: "Threshold",
53
+ widget: "number",
54
+ getDefault() {
55
+ return 0;
56
+ },
57
+ getProps() {
58
+ return {
59
+ options: {
60
+ isInteger: false,
61
+ isNonNegative: false,
62
+ },
63
+ placeholder: "Set threshold",
64
+ };
65
+ },
66
+ },
67
+ },
68
+ VisualizationComponent: makeVisualizationComponent(getAssetUrl),
69
+ StaticVisualizationComponent: makeStaticVisualizationComponent(getAssetUrl),
70
+ };
71
+ };
72
+
73
+ const makeVisualizationComponent = (getAssetUrl: (path: string) => string) => (props: CustomVisualizationProps<Settings>) => {
74
+ const { height, series, settings, width } = props;
75
+ const { threshold } = settings;
76
+ const value = series[0].data.rows[0][0];
77
+
78
+ if (typeof value !== "number" || typeof threshold !== "number") {
79
+ throw new Error("Value and threshold need to be numbers");
80
+ }
81
+
82
+ const emoji = value >= threshold ? "👍" : "👎";
83
+
84
+ return (
85
+ <div
86
+ style={{
87
+ display: "flex",
88
+ justifyContent: "center",
89
+ alignItems: "center",
90
+ width,
91
+ height,
92
+ fontSize: "10rem",
93
+ }}
94
+ >
95
+ {emoji}
96
+ </div>
97
+ );
98
+ };
99
+
100
+ const makeStaticVisualizationComponent = (getAssetUrl: (path: string) => string) => (
101
+ props: CustomStaticVisualizationProps<Settings>,
102
+ ) => {
103
+ const width = 540;
104
+ const height = 360;
105
+ const { series, settings } = props;
106
+ const { threshold } = settings;
107
+ const value = series[0].data.rows[0][0];
108
+
109
+ if (typeof value !== "number" || typeof threshold !== "number") {
110
+ throw new Error("Value and threshold need to be numbers");
111
+ }
112
+
113
+ const emoji =
114
+ value >= threshold ? (
115
+ <img src={getAssetUrl("thumbs-up.png")} />
116
+ ) : (
117
+ <img src={getAssetUrl("thumbs-down.png")} />
118
+ );
119
+
120
+ return (
121
+ <div
122
+ style={{
123
+ display: "flex",
124
+ justifyContent: "center",
125
+ alignItems: "center",
126
+ width,
127
+ height,
128
+ fontSize: "10rem",
129
+ }}
130
+ >
131
+ {emoji}
132
+ </div>
133
+ );
134
+ };
135
+
136
+ export default createVisualization;
@@ -0,0 +1,8 @@
1
+ {
2
+ "name": "__CUSTOM_VIZ_NAME__",
3
+ "icon": "icon.svg",
4
+ "assets": ["icon.svg", "thumbs-up.png", "thumbs-down.png"],
5
+ "metabase": {
6
+ "version": ">=59"
7
+ }
8
+ }
@@ -0,0 +1,18 @@
1
+ {
2
+ "name": "__CUSTOM_VIZ_NAME__",
3
+ "version": "0.0.1",
4
+ "private": true,
5
+ "type": "module",
6
+ "scripts": {
7
+ "build": "vite build",
8
+ "dev": "vite build --watch & vite preview",
9
+ "type-check": "tsc --noEmit"
10
+ },
11
+ "devDependencies": {
12
+ "@metabase/custom-viz": "__CUSTOM_VIZ_VERSION__",
13
+ "@types/react": "^19.2.14",
14
+ "react": "^19.1.0",
15
+ "typescript": "^5.9.3",
16
+ "vite": "^8.0.0"
17
+ }
18
+ }
Binary file
Binary file
@@ -0,0 +1,14 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "module": "ESNext",
5
+ "moduleResolution": "bundler",
6
+ "jsx": "react-jsx",
7
+ "strict": true,
8
+ "esModuleInterop": true,
9
+ "skipLibCheck": true,
10
+ "outDir": "dist",
11
+ "declaration": true
12
+ },
13
+ "include": ["src"]
14
+ }
@@ -0,0 +1,139 @@
1
+ import { resolve } from "path";
2
+ import { createServer } from "http";
3
+ import { watch, cpSync } from "fs";
4
+ import { defineConfig } from "vite";
5
+
6
+ /**
7
+ * Vite plugin that replaces `react` and `react/jsx-runtime` imports with
8
+ * virtual modules that read from Metabase's `window.__METABASE_VIZ_API__`.
9
+ *
10
+ * This is necessary because the ES module output format cannot use
11
+ * `output.globals`, and bare `import 'react'` would fail in the browser.
12
+ */
13
+ function metabaseVizExternals() {
14
+ const VIRTUAL_REACT = "\0virtual:react";
15
+ const VIRTUAL_JSX_RUNTIME = "\0virtual:react/jsx-runtime";
16
+ const VIRTUAL_CUSTOM_VIZ = "\0virtual:@metabase/custom-viz";
17
+
18
+ return {
19
+ name: "metabase-viz-externals",
20
+ enforce: "pre" as const,
21
+
22
+ resolveId(source) {
23
+ if (source === "react") {
24
+ return VIRTUAL_REACT;
25
+ }
26
+ if (source === "react/jsx-runtime") {
27
+ return VIRTUAL_JSX_RUNTIME;
28
+ }
29
+ if (source === "@metabase/custom-viz") {
30
+ return VIRTUAL_CUSTOM_VIZ;
31
+ }
32
+ return null;
33
+ },
34
+
35
+ load(id) {
36
+ if (id === VIRTUAL_REACT) {
37
+ return [
38
+ "const React = window.__METABASE_VIZ_API__.React;",
39
+ "export default React;",
40
+ "export const { useState, useEffect, useRef, useCallback, useMemo, useReducer, useContext, createElement, Fragment } = React;",
41
+ ].join("\n");
42
+ }
43
+ if (id === VIRTUAL_JSX_RUNTIME) {
44
+ return [
45
+ "const jsxRuntime = window.__METABASE_VIZ_API__.jsxRuntime;",
46
+ "export const { jsx, jsxs, Fragment } = jsxRuntime;",
47
+ ].join("\n");
48
+ }
49
+ if (id === VIRTUAL_CUSTOM_VIZ) {
50
+ return [
51
+ "const ct = window.__METABASE_VIZ_API__.columnTypes;",
52
+ "export const { isDate, isNumeric, isInteger, isBoolean, isString, isStringLike, isSummable, isNumericBaseType, isDateWithoutTime, isNumber, isFloat, isTime, isFK, isPK, isEntityName, isTitle, isProduct, isSource, isAddress, isScore, isQuantity, isCategory, isAny, isState, isCountry, isCoordinate, isLatitude, isLongitude, isCurrency, isPercentage, isID, isURL, isEmail, isAvatarURL, isImageURL, hasLatitudeAndLongitudeColumns } = ct;",
53
+ "export const formatValue = window.__METABASE_VIZ_API__.formatValue;",
54
+ ].join("\n");
55
+ }
56
+ return null;
57
+ },
58
+ };
59
+ }
60
+
61
+ const NOTIFY_PORT = 5175;
62
+
63
+ /**
64
+ * Vite plugin that starts a tiny SSE server and sends a "reload" event
65
+ * to all connected clients after each rebuild completes.
66
+ * Metabase's frontend connects to this to live-reload the custom viz.
67
+ */
68
+ function metabaseNotifyReload() {
69
+ const clients = new Set<import("http").ServerResponse>();
70
+ let server: ReturnType<typeof createServer> | null = null;
71
+
72
+ return {
73
+ name: "metabase-notify-reload",
74
+
75
+ buildStart() {
76
+ if (server) {
77
+ return;
78
+ }
79
+ server = createServer((req, res) => {
80
+ res.writeHead(200, {
81
+ "Content-Type": "text/event-stream",
82
+ "Cache-Control": "no-cache",
83
+ Connection: "keep-alive",
84
+ "Access-Control-Allow-Origin": "*",
85
+ });
86
+ clients.add(res);
87
+ req.on("close", () => clients.delete(res));
88
+ });
89
+ server.listen(NOTIFY_PORT, () => {
90
+ console.log(
91
+ `[metabase-notify] SSE server listening on http://localhost:${NOTIFY_PORT}`,
92
+ );
93
+ });
94
+
95
+ // Watch public/assets/ for changes — copy to dist/assets/ and notify
96
+ const assetsDir = resolve(__dirname, "public/assets");
97
+ watch(assetsDir, { recursive: true }, (_event, filename) => {
98
+ if (!filename) {
99
+ return;
100
+ }
101
+ cpSync(resolve(assetsDir, filename), resolve(__dirname, "dist/assets", filename));
102
+ for (const client of clients) {
103
+ client.write("data: reload\n\n");
104
+ }
105
+ console.log(`[metabase-notify] Asset changed: ${filename}, notified ${clients.size} client(s)`);
106
+ });
107
+ },
108
+
109
+ closeBundle() {
110
+ for (const client of clients) {
111
+ client.write("data: reload\n\n");
112
+ }
113
+ console.log(
114
+ `[metabase-notify] Build complete, notified ${clients.size} client(s)`,
115
+ );
116
+ },
117
+ };
118
+ }
119
+
120
+ const isWatch = process.argv.includes("--watch");
121
+
122
+ export default defineConfig({
123
+ plugins: [metabaseVizExternals(), ...(isWatch ? [metabaseNotifyReload()] : [])],
124
+ publicDir: "public",
125
+ build: {
126
+ outDir: "dist",
127
+ lib: {
128
+ entry: resolve(__dirname, "src/index.tsx"),
129
+ formats: ["iife"],
130
+ fileName: () => "index.js",
131
+ name: "__customVizPlugin__",
132
+ },
133
+ },
134
+ preview: {
135
+ port: 5174,
136
+ host: true,
137
+ cors: true,
138
+ },
139
+ });
@@ -0,0 +1,41 @@
1
+ import { Column } from './data';
2
+ export type ColumnPredicate = (column: Column | null | undefined) => boolean;
3
+ export interface ColumnTypes {
4
+ isDate: ColumnPredicate;
5
+ isNumeric: ColumnPredicate;
6
+ isInteger: ColumnPredicate;
7
+ isBoolean: ColumnPredicate;
8
+ isString: ColumnPredicate;
9
+ isStringLike: ColumnPredicate;
10
+ isSummable: ColumnPredicate;
11
+ isNumericBaseType: ColumnPredicate;
12
+ isDateWithoutTime: ColumnPredicate;
13
+ isNumber: ColumnPredicate;
14
+ isFloat: ColumnPredicate;
15
+ isTime: ColumnPredicate;
16
+ isFK: ColumnPredicate;
17
+ isPK: ColumnPredicate;
18
+ isEntityName: ColumnPredicate;
19
+ isTitle: ColumnPredicate;
20
+ isProduct: ColumnPredicate;
21
+ isSource: ColumnPredicate;
22
+ isAddress: ColumnPredicate;
23
+ isScore: ColumnPredicate;
24
+ isQuantity: ColumnPredicate;
25
+ isCategory: ColumnPredicate;
26
+ isAny: ColumnPredicate;
27
+ isState: ColumnPredicate;
28
+ isCountry: ColumnPredicate;
29
+ isCoordinate: ColumnPredicate;
30
+ isLatitude: ColumnPredicate;
31
+ isLongitude: ColumnPredicate;
32
+ isCurrency: ColumnPredicate;
33
+ isPercentage: ColumnPredicate;
34
+ isID: ColumnPredicate;
35
+ isURL: ColumnPredicate;
36
+ isEmail: ColumnPredicate;
37
+ isAvatarURL: ColumnPredicate;
38
+ isImageURL: ColumnPredicate;
39
+ hasLatitudeAndLongitudeColumns: (cols: Column[]) => boolean;
40
+ }
41
+ //# sourceMappingURL=column-types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"column-types.d.ts","sourceRoot":"","sources":["../../src/types/column-types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAErC,MAAM,MAAM,eAAe,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,KAAK,OAAO,CAAC;AAE7E,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,eAAe,CAAC;IACxB,SAAS,EAAE,eAAe,CAAC;IAC3B,SAAS,EAAE,eAAe,CAAC;IAC3B,SAAS,EAAE,eAAe,CAAC;IAC3B,QAAQ,EAAE,eAAe,CAAC;IAC1B,YAAY,EAAE,eAAe,CAAC;IAC9B,UAAU,EAAE,eAAe,CAAC;IAC5B,iBAAiB,EAAE,eAAe,CAAC;IACnC,iBAAiB,EAAE,eAAe,CAAC;IACnC,QAAQ,EAAE,eAAe,CAAC;IAC1B,OAAO,EAAE,eAAe,CAAC;IACzB,MAAM,EAAE,eAAe,CAAC;IACxB,IAAI,EAAE,eAAe,CAAC;IACtB,IAAI,EAAE,eAAe,CAAC;IACtB,YAAY,EAAE,eAAe,CAAC;IAC9B,OAAO,EAAE,eAAe,CAAC;IACzB,SAAS,EAAE,eAAe,CAAC;IAC3B,QAAQ,EAAE,eAAe,CAAC;IAC1B,SAAS,EAAE,eAAe,CAAC;IAC3B,OAAO,EAAE,eAAe,CAAC;IACzB,UAAU,EAAE,eAAe,CAAC;IAC5B,UAAU,EAAE,eAAe,CAAC;IAC5B,KAAK,EAAE,eAAe,CAAC;IACvB,OAAO,EAAE,eAAe,CAAC;IACzB,SAAS,EAAE,eAAe,CAAC;IAC3B,YAAY,EAAE,eAAe,CAAC;IAC9B,UAAU,EAAE,eAAe,CAAC;IAC5B,WAAW,EAAE,eAAe,CAAC;IAC7B,UAAU,EAAE,eAAe,CAAC;IAC5B,YAAY,EAAE,eAAe,CAAC;IAC9B,IAAI,EAAE,eAAe,CAAC;IACtB,KAAK,EAAE,eAAe,CAAC;IACvB,OAAO,EAAE,eAAe,CAAC;IACzB,WAAW,EAAE,eAAe,CAAC;IAC7B,UAAU,EAAE,eAAe,CAAC;IAC5B,8BAA8B,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC;CAC7D"}
@@ -0,0 +1,22 @@
1
+ import { Column, RowValue } from './data';
2
+ export type FormatValueOptions = {
3
+ column?: Column;
4
+ compact?: boolean;
5
+ currency?: string;
6
+ currency_style?: string;
7
+ date_format?: string;
8
+ date_style?: string;
9
+ date_separator?: string;
10
+ date_abbreviate?: boolean;
11
+ decimals?: number;
12
+ number_style?: string;
13
+ number_separators?: string;
14
+ prefix?: string;
15
+ suffix?: string;
16
+ scale?: number;
17
+ negativeInParentheses?: boolean;
18
+ time_enabled?: "minutes" | "milliseconds" | "seconds" | null;
19
+ time_style?: string;
20
+ };
21
+ export type FormatValue = (value: RowValue, options?: FormatValueOptions) => string;
22
+ //# sourceMappingURL=format.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../src/types/format.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAE/C,MAAM,MAAM,kBAAkB,GAAG;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,YAAY,CAAC,EAAE,SAAS,GAAG,cAAc,GAAG,SAAS,GAAG,IAAI,CAAC;IAC7D,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG,CACxB,KAAK,EAAE,QAAQ,EACf,OAAO,CAAC,EAAE,kBAAkB,KACzB,MAAM,CAAC"}
@@ -1,5 +1,8 @@
1
+ export * from './column-types';
1
2
  export * from './data';
2
3
  export * from './date-time';
4
+ export * from './format';
5
+ export * from './measure-text';
3
6
  export * from './viz';
4
7
  export * from './viz-settings';
5
8
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA,cAAc,QAAQ,CAAC;AACvB,cAAc,aAAa,CAAC;AAC5B,cAAc,OAAO,CAAC;AACtB,cAAc,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,QAAQ,CAAC;AACvB,cAAc,aAAa,CAAC;AAC5B,cAAc,UAAU,CAAC;AACzB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,OAAO,CAAC;AACtB,cAAc,gBAAgB,CAAC"}
@@ -1,6 +1,6 @@
1
1
  import { ComponentType } from 'react';
2
2
  import { Column, DatasetData, RowValue, Series } from './data';
3
- import { TextHeightMeasurer, TextWidthMeasurer } from './measure-text';
3
+ import { TextHeightMeasurer, TextMeasurer, TextWidthMeasurer } from './measure-text';
4
4
  import { WidgetName, Widgets } from './viz-settings';
5
5
  /**
6
6
  * Export this function to define a custom visualization.
@@ -11,6 +11,24 @@ export type CreateCustomVisualizationProps = {
11
11
  * Translates text using ttag function used in Metabase.
12
12
  */
13
13
  translate: (text: string) => string;
14
+ /**
15
+ * Returns a URL for a static asset declared in the plugin manifest.
16
+ * Use this to reference images and other static files from your plugin.
17
+ * @example getAssetUrl("icon.svg")
18
+ */
19
+ getAssetUrl: (assetPath: string) => string;
20
+ /**
21
+ * Measures text dimensions (width and height) for given text and font style.
22
+ */
23
+ measureText: TextMeasurer;
24
+ /**
25
+ * Measures text width for given text and font style.
26
+ */
27
+ measureTextWidth: TextWidthMeasurer;
28
+ /**
29
+ * Measures text height for given text and font style.
30
+ */
31
+ measureTextHeight: TextHeightMeasurer;
14
32
  };
15
33
  export type CustomVisualization<CustomVisualizationSettings> = {
16
34
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"viz.d.ts","sourceRoot":"","sources":["../../src/types/viz.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"viz.d.ts","sourceRoot":"","sources":["../../src/types/viz.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAE3C,OAAO,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACpE,OAAO,KAAK,EACV,kBAAkB,EAClB,YAAY,EACZ,iBAAiB,EAClB,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAE1D;;GAEG;AACH,MAAM,MAAM,yBAAyB,CAAC,2BAA2B,IAAI,CACnE,KAAK,EAAE,8BAA8B,KAClC,mBAAmB,CAAC,2BAA2B,CAAC,CAAC;AAEtD,MAAM,MAAM,8BAA8B,GAAG;IAC3C;;OAEG;IACH,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IAEpC;;;;OAIG;IACH,WAAW,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,MAAM,CAAC;IAE3C;;OAEG;IACH,WAAW,EAAE,YAAY,CAAC;IAE1B;;OAEG;IACH,gBAAgB,EAAE,iBAAiB,CAAC;IAEpC;;OAEG;IACH,iBAAiB,EAAE,kBAAkB,CAAC;CACvC,CAAC;AAEF,MAAM,MAAM,mBAAmB,CAAC,2BAA2B,IAAI;IAC7D;;OAEG;IACH,EAAE,EAAE,MAAM,CAAC;IAEX;;OAEG;IACH,OAAO,IAAI,MAAM,CAAC;IAElB;;OAEG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IAErB;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB;;OAEG;IACH,OAAO,CAAC,EAAE,qBAAqB,CAAC;IAEhC;;OAEG;IACH,WAAW,CAAC,EAAE,qBAAqB,CAAC;IAEpC;;OAEG;IACH,QAAQ,CAAC,EAAE,sCAAsC,CAAC,2BAA2B,CAAC,CAAC;IAE/E;;;OAGG;IACH,UAAU,EAAE,CAAC,IAAI,EAAE,WAAW,KAAK,OAAO,CAAC;IAE3C;;OAEG;IACH,eAAe,EAAE,CACf,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,2BAA2B,KAClC,IAAI,GAAG,KAAK,CAAC;IAElB;;OAEG;IACH,sBAAsB,EAAE,aAAa,CACnC,wBAAwB,CAAC,2BAA2B,CAAC,CACtD,CAAC;IAEF;;OAEG;IACH,4BAA4B,CAAC,EAAE,aAAa,CAC1C,8BAA8B,CAAC,2BAA2B,CAAC,CAC5D,CAAC;CACH,CAAC;AAEF,MAAM,MAAM,sCAAsC,CAChD,2BAA2B,EAC3B,CAAC,SAAS,MAAM,2BAA2B,GACzC,MAAM,2BAA2B,IACjC;KACD,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,8BAA8B,CAC1C,2BAA2B,CAAC,GAAG,CAAC,EAChC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACvB,2BAA2B,CAC5B;CACF,CAAC;AAEF,MAAM,MAAM,eAAe,CAAC,MAAM,EAAE,2BAA2B,IAAI;IACjE,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,QAAQ,EAAE,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IAC1C,gBAAgB,EAAE,CAAC,QAAQ,EAAE,OAAO,CAAC,2BAA2B,CAAC,KAAK,IAAI,CAAC;CAC5E,CAAC;AAEF,KAAK,kCAAkC,CAAC,MAAM,EAAE,2BAA2B,IAAI;IAC7E,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IAEjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAE7B,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,2BAA2B,KAAK,OAAO,CAAC;IAC7E,UAAU,CAAC,EAAE,CACX,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,2BAA2B,KAClC,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,2BAA2B,KAAK,MAAM,CAAC;CAC9E,CAAC;AAEF,KAAK,+CAA+C,CAClD,MAAM,EACN,2BAA2B,IACzB;KACD,GAAG,IAAI,UAAU,GAAG,kCAAkC,CACrD,MAAM,EACN,2BAA2B,CAC5B,GAAG;QACF,MAAM,EAAE,GAAG,CAAC;QACZ,QAAQ,CAAC,EAAE,CACT,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,2BAA2B,KACrC,OAAO,CAAC,GAAG,CAAC,CAAC;KACnB;CACF,CAAC,UAAU,CAAC,CAAC;AAEd,KAAK,8CAA8C,CACjD,MAAM,EACN,MAAM,EACN,2BAA2B,IACzB,kCAAkC,CAAC,MAAM,EAAE,2BAA2B,CAAC,GAAG;IAC5E,MAAM,EAAE,aAAa,CACnB,MAAM,GAAG,eAAe,CAAC,MAAM,EAAE,2BAA2B,CAAC,CAC9D,CAAC;IACF,QAAQ,CAAC,EAAE,CACT,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,2BAA2B,KACrC,MAAM,CAAC;CACb,CAAC;AAEF,KAAK,2CAA2C,CAC9C,MAAM,EACN,2BAA2B,IACzB,kCAAkC,CAAC,MAAM,EAAE,2BAA2B,CAAC,GAAG;IAC5E,MAAM,CAAC,EAAE,KAAK,CAAC;IACf,QAAQ,CAAC,EAAE,KAAK,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,8BAA8B,CACxC,MAAM,EACN,MAAM,EACN,2BAA2B,IAEzB,+CAA+C,CAC7C,MAAM,EACN,2BAA2B,CAC5B,GACD,8CAA8C,CAC5C,MAAM,EACN,MAAM,EACN,2BAA2B,CAC5B,GACD,2CAA2C,CACzC,MAAM,EACN,2BAA2B,CAC5B,CAAC;AAEN,MAAM,MAAM,qBAAqB,GAAG;IAClC;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,wBAAwB,CAAC,2BAA2B,IAAI;IAClE,KAAK,EAAE,MAAM,CAAC;IAEd,MAAM,EAAE,MAAM,CAAC;IAEf,MAAM,EAAE,MAAM,CAAC;IAEf,QAAQ,EAAE,2BAA2B,CAAC;IAEtC,OAAO,EAAE,CACP,WAAW,EAAE,WAAW,CAAC,2BAA2B,CAAC,GAAG,IAAI,KACzD,IAAI,CAAC;CAGX,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG,CAAC,SAAS,EAAE,MAAM,KAAK,MAAM,CAAC;AAExD,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,WAAW,CAAC;IACtB,WAAW,EAAE,iBAAiB,CAAC;IAC/B,iBAAiB,EAAE,kBAAkB,CAAC;IACtC,UAAU,EAAE,MAAM,CAAC;CAEpB;AAGD,MAAM,MAAM,8BAA8B,CAAC,2BAA2B,IAAI;IACxE,MAAM,EAAE,MAAM,CAAC;IACf,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,QAAQ,EAAE,2BAA2B,CAAC;IACtC,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,gCAAgC,GAAG,EAAE,CAAC;AAElD,MAAM,MAAM,WAAW,CAAC,2BAA2B,IAAI;IACrD,KAAK,CAAC,EAAE,QAAQ,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,oBAAoB,EAAE,CAAC;IACpC,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAGlB,QAAQ,CAAC,EAAE,2BAA2B,CAAC;IAEvC,MAAM,CAAC,EAAE;QACP,GAAG,EAAE,QAAQ,EAAE,CAAC;QAChB,IAAI,EAAE,MAAM,EAAE,CAAC;KAChB,CAAC;CAGH,CAAC;AAEF,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,QAAQ,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAChB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@metabase/custom-viz",
3
- "version": "0.0.1-alpha.2",
3
+ "version": "0.0.1-alpha.3",
4
4
  "description": "Creating custom visualizations for Metabase",
5
5
  "type": "module",
6
6
  "bin": {
@@ -22,7 +22,7 @@
22
22
  ],
23
23
  "scripts": {
24
24
  "dev": "vite build --watch",
25
- "build": "vite build",
25
+ "build": "vite build && cp -r src/templates dist/templates",
26
26
  "lint": "oxlint src/",
27
27
  "format": "prettier --write .",
28
28
  "format:check": "prettier --check .",