@prismiq/react 0.1.0 → 0.1.1

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.
Files changed (57) hide show
  1. package/dist/{CustomSQLEditor-BXB4rf1q.d.cts → CustomSQLEditor-CYlOtecq.d.ts} +10 -3
  2. package/dist/{CustomSQLEditor-DYeId0Gp.d.ts → CustomSQLEditor-d84v_Cgp.d.cts} +10 -3
  3. package/dist/{DashboardDialog-LHmrtNQU.d.cts → DashboardDialog-CZD8I-6z.d.cts} +4 -4
  4. package/dist/{DashboardDialog-B3vYC5Gs.d.ts → DashboardDialog-DBNTVVSp.d.ts} +4 -4
  5. package/dist/{accessibility-2yy5yqRR.d.cts → accessibility-Bu2mNtaB.d.cts} +1 -1
  6. package/dist/{accessibility-2yy5yqRR.d.ts → accessibility-Bu2mNtaB.d.ts} +1 -1
  7. package/dist/charts/index.cjs +27 -27
  8. package/dist/charts/index.d.cts +2 -2
  9. package/dist/charts/index.d.ts +2 -2
  10. package/dist/charts/index.js +2 -2
  11. package/dist/{chunk-MOAEEF5P.js → chunk-3LDRRDJ6.js} +185 -91
  12. package/dist/chunk-3LDRRDJ6.js.map +1 -0
  13. package/dist/{chunk-NK7HKX2J.cjs → chunk-73TPDGXB.cjs} +7 -7
  14. package/dist/{chunk-NK7HKX2J.cjs.map → chunk-73TPDGXB.cjs.map} +1 -1
  15. package/dist/{chunk-UPYINBZU.js → chunk-ET7GCREP.js} +502 -46
  16. package/dist/chunk-ET7GCREP.js.map +1 -0
  17. package/dist/{chunk-2H5WTH4K.js → chunk-FQ23KG6G.js} +3 -3
  18. package/dist/{chunk-2H5WTH4K.js.map → chunk-FQ23KG6G.js.map} +1 -1
  19. package/dist/{chunk-4AVL6GQK.cjs → chunk-KXB2IZI2.cjs} +36 -9
  20. package/dist/chunk-KXB2IZI2.cjs.map +1 -0
  21. package/dist/{chunk-EX74SI67.js → chunk-LBE6GIBC.js} +36 -9
  22. package/dist/chunk-LBE6GIBC.js.map +1 -0
  23. package/dist/{chunk-NY6TZLST.cjs → chunk-URJH4H6G.cjs} +505 -49
  24. package/dist/chunk-URJH4H6G.cjs.map +1 -0
  25. package/dist/{chunk-FEABEF3J.cjs → chunk-VQDFS6VS.cjs} +374 -280
  26. package/dist/chunk-VQDFS6VS.cjs.map +1 -0
  27. package/dist/components/index.cjs +55 -55
  28. package/dist/components/index.d.cts +2 -2
  29. package/dist/components/index.d.ts +2 -2
  30. package/dist/components/index.js +2 -2
  31. package/dist/dashboard/index.cjs +36 -36
  32. package/dist/dashboard/index.d.cts +3 -3
  33. package/dist/dashboard/index.d.ts +3 -3
  34. package/dist/dashboard/index.js +4 -4
  35. package/dist/export/index.d.cts +1 -1
  36. package/dist/export/index.d.ts +1 -1
  37. package/dist/{index-C-Qcuu4Y.d.cts → index-CvKj3SWO.d.cts} +2 -2
  38. package/dist/{index-rPc7ijt8.d.ts → index-DXGLs1yY.d.ts} +2 -2
  39. package/dist/index.cjs +127 -127
  40. package/dist/index.cjs.map +1 -1
  41. package/dist/index.d.cts +30 -9
  42. package/dist/index.d.ts +30 -9
  43. package/dist/index.js +6 -6
  44. package/dist/index.js.map +1 -1
  45. package/dist/{types-WrCbOeAV.d.cts → types-j0kPJ9Hz.d.cts} +16 -1
  46. package/dist/{types-WrCbOeAV.d.ts → types-j0kPJ9Hz.d.ts} +16 -1
  47. package/dist/utils/index.cjs +15 -15
  48. package/dist/utils/index.d.cts +5 -21
  49. package/dist/utils/index.d.ts +5 -21
  50. package/dist/utils/index.js +1 -1
  51. package/package.json +2 -2
  52. package/dist/chunk-4AVL6GQK.cjs.map +0 -1
  53. package/dist/chunk-EX74SI67.js.map +0 -1
  54. package/dist/chunk-FEABEF3J.cjs.map +0 -1
  55. package/dist/chunk-MOAEEF5P.js.map +0 -1
  56. package/dist/chunk-NY6TZLST.cjs.map +0 -1
  57. package/dist/chunk-UPYINBZU.js.map +0 -1
@@ -1,5 +1,5 @@
1
1
  import { useTheme } from './chunk-T6STUE7E.js';
2
- import { useFocusTrap, parseColumnRef } from './chunk-EX74SI67.js';
2
+ import { useFocusTrap, parseColumnRef } from './chunk-LBE6GIBC.js';
3
3
  import { forwardRef, useState, useRef, useCallback, useEffect, isValidElement, cloneElement, createContext, useContext, useLayoutEffect, Component, useMemo } from 'react';
4
4
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
5
5
  import { createPortal } from 'react-dom';
@@ -2325,6 +2325,9 @@ var PrismiqClient = class {
2325
2325
  }
2326
2326
  /**
2327
2327
  * Make an authenticated request to the API.
2328
+ *
2329
+ * @param path - API path (starting with /)
2330
+ * @param options - Fetch options including signal for cancellation
2328
2331
  */
2329
2332
  async request(path, options = {}) {
2330
2333
  const url = `${this.endpoint}${path}`;
@@ -2470,6 +2473,17 @@ var PrismiqClient = class {
2470
2473
  const result = await this.request(path);
2471
2474
  return result.values;
2472
2475
  }
2476
+ /**
2477
+ * Get data source metadata including display names and descriptions.
2478
+ *
2479
+ * Returns metadata for all exposed tables/views that can be used
2480
+ * to show user-friendly names in the UI instead of raw table names.
2481
+ *
2482
+ * @returns Array of data source metadata.
2483
+ */
2484
+ async getDataSources() {
2485
+ return this.request("/data-sources");
2486
+ }
2473
2487
  // ============================================================================
2474
2488
  // Query Methods
2475
2489
  // ============================================================================
@@ -2503,12 +2517,14 @@ var PrismiqClient = class {
2503
2517
  *
2504
2518
  * @param query - The query definition to execute.
2505
2519
  * @param bypassCache - If true, bypass cache and re-execute query.
2520
+ * @param signal - Optional AbortSignal for cancellation.
2506
2521
  * @returns The query result with all rows and cache metadata.
2507
2522
  */
2508
- async executeQuery(query, bypassCache = false) {
2523
+ async executeQuery(query, bypassCache = false, signal) {
2509
2524
  return this.request("/query/execute", {
2510
2525
  method: "POST",
2511
- body: JSON.stringify({ query, bypass_cache: bypassCache })
2526
+ body: JSON.stringify({ query, bypass_cache: bypassCache }),
2527
+ signal
2512
2528
  });
2513
2529
  }
2514
2530
  /**
@@ -2861,6 +2877,7 @@ function AnalyticsProvider({
2861
2877
  }
2862
2878
  const client = clientRef.current;
2863
2879
  const [schema, setSchema] = useState(null);
2880
+ const [dataSources, setDataSources] = useState([]);
2864
2881
  const [isLoading, setIsLoading] = useState(true);
2865
2882
  const [error, setError] = useState(null);
2866
2883
  const hasFetchedSchemaRef = useRef(false);
@@ -2878,8 +2895,13 @@ function AnalyticsProvider({
2878
2895
  setIsLoading(true);
2879
2896
  setError(null);
2880
2897
  try {
2881
- const fetchedSchema = await client.getSchema();
2898
+ const [fetchedSchema, fetchedDataSources] = await Promise.all([
2899
+ client.getSchema(),
2900
+ client.getDataSources().catch(() => [])
2901
+ // Non-critical, fallback to empty
2902
+ ]);
2882
2903
  setSchema(fetchedSchema);
2904
+ setDataSources(fetchedDataSources);
2883
2905
  onSchemaLoadRef.current?.(fetchedSchema);
2884
2906
  } catch (err) {
2885
2907
  const schemaError = err instanceof Error ? err : new Error(String(err));
@@ -2901,6 +2923,7 @@ function AnalyticsProvider({
2901
2923
  () => ({
2902
2924
  client,
2903
2925
  schema,
2926
+ dataSources,
2904
2927
  isLoading,
2905
2928
  error,
2906
2929
  refetchSchema,
@@ -2908,7 +2931,7 @@ function AnalyticsProvider({
2908
2931
  userId,
2909
2932
  schemaName
2910
2933
  }),
2911
- [client, schema, isLoading, error, refetchSchema, tenantId, userId, schemaName]
2934
+ [client, schema, dataSources, isLoading, error, refetchSchema, tenantId, userId, schemaName]
2912
2935
  );
2913
2936
  const callbacks = useMemo(
2914
2937
  () => ({
@@ -2929,22 +2952,44 @@ function useAnalytics() {
2929
2952
  return context;
2930
2953
  }
2931
2954
  function useSchema() {
2932
- const { schema, isLoading, error } = useAnalytics();
2955
+ const { schema, dataSources, isLoading, error } = useAnalytics();
2933
2956
  const tables = useMemo(() => schema?.tables ?? [], [schema]);
2934
2957
  const relationships = useMemo(() => schema?.relationships ?? [], [schema]);
2958
+ const dataSourceMap = useMemo(() => {
2959
+ const map = /* @__PURE__ */ new Map();
2960
+ for (const ds of dataSources) {
2961
+ map.set(ds.table, ds);
2962
+ }
2963
+ return map;
2964
+ }, [dataSources]);
2935
2965
  const getTable = useCallback(
2936
2966
  (name) => {
2937
2967
  return tables.find((table) => table.name === name);
2938
2968
  },
2939
2969
  [tables]
2940
2970
  );
2971
+ const getDisplayName = useCallback(
2972
+ (tableName) => {
2973
+ return dataSourceMap.get(tableName)?.title ?? tableName;
2974
+ },
2975
+ [dataSourceMap]
2976
+ );
2977
+ const getDescription = useCallback(
2978
+ (tableName) => {
2979
+ return dataSourceMap.get(tableName)?.subtitle ?? "";
2980
+ },
2981
+ [dataSourceMap]
2982
+ );
2941
2983
  return {
2942
2984
  schema,
2943
2985
  tables,
2944
2986
  relationships,
2987
+ dataSources,
2945
2988
  isLoading,
2946
2989
  error,
2947
- getTable
2990
+ getTable,
2991
+ getDisplayName,
2992
+ getDescription
2948
2993
  };
2949
2994
  }
2950
2995
  function queryEquals(a, b) {
@@ -4833,6 +4878,29 @@ var containerStyles7 = {
4833
4878
  gap: "var(--prismiq-spacing-xs)",
4834
4879
  flex: 1
4835
4880
  };
4881
+ var comboboxContainerStyles = {
4882
+ position: "relative",
4883
+ flex: 1
4884
+ };
4885
+ var dropdownStyles2 = {
4886
+ position: "fixed",
4887
+ backgroundColor: "var(--prismiq-color-background)",
4888
+ border: "1px solid var(--prismiq-color-border)",
4889
+ borderRadius: "var(--prismiq-radius-md)",
4890
+ boxShadow: "var(--prismiq-shadow-md)",
4891
+ zIndex: 1e3,
4892
+ maxHeight: "200px",
4893
+ overflow: "auto"
4894
+ };
4895
+ var optionStyles2 = {
4896
+ padding: "var(--prismiq-spacing-sm) var(--prismiq-spacing-md)",
4897
+ cursor: "pointer",
4898
+ fontSize: "var(--prismiq-font-size-sm)",
4899
+ transition: "background-color 0.1s"
4900
+ };
4901
+ var optionHoverStyles2 = {
4902
+ backgroundColor: "var(--prismiq-color-surface-hover)"
4903
+ };
4836
4904
  function parseValue(value, dataType) {
4837
4905
  if (!value) return void 0;
4838
4906
  const type = dataType?.toLowerCase() ?? "";
@@ -4863,15 +4931,270 @@ function getInputType(dataType) {
4863
4931
  }
4864
4932
  return "text";
4865
4933
  }
4934
+ function isMultiValueOperator(op) {
4935
+ return op === "in_" || op === "not_in" || op === "in_or_null";
4936
+ }
4937
+ var tagContainerStyles = {
4938
+ display: "flex",
4939
+ flexWrap: "wrap",
4940
+ alignItems: "center",
4941
+ gap: "4px",
4942
+ padding: "4px 8px",
4943
+ border: "1px solid var(--prismiq-color-border)",
4944
+ borderRadius: "var(--prismiq-radius-sm)",
4945
+ backgroundColor: "var(--prismiq-color-background)",
4946
+ minHeight: "32px",
4947
+ cursor: "text",
4948
+ flex: 1
4949
+ };
4950
+ var tagStyles = {
4951
+ display: "inline-flex",
4952
+ alignItems: "center",
4953
+ gap: "4px",
4954
+ padding: "1px 6px",
4955
+ backgroundColor: "var(--prismiq-color-surface)",
4956
+ border: "1px solid var(--prismiq-color-border)",
4957
+ borderRadius: "var(--prismiq-radius-sm)",
4958
+ fontSize: "var(--prismiq-font-size-sm)",
4959
+ lineHeight: "20px",
4960
+ whiteSpace: "nowrap"
4961
+ };
4962
+ var tagRemoveStyles = {
4963
+ display: "inline-flex",
4964
+ alignItems: "center",
4965
+ justifyContent: "center",
4966
+ width: "14px",
4967
+ height: "14px",
4968
+ border: "none",
4969
+ background: "none",
4970
+ cursor: "pointer",
4971
+ padding: 0,
4972
+ fontSize: "12px",
4973
+ lineHeight: 1,
4974
+ color: "var(--prismiq-color-text-muted)",
4975
+ borderRadius: "50%"
4976
+ };
4977
+ var tagInputStyles = {
4978
+ border: "none",
4979
+ outline: "none",
4980
+ background: "none",
4981
+ flex: 1,
4982
+ minWidth: "80px",
4983
+ fontSize: "var(--prismiq-font-size-sm)",
4984
+ padding: "2px 0",
4985
+ color: "var(--prismiq-color-text)"
4986
+ };
4987
+ var multiOptionCheckStyles = {
4988
+ marginRight: "6px",
4989
+ color: "var(--prismiq-color-primary)",
4990
+ fontWeight: 700,
4991
+ fontSize: "12px"
4992
+ };
4866
4993
  function FilterValueInput({
4867
4994
  operator,
4868
4995
  value,
4869
4996
  onChange,
4870
4997
  dataType,
4871
4998
  disabled = false,
4872
- className
4999
+ className,
5000
+ tableName,
5001
+ columnName
4873
5002
  }) {
5003
+ const { client } = useAnalytics();
4874
5004
  const inputType = getInputType(dataType);
5005
+ const isMulti = isMultiValueOperator(operator);
5006
+ const [sampleValues, setSampleValues] = useState([]);
5007
+ const [isLoadingValues, setIsLoadingValues] = useState(false);
5008
+ const fetchedRef = useRef(null);
5009
+ const fetchSeqRef = useRef(0);
5010
+ const [isDropdownOpen, setIsDropdownOpen] = useState(false);
5011
+ const [highlightedIndex, setHighlightedIndex] = useState(-1);
5012
+ const [dropdownPosition, setDropdownPosition] = useState({ top: 0, left: 0, width: 0 });
5013
+ const inputRef = useRef(null);
5014
+ const dropdownRef = useRef(null);
5015
+ const containerRef = useRef(null);
5016
+ const [multiInputText, setMultiInputText] = useState("");
5017
+ useEffect(() => {
5018
+ setMultiInputText("");
5019
+ }, [operator]);
5020
+ useEffect(() => {
5021
+ if (!tableName || !columnName || !client) {
5022
+ setSampleValues([]);
5023
+ setIsLoadingValues(false);
5024
+ fetchedRef.current = null;
5025
+ return;
5026
+ }
5027
+ const fetchKey = `${tableName}.${columnName}`;
5028
+ if (fetchedRef.current === fetchKey) return;
5029
+ const fetchSeq = ++fetchSeqRef.current;
5030
+ const fetchSamples = async () => {
5031
+ setIsLoadingValues(true);
5032
+ try {
5033
+ const values = await client.getColumnSample(tableName, columnName, 100);
5034
+ const stringValues = values.filter((v) => v !== null && v !== void 0).map((v) => String(v));
5035
+ if (fetchSeqRef.current !== fetchSeq) return;
5036
+ setSampleValues(stringValues);
5037
+ fetchedRef.current = fetchKey;
5038
+ } catch (err) {
5039
+ if (fetchSeqRef.current !== fetchSeq) return;
5040
+ console.error("Failed to fetch sample values:", err);
5041
+ setSampleValues([]);
5042
+ fetchedRef.current = null;
5043
+ } finally {
5044
+ if (fetchSeqRef.current === fetchSeq) {
5045
+ setIsLoadingValues(false);
5046
+ }
5047
+ }
5048
+ };
5049
+ fetchSamples();
5050
+ }, [client, tableName, columnName]);
5051
+ const selectedValues = isMulti && Array.isArray(value) ? value.filter((v) => v !== null && v !== void 0).map((v) => String(v)) : [];
5052
+ const currentValueStr = isMulti ? multiInputText : formatValue(value);
5053
+ const filteredOptions = isMulti ? sampleValues.filter(
5054
+ (v) => v.toLowerCase().includes(multiInputText.toLowerCase()) && !selectedValues.includes(v)
5055
+ ) : sampleValues.filter(
5056
+ (v) => v.toLowerCase().includes(currentValueStr.toLowerCase())
5057
+ );
5058
+ const updateDropdownPosition = useCallback(() => {
5059
+ const el = isMulti ? containerRef.current : inputRef.current;
5060
+ if (el) {
5061
+ const rect = el.getBoundingClientRect();
5062
+ setDropdownPosition({
5063
+ top: rect.bottom + 4,
5064
+ left: rect.left,
5065
+ width: rect.width
5066
+ });
5067
+ }
5068
+ }, [isMulti]);
5069
+ useEffect(() => {
5070
+ const handleClickOutside = (event) => {
5071
+ const target = event.target;
5072
+ const isInsideContainer = containerRef.current?.contains(target);
5073
+ const isInsideDropdown = dropdownRef.current?.contains(target);
5074
+ if (!isInsideContainer && !isInsideDropdown) {
5075
+ setIsDropdownOpen(false);
5076
+ }
5077
+ };
5078
+ document.addEventListener("mousedown", handleClickOutside);
5079
+ return () => document.removeEventListener("mousedown", handleClickOutside);
5080
+ }, []);
5081
+ const handleInputFocus = useCallback(() => {
5082
+ if (sampleValues.length > 0) {
5083
+ updateDropdownPosition();
5084
+ setIsDropdownOpen(true);
5085
+ setHighlightedIndex(-1);
5086
+ }
5087
+ }, [sampleValues.length, updateDropdownPosition]);
5088
+ const handleOptionSelect = useCallback(
5089
+ (optionValue) => {
5090
+ onChange(parseValue(optionValue, dataType));
5091
+ setIsDropdownOpen(false);
5092
+ inputRef.current?.blur();
5093
+ },
5094
+ [onChange, dataType]
5095
+ );
5096
+ const addMultiValue = useCallback(
5097
+ (val) => {
5098
+ const trimmed = val.trim();
5099
+ if (!trimmed) return;
5100
+ if (selectedValues.includes(trimmed)) return;
5101
+ const newValues = [...selectedValues, trimmed].map((v) => parseValue(v, dataType));
5102
+ onChange(newValues);
5103
+ setMultiInputText("");
5104
+ },
5105
+ [selectedValues, onChange, dataType]
5106
+ );
5107
+ const removeMultiValue = useCallback(
5108
+ (val) => {
5109
+ const newValues = selectedValues.filter((v) => v !== val).map((v) => parseValue(v, dataType));
5110
+ onChange(newValues.length > 0 ? newValues : []);
5111
+ },
5112
+ [selectedValues, onChange, dataType]
5113
+ );
5114
+ const handleMultiOptionSelect = useCallback(
5115
+ (optionValue) => {
5116
+ if (selectedValues.includes(optionValue)) {
5117
+ removeMultiValue(optionValue);
5118
+ } else {
5119
+ addMultiValue(optionValue);
5120
+ }
5121
+ setMultiInputText("");
5122
+ updateDropdownPosition();
5123
+ inputRef.current?.focus();
5124
+ },
5125
+ [selectedValues, addMultiValue, removeMultiValue, updateDropdownPosition]
5126
+ );
5127
+ const handleMultiInputKeyDown = useCallback(
5128
+ (e) => {
5129
+ if (e.key === "Backspace" && multiInputText === "" && selectedValues.length > 0) {
5130
+ const lastVal = selectedValues[selectedValues.length - 1];
5131
+ if (lastVal !== void 0) removeMultiValue(lastVal);
5132
+ return;
5133
+ }
5134
+ if (isDropdownOpen && filteredOptions.length > 0) {
5135
+ switch (e.key) {
5136
+ case "ArrowDown":
5137
+ e.preventDefault();
5138
+ setHighlightedIndex((prev) => Math.min(prev + 1, filteredOptions.length - 1));
5139
+ return;
5140
+ case "ArrowUp":
5141
+ e.preventDefault();
5142
+ setHighlightedIndex((prev) => Math.max(prev - 1, 0));
5143
+ return;
5144
+ case "Enter":
5145
+ e.preventDefault();
5146
+ if (highlightedIndex >= 0 && filteredOptions[highlightedIndex]) {
5147
+ handleMultiOptionSelect(filteredOptions[highlightedIndex]);
5148
+ } else if (multiInputText.trim()) {
5149
+ addMultiValue(multiInputText);
5150
+ }
5151
+ return;
5152
+ case "Escape":
5153
+ setIsDropdownOpen(false);
5154
+ return;
5155
+ }
5156
+ }
5157
+ if (e.key === "," || e.key === "Enter") {
5158
+ e.preventDefault();
5159
+ addMultiValue(multiInputText);
5160
+ }
5161
+ },
5162
+ [
5163
+ multiInputText,
5164
+ selectedValues,
5165
+ isDropdownOpen,
5166
+ filteredOptions,
5167
+ highlightedIndex,
5168
+ addMultiValue,
5169
+ removeMultiValue,
5170
+ handleMultiOptionSelect
5171
+ ]
5172
+ );
5173
+ const handleSingleKeyDown = useCallback(
5174
+ (e) => {
5175
+ if (!isDropdownOpen || filteredOptions.length === 0) return;
5176
+ switch (e.key) {
5177
+ case "ArrowDown":
5178
+ e.preventDefault();
5179
+ setHighlightedIndex((prev) => Math.min(prev + 1, filteredOptions.length - 1));
5180
+ break;
5181
+ case "ArrowUp":
5182
+ e.preventDefault();
5183
+ setHighlightedIndex((prev) => Math.max(prev - 1, 0));
5184
+ break;
5185
+ case "Enter":
5186
+ e.preventDefault();
5187
+ if (highlightedIndex >= 0 && filteredOptions[highlightedIndex]) {
5188
+ handleOptionSelect(filteredOptions[highlightedIndex]);
5189
+ }
5190
+ break;
5191
+ case "Escape":
5192
+ setIsDropdownOpen(false);
5193
+ break;
5194
+ }
5195
+ },
5196
+ [isDropdownOpen, filteredOptions, highlightedIndex, handleOptionSelect]
5197
+ );
4875
5198
  if (operator === "is_null" || operator === "is_not_null") {
4876
5199
  return /* @__PURE__ */ jsx(Fragment, {});
4877
5200
  }
@@ -4911,36 +5234,163 @@ function FilterValueInput({
4911
5234
  )
4912
5235
  ] });
4913
5236
  }
4914
- if (operator === "in_" || operator === "not_in" || operator === "in_or_null") {
4915
- const handleMultiChange = (e) => {
4916
- const values = e.target.value.split(",").map((v) => v.trim()).filter(Boolean).map((v) => parseValue(v, dataType));
4917
- onChange(values);
4918
- };
4919
- return /* @__PURE__ */ jsx("div", { className, style: containerStyles7, children: /* @__PURE__ */ jsx(
5237
+ if (isMulti) {
5238
+ return /* @__PURE__ */ jsx("div", { className, style: containerStyles7, children: /* @__PURE__ */ jsxs("div", { ref: containerRef, style: comboboxContainerStyles, children: [
5239
+ /* @__PURE__ */ jsxs(
5240
+ "div",
5241
+ {
5242
+ "data-testid": "filter-tag-container",
5243
+ style: tagContainerStyles,
5244
+ onClick: () => inputRef.current?.focus(),
5245
+ children: [
5246
+ selectedValues.map((val) => /* @__PURE__ */ jsxs("span", { "data-testid": `filter-tag-${val}`, style: tagStyles, children: [
5247
+ val,
5248
+ /* @__PURE__ */ jsx(
5249
+ "button",
5250
+ {
5251
+ type: "button",
5252
+ "data-testid": `filter-tag-remove-${val}`,
5253
+ style: tagRemoveStyles,
5254
+ onClick: (e) => {
5255
+ e.stopPropagation();
5256
+ removeMultiValue(val);
5257
+ },
5258
+ tabIndex: -1,
5259
+ children: "\xD7"
5260
+ }
5261
+ )
5262
+ ] }, val)),
5263
+ /* @__PURE__ */ jsx(
5264
+ "input",
5265
+ {
5266
+ ref: inputRef,
5267
+ "data-testid": "filter-multi-input",
5268
+ type: "text",
5269
+ placeholder: selectedValues.length === 0 ? isLoadingValues ? "Loading..." : "Type or select values" : "",
5270
+ value: multiInputText,
5271
+ disabled: disabled || isLoadingValues,
5272
+ onChange: (e) => {
5273
+ setMultiInputText(e.target.value);
5274
+ if (sampleValues.length > 0) {
5275
+ updateDropdownPosition();
5276
+ setIsDropdownOpen(true);
5277
+ setHighlightedIndex(-1);
5278
+ }
5279
+ },
5280
+ onFocus: handleInputFocus,
5281
+ onKeyDown: handleMultiInputKeyDown,
5282
+ style: tagInputStyles
5283
+ }
5284
+ )
5285
+ ]
5286
+ }
5287
+ ),
5288
+ selectedValues.length === 0 && !multiInputText && /* @__PURE__ */ jsxs("div", { "data-testid": "filter-multi-hint", style: {
5289
+ fontSize: "11px",
5290
+ color: "var(--prismiq-color-text-muted)",
5291
+ marginTop: "2px",
5292
+ paddingLeft: "2px"
5293
+ }, children: [
5294
+ "Press ",
5295
+ /* @__PURE__ */ jsx("kbd", { style: { padding: "0 3px", border: "1px solid var(--prismiq-color-border)", borderRadius: "3px", fontSize: "10px" }, children: "," }),
5296
+ " or ",
5297
+ /* @__PURE__ */ jsx("kbd", { style: { padding: "0 3px", border: "1px solid var(--prismiq-color-border)", borderRadius: "3px", fontSize: "10px" }, children: "Enter" }),
5298
+ " to add values"
5299
+ ] }),
5300
+ isDropdownOpen && filteredOptions.length > 0 && typeof document !== "undefined" && createPortal(
5301
+ /* @__PURE__ */ jsx(
5302
+ "div",
5303
+ {
5304
+ ref: dropdownRef,
5305
+ "data-testid": "filter-dropdown",
5306
+ style: {
5307
+ ...dropdownStyles2,
5308
+ top: dropdownPosition.top,
5309
+ left: dropdownPosition.left,
5310
+ width: dropdownPosition.width
5311
+ },
5312
+ children: filteredOptions.map((optionValue, index) => {
5313
+ const isSelected = selectedValues.includes(optionValue);
5314
+ return /* @__PURE__ */ jsxs(
5315
+ "div",
5316
+ {
5317
+ "data-testid": `filter-option-${index}`,
5318
+ onClick: () => handleMultiOptionSelect(optionValue),
5319
+ onMouseEnter: () => setHighlightedIndex(index),
5320
+ style: {
5321
+ ...optionStyles2,
5322
+ ...index === highlightedIndex ? optionHoverStyles2 : {},
5323
+ ...isSelected ? { backgroundColor: "var(--prismiq-color-surface)", fontWeight: 500 } : {}
5324
+ },
5325
+ children: [
5326
+ /* @__PURE__ */ jsx("span", { style: multiOptionCheckStyles, children: isSelected ? "\u2713" : "\u2003" }),
5327
+ optionValue
5328
+ ]
5329
+ },
5330
+ `${optionValue}-${index}`
5331
+ );
5332
+ })
5333
+ }
5334
+ ),
5335
+ document.body
5336
+ )
5337
+ ] }) });
5338
+ }
5339
+ return /* @__PURE__ */ jsx("div", { className, style: containerStyles7, children: /* @__PURE__ */ jsxs("div", { ref: containerRef, style: comboboxContainerStyles, children: [
5340
+ /* @__PURE__ */ jsx(
4920
5341
  Input,
4921
5342
  {
5343
+ ref: inputRef,
5344
+ "data-testid": "filter-single-input",
4922
5345
  inputSize: "sm",
4923
- type: "text",
4924
- placeholder: "value1, value2, ...",
4925
- value: formatValue(value),
4926
- disabled,
4927
- onChange: handleMultiChange,
4928
- style: { flex: 1 }
5346
+ type: inputType,
5347
+ placeholder: isLoadingValues ? "Loading..." : "Type or select value",
5348
+ value: currentValueStr,
5349
+ disabled: disabled || isLoadingValues,
5350
+ onChange: (e) => {
5351
+ onChange(parseValue(e.target.value, dataType));
5352
+ if (sampleValues.length > 0) {
5353
+ updateDropdownPosition();
5354
+ setIsDropdownOpen(true);
5355
+ }
5356
+ },
5357
+ onFocus: handleInputFocus,
5358
+ onKeyDown: handleSingleKeyDown,
5359
+ style: { width: "100%" }
4929
5360
  }
4930
- ) });
4931
- }
4932
- return /* @__PURE__ */ jsx("div", { className, style: containerStyles7, children: /* @__PURE__ */ jsx(
4933
- Input,
4934
- {
4935
- inputSize: "sm",
4936
- type: inputType,
4937
- placeholder: "Value",
4938
- value: formatValue(value),
4939
- disabled,
4940
- onChange: (e) => onChange(parseValue(e.target.value, dataType)),
4941
- style: { flex: 1 }
4942
- }
4943
- ) });
5361
+ ),
5362
+ isDropdownOpen && filteredOptions.length > 0 && typeof document !== "undefined" && createPortal(
5363
+ /* @__PURE__ */ jsx(
5364
+ "div",
5365
+ {
5366
+ ref: dropdownRef,
5367
+ "data-testid": "filter-dropdown",
5368
+ style: {
5369
+ ...dropdownStyles2,
5370
+ top: dropdownPosition.top,
5371
+ left: dropdownPosition.left,
5372
+ width: dropdownPosition.width
5373
+ },
5374
+ children: filteredOptions.map((optionValue, index) => /* @__PURE__ */ jsx(
5375
+ "div",
5376
+ {
5377
+ "data-testid": `filter-option-${index}`,
5378
+ onClick: () => handleOptionSelect(optionValue),
5379
+ onMouseEnter: () => setHighlightedIndex(index),
5380
+ style: {
5381
+ ...optionStyles2,
5382
+ ...index === highlightedIndex ? optionHoverStyles2 : {},
5383
+ ...optionValue === currentValueStr ? { backgroundColor: "var(--prismiq-color-surface)", fontWeight: 500 } : {}
5384
+ },
5385
+ children: optionValue
5386
+ },
5387
+ `${optionValue}-${index}`
5388
+ ))
5389
+ }
5390
+ ),
5391
+ document.body
5392
+ )
5393
+ ] }) });
4944
5394
  }
4945
5395
  var rowStyles = {
4946
5396
  display: "flex",
@@ -5033,13 +5483,16 @@ function FilterRow({
5033
5483
  });
5034
5484
  return options;
5035
5485
  }, [tables, schema]);
5486
+ const currentTable = useMemo(
5487
+ () => tables.find((t) => t.id === filter.table_id),
5488
+ [tables, filter.table_id]
5489
+ );
5036
5490
  const currentColumnSchema = useMemo(() => {
5037
- const table = tables.find((t) => t.id === filter.table_id);
5038
- if (!table) return void 0;
5039
- const tableSchema = schema.tables.find((t) => t.name === table.name);
5491
+ if (!currentTable) return void 0;
5492
+ const tableSchema = schema.tables.find((t) => t.name === currentTable.name);
5040
5493
  if (!tableSchema) return void 0;
5041
5494
  return tableSchema.columns.find((c) => c.name === filter.column);
5042
- }, [tables, schema, filter.table_id, filter.column]);
5495
+ }, [currentTable, schema, filter.column]);
5043
5496
  const operatorOptions = useMemo(
5044
5497
  () => getOperatorsForType(currentColumnSchema?.data_type),
5045
5498
  [currentColumnSchema]
@@ -5100,7 +5553,9 @@ function FilterRow({
5100
5553
  operator: filter.operator,
5101
5554
  value: filter.value,
5102
5555
  onChange: handleValueChange,
5103
- dataType: currentColumnSchema?.data_type
5556
+ dataType: currentColumnSchema?.data_type,
5557
+ tableName: currentTable?.name,
5558
+ columnName: filter.column
5104
5559
  }
5105
5560
  ) }),
5106
5561
  /* @__PURE__ */ jsx(
@@ -8541,13 +8996,14 @@ function TableSelector({
8541
8996
  className
8542
8997
  }) {
8543
8998
  const { theme } = useTheme();
8999
+ const { getDisplayName } = useSchema();
8544
9000
  const availableTableOptions = useMemo(() => {
8545
9001
  const selectedNames = new Set(tables.map((t) => t.name));
8546
9002
  return schema.tables.filter((t) => !selectedNames.has(t.name)).map((t) => ({
8547
9003
  value: t.name,
8548
- label: `${t.name} (${t.columns.length} cols)`
9004
+ label: getDisplayName(t.name)
8549
9005
  }));
8550
- }, [schema.tables, tables]);
9006
+ }, [schema.tables, tables, getDisplayName]);
8551
9007
  const suggestedTables = useMemo(() => {
8552
9008
  if (!showRelationships || tables.length === 0) return [];
8553
9009
  const selectedNames = new Set(tables.map((t) => t.name));
@@ -8649,7 +9105,7 @@ function TableSelector({
8649
9105
  return /* @__PURE__ */ jsxs("div", { className, style: containerStyle, children: [
8650
9106
  tables.length > 0 && /* @__PURE__ */ jsx("div", { style: selectedTablesStyle, children: tables.map((table, index) => /* @__PURE__ */ jsxs("div", { style: tableChipStyle, children: [
8651
9107
  /* @__PURE__ */ jsx(Icon, { name: "table", size: 14 }),
8652
- /* @__PURE__ */ jsx("span", { children: table.name }),
9108
+ /* @__PURE__ */ jsx("span", { children: getDisplayName(table.name) }),
8653
9109
  index === 0 && /* @__PURE__ */ jsx(Badge, { size: "sm", variant: "default", children: "primary" }),
8654
9110
  tables.length > 1 && /* @__PURE__ */ jsx(
8655
9111
  "button",
@@ -8657,7 +9113,7 @@ function TableSelector({
8657
9113
  type: "button",
8658
9114
  style: removeButtonStyle,
8659
9115
  onClick: () => handleRemoveTable(table.id),
8660
- "aria-label": `Remove ${table.name}`,
9116
+ "aria-label": `Remove ${getDisplayName(table.name)}`,
8661
9117
  children: /* @__PURE__ */ jsx(Icon, { name: "x", size: 12 })
8662
9118
  }
8663
9119
  )
@@ -8691,7 +9147,7 @@ function TableSelector({
8691
9147
  title: suggestion.relationship,
8692
9148
  children: [
8693
9149
  /* @__PURE__ */ jsx(Icon, { name: "plus", size: 10 }),
8694
- suggestion.table
9150
+ getDisplayName(suggestion.table)
8695
9151
  ]
8696
9152
  },
8697
9153
  suggestion.table
@@ -8702,5 +9158,5 @@ function TableSelector({
8702
9158
  }
8703
9159
 
8704
9160
  export { AggregationPicker, AnalyticsProvider, AutoSaveIndicator, Badge, Button, CalculatedFieldBuilder, Checkbox, CollapsibleSection, ColorPaletteSelector, ColumnNode, ColumnSelector, CrossFilterProvider, CustomSQLEditor, Dialog, DialogFooter, DialogHeader, Dropdown, DropdownItem, DropdownSeparator, EmptyDashboard, EmptyState, ErrorBoundary, ErrorFallback, ExpressionEditor, FilterBuilder, FilterRow, FilterValueInput, Icon, Input, JoinBuilder, JoinRow, NoData, NoResults, Pagination, PrismiqClient, PrismiqError, QueryBuilder, QueryBuilderToolbar, QueryPreview, ResultsTable, SavedQueryPicker, SchemaExplorer, Select, SelectedColumn, Skeleton, SkeletonChart, SkeletonMetricCard, SkeletonTable, SkeletonText, SortBuilder, SortRow, TableCell, TableHeader, TableNode, TableRow, TableSelector, TimeSeriesConfig, Tooltip, WidgetErrorBoundary, useAnalytics, useAnalyticsCallbacks, useChartData, useCrossFilterOptional, useCustomSQL, useDashboard, useDashboardMutations, useDashboardPinStatus, useDashboards, useDebouncedLayoutSave, usePinMutations, usePinnedDashboards, useQuery, useSavedQueries, useSchema };
8705
- //# sourceMappingURL=chunk-UPYINBZU.js.map
8706
- //# sourceMappingURL=chunk-UPYINBZU.js.map
9161
+ //# sourceMappingURL=chunk-ET7GCREP.js.map
9162
+ //# sourceMappingURL=chunk-ET7GCREP.js.map