@datawheel/data-explorer 0.1.3 → 0.2.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 (2) hide show
  1. package/dist/main.js +98 -26
  2. package/package.json +1 -1
package/dist/main.js CHANGED
@@ -14,7 +14,7 @@ import formUrlEncode from 'form-urlencoded';
14
14
  import formUrlDecode from 'form-urldecoded';
15
15
  import { MRT_ProgressBar, flexRender, MRT_TableBodyCell, MRT_ToolbarAlertBanner, useMantineReactTable, MantineReactTable, MRT_TablePagination } from 'mantine-react-table';
16
16
  import { formatAbbreviate, format } from 'd3plus-format';
17
- import { QueryClient, QueryClientProvider, useQuery } from '@tanstack/react-query';
17
+ import { QueryClient, QueryClientProvider, useQuery, useQueryClient } from '@tanstack/react-query';
18
18
  import debounce from 'lodash.debounce';
19
19
  import { matchSorter } from 'match-sorter';
20
20
  import yn from 'yn';
@@ -1703,7 +1703,7 @@ function willDownloadQuery(format2) {
1703
1703
  const dataURL = query.toString("logiclayer").replace(olapClient.datasource.serverUrl, "");
1704
1704
  return Promise.all([
1705
1705
  axios({ url: dataURL, responseType: "blob" }).then((response) => response.data),
1706
- calcMaxMemberCount(query, params).then((maxRows) => {
1706
+ calcMaxMemberCount(query, params, dispatch).then((maxRows) => {
1707
1707
  if (maxRows > 5e4) {
1708
1708
  dispatch(loadingActions.setLoadingMessage({ type: "HEAVY_QUERY", rows: maxRows }));
1709
1709
  }
@@ -1725,10 +1725,19 @@ function willExecuteQuery({ limit, offset } = {}) {
1725
1725
  const allParams = isPrefetch ? { ...params, pagiLimit: limit, pagiOffset: offset } : params;
1726
1726
  const { result: currentResult } = selectCurrentQueryItem(state);
1727
1727
  if (!isValidQuery(params)) return Promise.resolve();
1728
- return olapClient.getCube(params.cube).then((cube) => {
1728
+ return olapClient.getCube(params.cube).then(async (cube) => {
1729
1729
  const query = applyQueryParams(cube.query, allParams, { previewLimit });
1730
+ const axios = olapClient.datasource.axiosInstance;
1731
+ const dataURL = query.toString("logiclayer").replace(olapClient.datasource.serverUrl, "");
1730
1732
  return Promise.all([
1731
- olapClient.execQuery(query, endpoint),
1733
+ axios({ url: dataURL }).then((response) => {
1734
+ return {
1735
+ data: response.data,
1736
+ headers: { ...response.headers },
1737
+ query,
1738
+ status: response.status
1739
+ };
1740
+ }),
1732
1741
  calcMaxMemberCount(query, allParams, dispatch).then((maxRows) => {
1733
1742
  if (maxRows > 5e4) {
1734
1743
  dispatch(loadingActions.setLoadingMessage({ type: "HEAVY_QUERY", rows: maxRows }));
@@ -1737,19 +1746,20 @@ function willExecuteQuery({ limit, offset } = {}) {
1737
1746
  ]).then(
1738
1747
  (result) => {
1739
1748
  const [aggregation] = result;
1749
+ const { data, headers, status } = aggregation;
1740
1750
  !isPrefetch && dispatch(
1741
1751
  queriesActions.updateResult({
1742
- data: aggregation.data,
1743
- types: aggregation.data.length ? describeData(cube.toJSON(), params, aggregation.data) : currentResult.types,
1744
- headers: { ...aggregation.headers },
1752
+ data,
1753
+ types: (data == null ? void 0 : data.data.length) ? describeData(cube.toJSON(), params, data == null ? void 0 : data.data) : currentResult.types,
1754
+ headers: { ...headers },
1745
1755
  sourceCall: query.toSource(),
1746
- status: aggregation.status || 500,
1756
+ status: status || 500,
1747
1757
  url: query.toString(endpoint)
1748
1758
  })
1749
1759
  );
1750
1760
  return {
1751
- data: aggregation.data,
1752
- types: aggregation.data.length ? describeData(cube.toJSON(), params, aggregation.data) : currentResult.types
1761
+ data,
1762
+ types: (data == null ? void 0 : data.data.length) ? describeData(cube.toJSON(), params, data == null ? void 0 : data.data) : currentResult.types
1753
1763
  };
1754
1764
  },
1755
1765
  (error) => {
@@ -2437,11 +2447,16 @@ function CubeSource() {
2437
2447
 
2438
2448
  // src/components/TableFooter.tsx
2439
2449
  function TableFooter(props) {
2440
- const { result, table, data = [] } = props;
2450
+ const { result, table } = props;
2441
2451
  const { translate: t } = useTranslation();
2442
2452
  const { url } = result;
2443
2453
  const { copy, copied } = useClipboard({ timeout: 1e3 });
2444
2454
  const copyHandler = useCallback(() => copy(url), [url]);
2455
+ const totalRowCount = table.options.rowCount;
2456
+ const {
2457
+ pagination: { pageSize }
2458
+ } = table.getState();
2459
+ const showPagination = totalRowCount && Boolean(totalRowCount > pageSize);
2445
2460
  return /* @__PURE__ */ React10__default.createElement(Box, { w: "100%", sx: { flex: "0 0 70px" } }, /* @__PURE__ */ React10__default.createElement(
2446
2461
  Flex,
2447
2462
  {
@@ -2452,7 +2467,7 @@ function TableFooter(props) {
2452
2467
  gap: "sm"
2453
2468
  },
2454
2469
  /* @__PURE__ */ React10__default.createElement(CubeSource, null),
2455
- /* @__PURE__ */ React10__default.createElement(Group, { position: "right", spacing: "sm" }, /* @__PURE__ */ React10__default.createElement(Text, { c: "dimmed" }, t("results.count_rows", { n: data.length })), /* @__PURE__ */ React10__default.createElement(MRT_TablePagination, { table }), /* @__PURE__ */ React10__default.createElement(ApiAndCsvButtons, { copied, copyHandler, url }))
2470
+ /* @__PURE__ */ React10__default.createElement(Group, { position: "right", spacing: "sm" }, /* @__PURE__ */ React10__default.createElement(Text, { c: "dimmed" }, t("results.count_rows", { n: totalRowCount })), showPagination && /* @__PURE__ */ React10__default.createElement(MRT_TablePagination, { table }), /* @__PURE__ */ React10__default.createElement(ApiAndCsvButtons, { copied, copyHandler, url }))
2456
2471
  ));
2457
2472
  }
2458
2473
  var ApiAndCsvButtons = (props) => {
@@ -3149,7 +3164,7 @@ function getFiltersConditions(fn, value) {
3149
3164
  ]);
3150
3165
  return (_a = comparisonMap.get(fn)) == null ? void 0 : _a(value);
3151
3166
  }
3152
- function useTableData({ offset, limit, columns, filters, cuts }) {
3167
+ function useTableData({ offset, limit, columns, filters, cuts, pagination }) {
3153
3168
  const normalizedFilters = filters.map((filter) => ({
3154
3169
  id: filter.measure,
3155
3170
  value: getFilterValue(filter)
@@ -3160,10 +3175,8 @@ function useTableData({ offset, limit, columns, filters, cuts }) {
3160
3175
  const cutKey = JSON.stringify(normalizedCuts);
3161
3176
  const actions2 = useActions();
3162
3177
  const columnsStr = JSON.stringify(columns.sort());
3163
- const page = offset;
3178
+ const page = pagination.pageIndex;
3164
3179
  const [filterKeydebouced, setDebouncedTerm] = useState([
3165
- limit,
3166
- offset,
3167
3180
  columnsStr,
3168
3181
  filterKey,
3169
3182
  cutKey,
@@ -3171,7 +3184,7 @@ function useTableData({ offset, limit, columns, filters, cuts }) {
3171
3184
  ]);
3172
3185
  useEffect(() => {
3173
3186
  const handler = debounce(() => {
3174
- const term = [limit, offset, columnsStr, filterKey, cutKey, page];
3187
+ const term = [columnsStr, filterKey, cutKey, page];
3175
3188
  setDebouncedTerm(term);
3176
3189
  }, 700);
3177
3190
  handler();
@@ -3182,13 +3195,56 @@ function useTableData({ offset, limit, columns, filters, cuts }) {
3182
3195
  queryFn: () => {
3183
3196
  return actions2.willExecuteQuery().then((res) => {
3184
3197
  const { data, types } = res;
3185
- return { data: data != null ? data : [], types };
3198
+ const { data: tableData, page: page2 } = data;
3199
+ return { data: tableData != null ? tableData : [], types, page: page2 };
3186
3200
  });
3187
3201
  },
3188
3202
  staleTime: 3e5,
3189
3203
  enabled: !!filterKeydebouced
3190
3204
  });
3191
3205
  }
3206
+ function usePrefetch({
3207
+ data,
3208
+ isPlaceholderData,
3209
+ limit,
3210
+ offset,
3211
+ totalRowCount,
3212
+ columns,
3213
+ cuts,
3214
+ filters,
3215
+ pagination
3216
+ }) {
3217
+ const queryClient2 = useQueryClient();
3218
+ const actions2 = useActions();
3219
+ const page = pagination.pageIndex + 1;
3220
+ const hasMore = page * pagination.pageSize <= totalRowCount;
3221
+ const off = page * pagination.pageSize;
3222
+ const normalizedFilters = filters.map((filter) => ({
3223
+ id: filter.measure,
3224
+ value: getFilterValue(filter)
3225
+ // fn: getFilterFn(filter)
3226
+ }));
3227
+ const normalizedCuts = cuts.map((cut) => ({ id: cut.uniqueName, members: cut.members }));
3228
+ const filterKey = JSON.stringify(normalizedFilters);
3229
+ const cutKey = JSON.stringify(normalizedCuts);
3230
+ const columnsStr = JSON.stringify(columns.sort());
3231
+ const key = [columnsStr, filterKey, cutKey, page];
3232
+ React10__default.useEffect(() => {
3233
+ if (!isPlaceholderData && hasMore) {
3234
+ queryClient2.prefetchQuery({
3235
+ queryKey: ["table", key],
3236
+ queryFn: () => {
3237
+ return actions2.willExecuteQuery({ offset: off, limit }).then((res) => {
3238
+ const { data: data2, types } = res;
3239
+ const { data: tableData, page: page2 } = data2;
3240
+ return { data: tableData != null ? tableData : [], types, page: page2 };
3241
+ });
3242
+ },
3243
+ staleTime: 3e5
3244
+ });
3245
+ }
3246
+ }, [data, limit, offset, page, isPlaceholderData, key, queryClient2, hasMore, off]);
3247
+ }
3192
3248
  function useTable({
3193
3249
  cube,
3194
3250
  result,
@@ -3239,18 +3295,29 @@ function useTable({
3239
3295
  return { measure, filter };
3240
3296
  });
3241
3297
  }, [measuresMap, measuresOlap, filtersMap, filterItems]);
3242
- const { isLoading, isFetching, isError, data } = useTableData({
3298
+ const { isLoading, isFetching, isError, data, isPlaceholderData } = useTableData({
3243
3299
  offset,
3244
3300
  limit,
3245
3301
  columns: finalUniqueKeys,
3246
3302
  filters: filterItems.filter(isActiveItem),
3247
- cuts: itemsCuts.filter(isActiveCut)
3303
+ cuts: itemsCuts.filter(isActiveCut),
3304
+ pagination
3248
3305
  });
3249
3306
  const tableData = (data == null ? void 0 : data.data) || [];
3250
3307
  const tableTypes = (data == null ? void 0 : data.types) || types;
3308
+ const totalRowCount = data == null ? void 0 : data.page.total;
3251
3309
  const finalKeys = Object.values(tableTypes).filter((t2) => !t2.isId).filter(columnFilter).sort(columnSorting);
3252
- const totalRowCount = result.data.length === limit ? limit * 10 : result.data.length;
3253
- const fetchedTableData = tableData != null ? tableData : [];
3310
+ usePrefetch({
3311
+ data: tableData,
3312
+ isPlaceholderData,
3313
+ offset,
3314
+ limit,
3315
+ totalRowCount,
3316
+ columns: finalUniqueKeys,
3317
+ filters: filterItems.filter(isActiveItem),
3318
+ cuts: itemsCuts.filter(isActiveCut),
3319
+ pagination
3320
+ });
3254
3321
  useEffect(() => {
3255
3322
  actions2.updatePagination({
3256
3323
  limit: pagination.pageSize,
@@ -3426,7 +3493,7 @@ function useTable({
3426
3493
  );
3427
3494
  const table = useMantineReactTable({
3428
3495
  columns,
3429
- data: fetchedTableData,
3496
+ data: tableData,
3430
3497
  onPaginationChange: setPagination,
3431
3498
  enableHiding: false,
3432
3499
  manualFiltering: true,
@@ -3442,7 +3509,7 @@ function useTable({
3442
3509
  ...constTableProps,
3443
3510
  ...mantineTableProps
3444
3511
  });
3445
- return { table, isError, isLoading, data: fetchedTableData };
3512
+ return { table, isError, isLoading, data: tableData };
3446
3513
  }
3447
3514
  function TableView({ table, result, isError, isLoading, data }) {
3448
3515
  const isData = Boolean(table.getRowModel().rows.length);
@@ -4097,7 +4164,6 @@ function LocaleSelector() {
4097
4164
  if (currentCode !== l.value) {
4098
4165
  resetGraph();
4099
4166
  actions2.updateLocale(l.value);
4100
- actions2.willRequestQuery();
4101
4167
  }
4102
4168
  };
4103
4169
  if (localeOptions.length < 2) {
@@ -4113,7 +4179,13 @@ function LocaleSelector() {
4113
4179
  selectedItem: currentCode,
4114
4180
  selectProps: {
4115
4181
  styles: localeSelectorStyle,
4116
- icon: /* @__PURE__ */ React10__default.createElement(IconLanguage, { size: "0.8rem", color: theme.colorScheme === "dark" ? theme.fn.lighten(theme.fn.primaryColor(), 0.8) : theme.fn.primaryColor() })
4182
+ icon: /* @__PURE__ */ React10__default.createElement(
4183
+ IconLanguage,
4184
+ {
4185
+ size: "0.8rem",
4186
+ color: theme.colorScheme === "dark" ? theme.fn.lighten(theme.fn.primaryColor(), 0.8) : theme.fn.primaryColor()
4187
+ }
4188
+ )
4117
4189
  }
4118
4190
  }
4119
4191
  )));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@datawheel/data-explorer",
3
- "version": "0.1.3",
3
+ "version": "0.2.1",
4
4
  "exports": {
5
5
  ".": {
6
6
  "import": "./dist/main.js"