flowerbi-react 1.19.0 → 2.0.0

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/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Defines hooks for working with FlowerBI from React applications:
4
4
 
5
- - `useQuery` - the state of a query and the data it produces
5
+ - `useFlowerBI` - the state of a query and the data it produces
6
6
  - `usePageFilters` - a shared set of filters that chart components can interact via
7
7
 
8
8
  Also some components:
@@ -1,4 +1,3 @@
1
- /// <reference types="react" />
2
1
  import { QueryValues, ExpandedQueryResult, QuerySelect } from "flowerbi";
3
2
  export declare type ColumnDefinition = string | [string, "left" | "right"];
4
3
  export declare type FlowerBITableProps<S extends QuerySelect> = {
@@ -3,6 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.FlowerBITable = void 0;
6
7
  var react_1 = __importDefault(require("react"));
7
8
  var flowerbi_1 = require("flowerbi");
8
9
  function renderCell(key, def) {
@@ -1 +1 @@
1
- {"version":3,"file":"FlowerBITable.js","sourceRoot":"","sources":["../src/FlowerBITable.tsx"],"names":[],"mappings":";;;;;AAAA,gDAA0B;AAC1B,qCAA2G;AAI3G,SAAS,UAAU,CAAC,GAAW,EAAE,GAAqB;IAClD,IAAM,KAAK,GAAG,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IACrD,IAAM,KAAK,GAAG,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IAExD,OAAO,CACH,sCAAI,GAAG,EAAE,GAAG,EAAE,SAAS,EAAE,KAAK,IACzB,KAAK,CACL,CACR,CAAC;AACN,CAAC;AASD,SAAgB,aAAa,CAAwB,EAAsC;QAArC,cAAI,EAAE,oBAAO;IAC/D,OAAO,CACH;QACI;YACI,0CACK,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,UAAC,MAAM,IAAK,OAAA,CAClC,sCAAI,GAAG,EAAE,MAAM,IAAG,MAAM,CAAM,CACjC,EAFqC,CAErC,CAAC,CACD,CACD;QACR,6CACK,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,UAAC,MAAM,EAAE,CAAC;;YAAK,OAAA,CAC7B,sCAAI,GAAG,QAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,mCAAI,CAAC,IAEzC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,UAAC,MAAM,IAAK,OAAA,UAAU,CAC3C,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,yBAAc,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EADhC,CACgC,CAAC,CAErE,CACR,CAAA;SAAA,CAAC,CACE;QACP,IAAI,CAAC,MAAM,IAAI,CACZ;YACI,0CAEI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,UAAC,MAAM,IAAK,OAAA,UAAU,CAC3C,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,2BAAgB,CAAC,IAAI,CAAC,MAAO,CAAC,CAAC,CAAC,EAD3B,CAC2B,CAAC,CAEhE,CACD,CACX,CACG,CACX,CAAC;AACN,CAAC;AAhCD,sCAgCC"}
1
+ {"version":3,"file":"FlowerBITable.js","sourceRoot":"","sources":["../src/FlowerBITable.tsx"],"names":[],"mappings":";;;;;;AAAA,gDAA0B;AAC1B,qCAA2G;AAI3G,SAAS,UAAU,CAAC,GAAW,EAAE,GAAqB;IAClD,IAAM,KAAK,GAAG,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IACrD,IAAM,KAAK,GAAG,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IAExD,OAAO,CACH,sCAAI,GAAG,EAAE,GAAG,EAAE,SAAS,EAAE,KAAK,IACzB,KAAK,CACL,CACR,CAAC;AACN,CAAC;AASD,SAAgB,aAAa,CAAwB,EAAsC;QAArC,IAAI,UAAA,EAAE,OAAO,aAAA;IAC/D,OAAO,CACH;QACI;YACI,0CACK,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,UAAC,MAAM,IAAK,OAAA,CAClC,sCAAI,GAAG,EAAE,MAAM,IAAG,MAAM,CAAM,CACjC,EAFqC,CAErC,CAAC,CACD,CACD;QACR,6CACK,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,UAAC,MAAM,EAAE,CAAC;;YAAK,OAAA,CAC7B,sCAAI,GAAG,EAAE,MAAA,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,mCAAI,CAAC,IAEzC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,UAAC,MAAM,IAAK,OAAA,UAAU,CAC3C,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,yBAAc,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EADhC,CACgC,CAAC,CAErE,CACR,CAAA;SAAA,CAAC,CACE;QACP,IAAI,CAAC,MAAM,IAAI,CACZ;YACI,0CAEI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,UAAC,MAAM,IAAK,OAAA,UAAU,CAC3C,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,2BAAgB,CAAC,IAAI,CAAC,MAAO,CAAC,CAAC,CAAC,EAD3B,CAC2B,CAAC,CAEhE,CACD,CACX,CACG,CACX,CAAC;AACN,CAAC;AAhCD,sCAgCC"}
package/dist/index.d.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  export * from "./FlowerBITable";
2
2
  export * from "./usePageFilters";
3
- export * from "./useQuery";
3
+ export * from "./useFlowerBI";
package/dist/index.js CHANGED
@@ -1,9 +1,16 @@
1
1
  "use strict";
2
- function __export(m) {
3
- for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
4
- }
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
5
+ }) : (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ o[k2] = m[k];
8
+ }));
9
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
10
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
11
+ };
5
12
  Object.defineProperty(exports, "__esModule", { value: true });
6
- __export(require("./FlowerBITable"));
7
- __export(require("./usePageFilters"));
8
- __export(require("./useQuery"));
13
+ __exportStar(require("./FlowerBITable"), exports);
14
+ __exportStar(require("./usePageFilters"), exports);
15
+ __exportStar(require("./useFlowerBI"), exports);
9
16
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;AAAA,qCAAgC;AAChC,sCAAiC;AACjC,gCAA2B"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,kDAAgC;AAChC,mDAAiC;AACjC,gDAA8B"}
@@ -0,0 +1,50 @@
1
+ import { Query, QueryFetch, QuerySelect, ExpandedQueryResult } from "flowerbi";
2
+ export declare type UseQueryState = "init" | "ready" | "refresh" | "error";
3
+ export interface UseQueryResult<S extends QuerySelect> extends ExpandedQueryResult<S> {
4
+ /**
5
+ * The state of the query operation:
6
+ *
7
+ * - `init` - no result has been downloaded yet
8
+ * - `ready` - result has been downloaded
9
+ * - `refresh` - a new result is being downloaded
10
+ * - `error` - most recent query attempt failed
11
+ */
12
+ state: UseQueryState;
13
+ }
14
+ /**
15
+ * Defines another query on which our query depends - for example a
16
+ * first query may return the top 10 vendors, and a subsequent query
17
+ * may then use an `in` filter to get details about those 10 vendors.
18
+ */
19
+ export declare type QueryDependency = {
20
+ /**
21
+ * The result of the query we depend on
22
+ */
23
+ dependency: UseQueryResult<QuerySelect>;
24
+ /**
25
+ * If true (default is false) then if the dependency query produces
26
+ * an empty result, our query should also produce an empty result,
27
+ * so there is no need to execute it.
28
+ */
29
+ nonEmpty?: boolean;
30
+ };
31
+ /**
32
+ * A custom React hook that evaluates to the result of a
33
+ * [Query](../flowerbi/interfaces/query.html), making it easy to perform a
34
+ * query from within a component.
35
+ *
36
+ * The returned object has a strongly-typed `records` array, and optionally
37
+ * a `totals` object. It has a `state` of type {@link UseQueryState} that
38
+ * can be used to show a loading indicator.
39
+ *
40
+ * @param fetch The fetch function to use.
41
+ * @param query The [Query](../flowerbi/interfaces/query.html) specification.
42
+ * @param dependencies Optionally, a list of one or more other queries whose
43
+ * results are used to build this query, so we wait for them before executing,
44
+ * and optionally short-circuit to an empty result if the dependency is empty.
45
+ */
46
+ export declare function useFlowerBI<S extends QuerySelect>(fetch: QueryFetch, query: Query<S>, dependencies?: QueryDependency[]): UseQueryResult<S>;
47
+ /**
48
+ * Alias of useFlowerBI for backward compatibility.
49
+ */
50
+ export declare const useQuery: typeof useFlowerBI;
@@ -0,0 +1,82 @@
1
+ "use strict";
2
+ var __assign = (this && this.__assign) || function () {
3
+ __assign = Object.assign || function(t) {
4
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
5
+ s = arguments[i];
6
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
+ t[p] = s[p];
8
+ }
9
+ return t;
10
+ };
11
+ return __assign.apply(this, arguments);
12
+ };
13
+ var __importDefault = (this && this.__importDefault) || function (mod) {
14
+ return (mod && mod.__esModule) ? mod : { "default": mod };
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.useQuery = exports.useFlowerBI = void 0;
18
+ var react_1 = require("react");
19
+ var flowerbi_1 = require("flowerbi");
20
+ var json_stable_stringify_1 = __importDefault(require("json-stable-stringify"));
21
+ /**
22
+ * A custom React hook that evaluates to the result of a
23
+ * [Query](../flowerbi/interfaces/query.html), making it easy to perform a
24
+ * query from within a component.
25
+ *
26
+ * The returned object has a strongly-typed `records` array, and optionally
27
+ * a `totals` object. It has a `state` of type {@link UseQueryState} that
28
+ * can be used to show a loading indicator.
29
+ *
30
+ * @param fetch The fetch function to use.
31
+ * @param query The [Query](../flowerbi/interfaces/query.html) specification.
32
+ * @param dependencies Optionally, a list of one or more other queries whose
33
+ * results are used to build this query, so we wait for them before executing,
34
+ * and optionally short-circuit to an empty result if the dependency is empty.
35
+ */
36
+ function useFlowerBI(fetch, query, dependencies) {
37
+ var queryJson = (0, flowerbi_1.jsonifyQuery)(query);
38
+ var _a = (0, react_1.useState)("init"), state = _a[0], setState = _a[1];
39
+ var _b = (0, react_1.useState)({ records: [] }), result = _b[0], setResult = _b[1];
40
+ (0, react_1.useEffect)(function () {
41
+ var disposed = false; // discard stale results
42
+ if (dependencies === null || dependencies === void 0 ? void 0 : dependencies.length) {
43
+ // if any not ready, neither are we
44
+ if (dependencies.some(function (x) { return x.dependency.state !== "ready"; })) {
45
+ if (state !== "init") {
46
+ setState("refresh");
47
+ }
48
+ return;
49
+ }
50
+ // if any with option nonEmpty produced empty result, so do we
51
+ if (dependencies.filter(function (x) { return !!x.nonEmpty; }).some(function (x) { return !x.dependency.records.length; })) {
52
+ setState("ready");
53
+ setResult({ records: [] });
54
+ return;
55
+ }
56
+ }
57
+ if (state !== "init") {
58
+ setState("refresh");
59
+ }
60
+ fetch(queryJson).then(function (x) {
61
+ if (!disposed) {
62
+ setState("ready");
63
+ setResult(x);
64
+ }
65
+ }, function () {
66
+ if (!disposed) {
67
+ setState("error");
68
+ }
69
+ });
70
+ return function () {
71
+ disposed = true;
72
+ };
73
+ // eslint-disable-next-line react-hooks/exhaustive-deps
74
+ }, [fetch, (0, json_stable_stringify_1.default)(queryJson)]);
75
+ return __assign(__assign({}, (0, flowerbi_1.expandQueryResult)(query.select, result)), { state: state });
76
+ }
77
+ exports.useFlowerBI = useFlowerBI;
78
+ /**
79
+ * Alias of useFlowerBI for backward compatibility.
80
+ */
81
+ exports.useQuery = useFlowerBI;
82
+ //# sourceMappingURL=useFlowerBI.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useFlowerBI.js","sourceRoot":"","sources":["../src/useFlowerBI.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,+BAAoD;AACpD,qCAAiI;AACjI,gFAAoD;AAkCpD;;;;;;;;;;;;;;GAcG;AACH,SAAgB,WAAW,CAAwB,KAAiB,EAAE,KAAe,EAAE,YAAgC;IACnH,IAAM,SAAS,GAAG,IAAA,uBAAY,EAAC,KAAK,CAAC,CAAC;IAEhC,IAAA,KAAoB,IAAA,gBAAQ,EAAgB,MAAM,CAAC,EAAlD,KAAK,QAAA,EAAE,QAAQ,QAAmC,CAAC;IACpD,IAAA,KAAsB,IAAA,gBAAQ,EAAkB,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,EAA/D,MAAM,QAAA,EAAE,SAAS,QAA8C,CAAC;IAEvE,IAAA,iBAAS,EAAC;QACN,IAAI,QAAQ,GAAG,KAAK,CAAC,CAAC,wBAAwB;QAE9C,IAAI,YAAY,aAAZ,YAAY,uBAAZ,YAAY,CAAE,MAAM,EAAE;YACtB,mCAAmC;YACnC,IAAI,YAAY,CAAC,IAAI,CAAC,UAAA,CAAC,IAAI,OAAA,CAAC,CAAC,UAAU,CAAC,KAAK,KAAK,OAAO,EAA9B,CAA8B,CAAC,EAAE;gBACxD,IAAI,KAAK,KAAK,MAAM,EAAE;oBAClB,QAAQ,CAAC,SAAS,CAAC,CAAC;iBACvB;gBACD,OAAO;aACV;YAED,8DAA8D;YAC9D,IAAI,YAAY,CAAC,MAAM,CAAC,UAAA,CAAC,IAAI,OAAA,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAZ,CAAY,CAAC,CAAC,IAAI,CAAC,UAAA,CAAC,IAAI,OAAA,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,EAA5B,CAA4B,CAAC,EAAE;gBAChF,QAAQ,CAAC,OAAO,CAAC,CAAC;gBAClB,SAAS,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC;gBAC3B,OAAO;aACV;SACJ;QAED,IAAI,KAAK,KAAK,MAAM,EAAE;YAClB,QAAQ,CAAC,SAAS,CAAC,CAAC;SACvB;QAED,KAAK,CAAC,SAAS,CAAC,CAAC,IAAI,CACjB,UAAA,CAAC;YACG,IAAI,CAAC,QAAQ,EAAE;gBACX,QAAQ,CAAC,OAAO,CAAC,CAAC;gBAClB,SAAS,CAAC,CAAC,CAAC,CAAC;aAChB;QACL,CAAC,EACD;YACI,IAAI,CAAC,QAAQ,EAAE;gBACX,QAAQ,CAAC,OAAO,CAAC,CAAC;aACrB;QACL,CAAC,CACJ,CAAC;QAEF,OAAO;YACH,QAAQ,GAAG,IAAI,CAAC;QACpB,CAAC,CAAC;QACF,uDAAuD;IAC3D,CAAC,EAAE,CAAC,KAAK,EAAE,IAAA,+BAAe,EAAC,SAAS,CAAC,CAAC,CAAC,CAAC;IAExC,6BAAY,IAAA,4BAAiB,EAAC,KAAK,CAAC,MAAM,EAAE,MAAM,CAAC,KAAE,KAAK,OAAA,IAAG;AACjE,CAAC;AAnDD,kCAmDC;AAED;;GAEG;AACU,QAAA,QAAQ,GAAG,WAAW,CAAC"}
@@ -10,17 +10,29 @@ var __assign = (this && this.__assign) || function () {
10
10
  };
11
11
  return __assign.apply(this, arguments);
12
12
  };
13
+ var __importDefault = (this && this.__importDefault) || function (mod) {
14
+ return (mod && mod.__esModule) ? mod : { "default": mod };
15
+ };
13
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.usePageFilters = void 0;
14
18
  var react_1 = require("react");
19
+ var json_stable_stringify_1 = __importDefault(require("json-stable-stringify"));
15
20
  var clearedState = {
16
21
  global: [],
17
22
  interactions: [],
18
23
  interactionKey: "",
19
24
  };
20
25
  function usePageFilters() {
21
- var _a = react_1.useState(clearedState), state = _a[0], set = _a[1];
26
+ var _a = (0, react_1.useState)(clearedState), state = _a[0], set = _a[1];
22
27
  function setInteraction(interactionKey, interactions) {
23
- set(__assign(__assign({}, state), { interactionKey: interactionKey, interactions: interactions }));
28
+ console.log(interactionKey, state.interactionKey, state.interactionKey === interactionKey, interactions, state.interactions, (0, json_stable_stringify_1.default)(state.interactions), (0, json_stable_stringify_1.default)(interactions), (0, json_stable_stringify_1.default)(state.interactions) === (0, json_stable_stringify_1.default)(interactions));
29
+ if (state.interactionKey === interactionKey &&
30
+ (0, json_stable_stringify_1.default)(state.interactions) === (0, json_stable_stringify_1.default)(interactions)) {
31
+ clearInteraction();
32
+ }
33
+ else {
34
+ set(__assign(__assign({}, state), { interactionKey: interactionKey, interactions: interactions }));
35
+ }
24
36
  }
25
37
  function setGlobal(global) {
26
38
  set(__assign(__assign({}, state), { global: global }));
@@ -1 +1 @@
1
- {"version":3,"file":"usePageFilters.js","sourceRoot":"","sources":["../src/usePageFilters.ts"],"names":[],"mappings":";;;;;;;;;;;;;AAAA,+BAAiC;AAkBjC,IAAM,YAAY,GAAqB;IACnC,MAAM,EAAE,EAAE;IACV,YAAY,EAAE,EAAE;IAChB,cAAc,EAAE,EAAE;CACrB,CAAC;AAEF,SAAgB,cAAc;IACpB,IAAA,mCAAuD,EAAtD,aAAK,EAAE,WAA+C,CAAC;IAC9D,SAAS,cAAc,CAAC,cAAsB,EAAE,YAA0B;QACtE,GAAG,uBAAM,KAAK,KAAE,cAAc,gBAAA,EAAE,YAAY,cAAA,IAAG,CAAC;IACpD,CAAC;IACD,SAAS,SAAS,CAAC,MAAoB;QACnC,GAAG,uBAAM,KAAK,KAAE,MAAM,QAAA,IAAG,CAAC;IAC9B,CAAC;IACD,SAAS,gBAAgB;QACrB,GAAG,uBAAM,KAAK,KAAE,cAAc,EAAE,EAAE,EAAE,YAAY,EAAE,EAAE,IAAG,CAAC;IAC5D,CAAC;IACD,SAAS,WAAW;QAChB,GAAG,uBAAM,KAAK,KAAE,MAAM,EAAE,EAAE,IAAG,CAAC;IAClC,CAAC;IACD,SAAS,QAAQ;QACb,GAAG,CAAC,YAAY,CAAC,CAAC;IACtB,CAAC;IACD,SAAS,UAAU,CAAC,GAAW;QAC3B,IAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;QAC5B,OAAO,GAAG,KAAK,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IACrF,CAAC;IACD,6BAAY,KAAK,KAAE,cAAc,gBAAA,EAAE,SAAS,WAAA,EAAE,gBAAgB,kBAAA,EAAE,WAAW,aAAA,EAAE,QAAQ,UAAA,EAAE,UAAU,YAAA,IAAG;AACxG,CAAC;AAtBD,wCAsBC"}
1
+ {"version":3,"file":"usePageFilters.js","sourceRoot":"","sources":["../src/usePageFilters.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,+BAAiC;AAEjC,gFAAoD;AAiBpD,IAAM,YAAY,GAAqB;IACnC,MAAM,EAAE,EAAE;IACV,YAAY,EAAE,EAAE;IAChB,cAAc,EAAE,EAAE;CACrB,CAAC;AAEF,SAAgB,cAAc;IACpB,IAAA,KAAe,IAAA,gBAAQ,EAAmB,YAAY,CAAC,EAAtD,KAAK,QAAA,EAAE,GAAG,QAA4C,CAAC;IAC9D,SAAS,cAAc,CAAC,cAAsB,EAAE,YAA0B;QACtE,OAAO,CAAC,GAAG,CAAC,cAAc,EAAE,KAAK,CAAC,cAAc,EAAE,KAAK,CAAC,cAAc,KAAK,cAAc,EACrF,YAAY,EAAE,KAAK,CAAC,YAAY,EAChC,IAAA,+BAAe,EAAC,KAAK,CAAC,YAAY,CAAC,EAAE,IAAA,+BAAe,EAAC,YAAY,CAAC,EAClE,IAAA,+BAAe,EAAC,KAAK,CAAC,YAAY,CAAC,KAAK,IAAA,+BAAe,EAAC,YAAY,CAAC,CAAC,CAAC;QAE3E,IAAI,KAAK,CAAC,cAAc,KAAK,cAAc;YACvC,IAAA,+BAAe,EAAC,KAAK,CAAC,YAAY,CAAC,KAAK,IAAA,+BAAe,EAAC,YAAY,CAAC,EAAE;YACvE,gBAAgB,EAAE,CAAC;SACtB;aAAM;YACH,GAAG,uBAAM,KAAK,KAAE,cAAc,gBAAA,EAAE,YAAY,cAAA,IAAG,CAAC;SACnD;IACL,CAAC;IACD,SAAS,SAAS,CAAC,MAAoB;QACnC,GAAG,uBAAM,KAAK,KAAE,MAAM,QAAA,IAAG,CAAC;IAC9B,CAAC;IACD,SAAS,gBAAgB;QACrB,GAAG,uBAAM,KAAK,KAAE,cAAc,EAAE,EAAE,EAAE,YAAY,EAAE,EAAE,IAAG,CAAC;IAC5D,CAAC;IACD,SAAS,WAAW;QAChB,GAAG,uBAAM,KAAK,KAAE,MAAM,EAAE,EAAE,IAAG,CAAC;IAClC,CAAC;IACD,SAAS,QAAQ;QACb,GAAG,CAAC,YAAY,CAAC,CAAC;IACtB,CAAC;IACD,SAAS,UAAU,CAAC,GAAW;QAC3B,IAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;QAC5B,OAAO,GAAG,KAAK,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IACrF,CAAC;IACD,6BAAY,KAAK,KAAE,cAAc,gBAAA,EAAE,SAAS,WAAA,EAAE,gBAAgB,kBAAA,EAAE,WAAW,aAAA,EAAE,QAAQ,UAAA,EAAE,UAAU,YAAA,IAAG;AACxG,CAAC;AAhCD,wCAgCC"}
@@ -11,6 +11,23 @@ export interface UseQueryResult<S extends QuerySelect> extends ExpandedQueryResu
11
11
  */
12
12
  state: UseQueryState;
13
13
  }
14
+ /**
15
+ * Defines another query on which our query depends - for example a
16
+ * first query may return the top 10 vendors, and a subsequent query
17
+ * may then use an `in` filter to get details about those 10 vendors.
18
+ */
19
+ export declare type QueryDependency = {
20
+ /**
21
+ * The result of the query we depend on
22
+ */
23
+ dependency: UseQueryResult<QuerySelect>;
24
+ /**
25
+ * If true (default is false) then if the dependency query produces
26
+ * an empty result, our query should also produce an empty result,
27
+ * so there is no need to execute it.
28
+ */
29
+ nonEmpty?: boolean;
30
+ };
14
31
  /**
15
32
  * A custom React hook that evaluates to the result of a
16
33
  * [Query](../flowerbi/interfaces/query.html), making it easy to perform a
@@ -22,5 +39,8 @@ export interface UseQueryResult<S extends QuerySelect> extends ExpandedQueryResu
22
39
  *
23
40
  * @param fetch The fetch function to use.
24
41
  * @param query The [Query](../flowerbi/interfaces/query.html) specification.
42
+ * @param dependencies Optionally, a list of one or more other queries whose
43
+ * results are used to build this query, so we wait for them before executing,
44
+ * and optionally short-circuit to an empty result if the dependency is empty.
25
45
  */
26
- export declare function useQuery<S extends QuerySelect>(fetch: QueryFetch, query: Query<S>): UseQueryResult<S>;
46
+ export declare function useQuery<S extends QuerySelect>(fetch: QueryFetch, query: Query<S>, dependencies?: QueryDependency[]): UseQueryResult<S>;
package/dist/useQuery.js CHANGED
@@ -14,6 +14,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
14
14
  return (mod && mod.__esModule) ? mod : { "default": mod };
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.useQuery = void 0;
17
18
  var react_1 = require("react");
18
19
  var flowerbi_1 = require("flowerbi");
19
20
  var json_stable_stringify_1 = __importDefault(require("json-stable-stringify"));
@@ -28,13 +29,31 @@ var json_stable_stringify_1 = __importDefault(require("json-stable-stringify"));
28
29
  *
29
30
  * @param fetch The fetch function to use.
30
31
  * @param query The [Query](../flowerbi/interfaces/query.html) specification.
32
+ * @param dependencies Optionally, a list of one or more other queries whose
33
+ * results are used to build this query, so we wait for them before executing,
34
+ * and optionally short-circuit to an empty result if the dependency is empty.
31
35
  */
32
- function useQuery(fetch, query) {
33
- var queryJson = flowerbi_1.jsonifyQuery(query);
34
- var _a = react_1.useState("init"), state = _a[0], setState = _a[1];
35
- var _b = react_1.useState({ records: [] }), result = _b[0], setResult = _b[1];
36
- react_1.useEffect(function () {
37
- var disposed = false;
36
+ function useQuery(fetch, query, dependencies) {
37
+ var queryJson = (0, flowerbi_1.jsonifyQuery)(query);
38
+ var _a = (0, react_1.useState)("init"), state = _a[0], setState = _a[1];
39
+ var _b = (0, react_1.useState)({ records: [] }), result = _b[0], setResult = _b[1];
40
+ (0, react_1.useEffect)(function () {
41
+ var disposed = false; // discard stale results
42
+ if (dependencies === null || dependencies === void 0 ? void 0 : dependencies.length) {
43
+ // if any not ready, neither are we
44
+ if (dependencies.some(function (x) { return x.dependency.state !== "ready"; })) {
45
+ if (state !== "init") {
46
+ setState("refresh");
47
+ }
48
+ return;
49
+ }
50
+ // if any with option nonEmpty produced empty result, so do we
51
+ if (dependencies.filter(function (x) { return !!x.nonEmpty; }).some(function (x) { return !x.dependency.records.length; })) {
52
+ setState("ready");
53
+ setResult({ records: [] });
54
+ return;
55
+ }
56
+ }
38
57
  if (state !== "init") {
39
58
  setState("refresh");
40
59
  }
@@ -48,9 +67,12 @@ function useQuery(fetch, query) {
48
67
  setState("error");
49
68
  }
50
69
  });
51
- return function () { disposed = true; };
52
- }, [json_stable_stringify_1.default(queryJson)]);
53
- return __assign(__assign({}, flowerbi_1.expandQueryResult(query.select, result)), { state: state });
70
+ return function () {
71
+ disposed = true;
72
+ };
73
+ // eslint-disable-next-line react-hooks/exhaustive-deps
74
+ }, [fetch, (0, json_stable_stringify_1.default)(queryJson)]);
75
+ return __assign(__assign({}, (0, flowerbi_1.expandQueryResult)(query.select, result)), { state: state });
54
76
  }
55
77
  exports.useQuery = useQuery;
56
78
  //# sourceMappingURL=useQuery.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"useQuery.js","sourceRoot":"","sources":["../src/useQuery.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,+BAA4C;AAC5C,qCAAiI;AACjI,gFAAoD;AAgBpD;;;;;;;;;;;GAWG;AACH,SAAgB,QAAQ,CAAwB,KAAiB,EAAE,KAAe;IAE9E,IAAM,SAAS,GAAG,uBAAY,CAAC,KAAK,CAAC,CAAC;IAEhC,IAAA,6BAAmD,EAAlD,aAAK,EAAE,gBAA2C,CAAC;IACpD,IAAA,sCAAgE,EAA/D,cAAM,EAAE,iBAAuD,CAAC;IAEvE,iBAAS,CAAC;QACN,IAAI,QAAQ,GAAG,KAAK,CAAC;QACrB,IAAI,KAAK,KAAK,MAAM,EAAE;YAClB,QAAQ,CAAC,SAAS,CAAC,CAAC;SACvB;QACD,KAAK,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,UAAA,CAAC;YACnB,IAAI,CAAC,QAAQ,EAAE;gBACX,QAAQ,CAAC,OAAO,CAAC,CAAC;gBAClB,SAAS,CAAC,CAAC,CAAC,CAAC;aAChB;QACL,CAAC,EAAE;YACC,IAAI,CAAC,QAAQ,EAAE;gBACX,QAAQ,CAAC,OAAO,CAAC,CAAC;aACrB;QACL,CAAC,CAAC,CAAC;QAEH,OAAO,cAAQ,QAAQ,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IACtC,CAAC,EAAE,CAAC,+BAAe,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;IAEjC,6BAAY,4BAAiB,CAAC,KAAK,CAAC,MAAM,EAAE,MAAM,CAAC,KAAE,KAAK,OAAA,IAAG;AACjE,CAAC;AA3BD,4BA2BC"}
1
+ {"version":3,"file":"useQuery.js","sourceRoot":"","sources":["../src/useQuery.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,+BAAoD;AACpD,qCAAiI;AACjI,gFAAoD;AAkCpD;;;;;;;;;;;;;;GAcG;AACH,SAAgB,QAAQ,CAAwB,KAAiB,EAAE,KAAe,EAAE,YAAgC;IAChH,IAAM,SAAS,GAAG,IAAA,uBAAY,EAAC,KAAK,CAAC,CAAC;IAEhC,IAAA,KAAoB,IAAA,gBAAQ,EAAgB,MAAM,CAAC,EAAlD,KAAK,QAAA,EAAE,QAAQ,QAAmC,CAAC;IACpD,IAAA,KAAsB,IAAA,gBAAQ,EAAkB,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,EAA/D,MAAM,QAAA,EAAE,SAAS,QAA8C,CAAC;IAEvE,IAAA,iBAAS,EAAC;QACN,IAAI,QAAQ,GAAG,KAAK,CAAC,CAAC,wBAAwB;QAE9C,IAAI,YAAY,aAAZ,YAAY,uBAAZ,YAAY,CAAE,MAAM,EAAE;YACtB,mCAAmC;YACnC,IAAI,YAAY,CAAC,IAAI,CAAC,UAAA,CAAC,IAAI,OAAA,CAAC,CAAC,UAAU,CAAC,KAAK,KAAK,OAAO,EAA9B,CAA8B,CAAC,EAAE;gBACxD,IAAI,KAAK,KAAK,MAAM,EAAE;oBAClB,QAAQ,CAAC,SAAS,CAAC,CAAC;iBACvB;gBACD,OAAO;aACV;YAED,8DAA8D;YAC9D,IAAI,YAAY,CAAC,MAAM,CAAC,UAAA,CAAC,IAAI,OAAA,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAZ,CAAY,CAAC,CAAC,IAAI,CAAC,UAAA,CAAC,IAAI,OAAA,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,EAA5B,CAA4B,CAAC,EAAE;gBAChF,QAAQ,CAAC,OAAO,CAAC,CAAC;gBAClB,SAAS,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC;gBAC3B,OAAO;aACV;SACJ;QAED,IAAI,KAAK,KAAK,MAAM,EAAE;YAClB,QAAQ,CAAC,SAAS,CAAC,CAAC;SACvB;QAED,KAAK,CAAC,SAAS,CAAC,CAAC,IAAI,CACjB,UAAA,CAAC;YACG,IAAI,CAAC,QAAQ,EAAE;gBACX,QAAQ,CAAC,OAAO,CAAC,CAAC;gBAClB,SAAS,CAAC,CAAC,CAAC,CAAC;aAChB;QACL,CAAC,EACD;YACI,IAAI,CAAC,QAAQ,EAAE;gBACX,QAAQ,CAAC,OAAO,CAAC,CAAC;aACrB;QACL,CAAC,CACJ,CAAC;QAEF,OAAO;YACH,QAAQ,GAAG,IAAI,CAAC;QACpB,CAAC,CAAC;QACF,uDAAuD;IAC3D,CAAC,EAAE,CAAC,KAAK,EAAE,IAAA,+BAAe,EAAC,SAAS,CAAC,CAAC,CAAC,CAAC;IAExC,6BAAY,IAAA,4BAAiB,EAAC,KAAK,CAAC,MAAM,EAAE,MAAM,CAAC,KAAE,KAAK,OAAA,IAAG;AACjE,CAAC;AAnDD,4BAmDC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "flowerbi-react",
3
- "version": "1.19.0",
3
+ "version": "2.0.0",
4
4
  "author": "Daniel Earwicker <dan@earwicker.com>",
5
5
  "license": "MIT",
6
6
  "description": "React helpers for FlowerBI",
@@ -9,22 +9,22 @@
9
9
  "dependencies": {
10
10
  "@types/json-stable-stringify": "^1.0.32",
11
11
  "@types/react": "^16.9.0",
12
- "json-stable-stringify": "^1.0.1",
13
- "flowerbi": "1.19.0"
12
+ "flowerbi": "2.0.0",
13
+ "json-stable-stringify": "^1.0.1"
14
14
  },
15
15
  "devDependencies": {
16
- "prettier": "^2.0.5",
17
- "react": "^16.13.1",
18
- "typescript": "~3.8.3",
19
- "typedoc": "^0.17.8"
16
+ "prettier": "^2.5.1",
17
+ "react": "^17.0.2",
18
+ "typedoc": "^0.22.11",
19
+ "typescript": "^4.5.5"
20
20
  },
21
21
  "peerDependencies": {
22
- "react": "^16.13.1"
22
+ "react": "^16.13.1 || ^17.0.2"
23
23
  },
24
24
  "scripts": {
25
25
  "build": "tsc",
26
26
  "watch": "tsc -w",
27
- "docs": "typedoc --mode file --out ../../../docs/typedoc/flowerbi-react src",
27
+ "docs": "typedoc --out ../../../docs/typedoc/flowerbi-react src",
28
28
  "prepare": "npm run build && npm run docs"
29
29
  }
30
30
  }
package/src/index.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  export * from "./FlowerBITable";
2
2
  export * from "./usePageFilters";
3
- export * from "./useQuery";
3
+ export * from "./useFlowerBI";
@@ -0,0 +1,108 @@
1
+ import { useState, useEffect, useRef } from "react";
2
+ import { Query, QueryFetch, jsonifyQuery, QueryResultJson, QuerySelect, expandQueryResult, ExpandedQueryResult } from "flowerbi";
3
+ import stableStringify from "json-stable-stringify";
4
+
5
+ export type UseQueryState = "init" | "ready" | "refresh" | "error";
6
+
7
+ export interface UseQueryResult<S extends QuerySelect> extends ExpandedQueryResult<S> {
8
+ /**
9
+ * The state of the query operation:
10
+ *
11
+ * - `init` - no result has been downloaded yet
12
+ * - `ready` - result has been downloaded
13
+ * - `refresh` - a new result is being downloaded
14
+ * - `error` - most recent query attempt failed
15
+ */
16
+ state: UseQueryState;
17
+ }
18
+
19
+ /**
20
+ * Defines another query on which our query depends - for example a
21
+ * first query may return the top 10 vendors, and a subsequent query
22
+ * may then use an `in` filter to get details about those 10 vendors.
23
+ */
24
+ export type QueryDependency = {
25
+ /**
26
+ * The result of the query we depend on
27
+ */
28
+ dependency: UseQueryResult<QuerySelect>;
29
+ /**
30
+ * If true (default is false) then if the dependency query produces
31
+ * an empty result, our query should also produce an empty result,
32
+ * so there is no need to execute it.
33
+ */
34
+ nonEmpty?: boolean;
35
+ };
36
+
37
+ /**
38
+ * A custom React hook that evaluates to the result of a
39
+ * [Query](../flowerbi/interfaces/query.html), making it easy to perform a
40
+ * query from within a component.
41
+ *
42
+ * The returned object has a strongly-typed `records` array, and optionally
43
+ * a `totals` object. It has a `state` of type {@link UseQueryState} that
44
+ * can be used to show a loading indicator.
45
+ *
46
+ * @param fetch The fetch function to use.
47
+ * @param query The [Query](../flowerbi/interfaces/query.html) specification.
48
+ * @param dependencies Optionally, a list of one or more other queries whose
49
+ * results are used to build this query, so we wait for them before executing,
50
+ * and optionally short-circuit to an empty result if the dependency is empty.
51
+ */
52
+ export function useFlowerBI<S extends QuerySelect>(fetch: QueryFetch, query: Query<S>, dependencies?: QueryDependency[]): UseQueryResult<S> {
53
+ const queryJson = jsonifyQuery(query);
54
+
55
+ const [state, setState] = useState<UseQueryState>("init");
56
+ const [result, setResult] = useState<QueryResultJson>({ records: [] });
57
+
58
+ useEffect(() => {
59
+ let disposed = false; // discard stale results
60
+
61
+ if (dependencies?.length) {
62
+ // if any not ready, neither are we
63
+ if (dependencies.some(x => x.dependency.state !== "ready")) {
64
+ if (state !== "init") {
65
+ setState("refresh");
66
+ }
67
+ return;
68
+ }
69
+
70
+ // if any with option nonEmpty produced empty result, so do we
71
+ if (dependencies.filter(x => !!x.nonEmpty).some(x => !x.dependency.records.length)) {
72
+ setState("ready");
73
+ setResult({ records: [] });
74
+ return;
75
+ }
76
+ }
77
+
78
+ if (state !== "init") {
79
+ setState("refresh");
80
+ }
81
+
82
+ fetch(queryJson).then(
83
+ x => {
84
+ if (!disposed) {
85
+ setState("ready");
86
+ setResult(x);
87
+ }
88
+ },
89
+ () => {
90
+ if (!disposed) {
91
+ setState("error");
92
+ }
93
+ }
94
+ );
95
+
96
+ return () => {
97
+ disposed = true;
98
+ };
99
+ // eslint-disable-next-line react-hooks/exhaustive-deps
100
+ }, [fetch, stableStringify(queryJson)]);
101
+
102
+ return { ...expandQueryResult(query.select, result), state };
103
+ }
104
+
105
+ /**
106
+ * Alias of useFlowerBI for backward compatibility.
107
+ */
108
+ export const useQuery = useFlowerBI;
@@ -1,5 +1,6 @@
1
1
  import { useState } from "react";
2
2
  import { FilterJson } from "flowerbi";
3
+ import stableStringify from "json-stable-stringify";
3
4
 
4
5
  export interface PageFiltersState {
5
6
  readonly global: FilterJson[];
@@ -25,7 +26,17 @@ const clearedState: PageFiltersState = {
25
26
  export function usePageFilters(): PageFilters {
26
27
  const [state, set] = useState<PageFiltersState>(clearedState);
27
28
  function setInteraction(interactionKey: string, interactions: FilterJson[]) {
28
- set({ ...state, interactionKey, interactions });
29
+ console.log(interactionKey, state.interactionKey, state.interactionKey === interactionKey,
30
+ interactions, state.interactions,
31
+ stableStringify(state.interactions), stableStringify(interactions),
32
+ stableStringify(state.interactions) === stableStringify(interactions));
33
+
34
+ if (state.interactionKey === interactionKey &&
35
+ stableStringify(state.interactions) === stableStringify(interactions)) {
36
+ clearInteraction();
37
+ } else {
38
+ set({ ...state, interactionKey, interactions });
39
+ }
29
40
  }
30
41
  function setGlobal(global: FilterJson[]) {
31
42
  set({ ...state, global });
package/src/useQuery.ts DELETED
@@ -1,58 +0,0 @@
1
- import { useState, useEffect } from "react";
2
- import { Query, QueryFetch, jsonifyQuery, QueryResultJson, QuerySelect, expandQueryResult, ExpandedQueryResult } from "flowerbi";
3
- import stableStringify from "json-stable-stringify";
4
-
5
- export type UseQueryState = "init" | "ready" | "refresh" | "error";
6
-
7
- export interface UseQueryResult<S extends QuerySelect> extends ExpandedQueryResult<S> {
8
- /**
9
- * The state of the query operation:
10
- *
11
- * - `init` - no result has been downloaded yet
12
- * - `ready` - result has been downloaded
13
- * - `refresh` - a new result is being downloaded
14
- * - `error` - most recent query attempt failed
15
- */
16
- state: UseQueryState;
17
- }
18
-
19
- /**
20
- * A custom React hook that evaluates to the result of a
21
- * [Query](../flowerbi/interfaces/query.html), making it easy to perform a
22
- * query from within a component.
23
- *
24
- * The returned object has a strongly-typed `records` array, and optionally
25
- * a `totals` object. It has a `state` of type {@link UseQueryState} that
26
- * can be used to show a loading indicator.
27
- *
28
- * @param fetch The fetch function to use.
29
- * @param query The [Query](../flowerbi/interfaces/query.html) specification.
30
- */
31
- export function useQuery<S extends QuerySelect>(fetch: QueryFetch, query: Query<S>): UseQueryResult<S> {
32
-
33
- const queryJson = jsonifyQuery(query);
34
-
35
- const [state, setState] = useState<UseQueryState>("init");
36
- const [result, setResult] = useState<QueryResultJson>({ records: [] });
37
-
38
- useEffect(() => {
39
- let disposed = false;
40
- if (state !== "init") {
41
- setState("refresh");
42
- }
43
- fetch(queryJson).then(x => {
44
- if (!disposed) {
45
- setState("ready");
46
- setResult(x);
47
- }
48
- }, () => {
49
- if (!disposed) {
50
- setState("error");
51
- }
52
- });
53
-
54
- return () => { disposed = true; };
55
- }, [stableStringify(queryJson)]);
56
-
57
- return { ...expandQueryResult(query.select, result), state };
58
- }