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