@darajs/core 1.3.2 → 1.4.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.
Files changed (106) hide show
  1. package/dist/actions/download-variable.d.ts +3 -3
  2. package/dist/actions/download-variable.d.ts.map +1 -1
  3. package/dist/actions/download-variable.js +32 -46
  4. package/dist/actions/download-variable.js.map +1 -1
  5. package/dist/actions/index.d.ts +0 -4
  6. package/dist/actions/index.d.ts.map +1 -1
  7. package/dist/actions/index.js +0 -4
  8. package/dist/actions/index.js.map +1 -1
  9. package/dist/actions/navigate-to.d.ts +3 -3
  10. package/dist/actions/navigate-to.d.ts.map +1 -1
  11. package/dist/actions/navigate-to.js +16 -57
  12. package/dist/actions/navigate-to.js.map +1 -1
  13. package/dist/actions/notify.d.ts +2 -6
  14. package/dist/actions/notify.d.ts.map +1 -1
  15. package/dist/actions/notify.js +8 -14
  16. package/dist/actions/notify.js.map +1 -1
  17. package/dist/actions/reset-variables.d.ts +2 -2
  18. package/dist/actions/reset-variables.d.ts.map +1 -1
  19. package/dist/actions/reset-variables.js +28 -17
  20. package/dist/actions/reset-variables.js.map +1 -1
  21. package/dist/actions/trigger-variable.d.ts +2 -2
  22. package/dist/actions/trigger-variable.d.ts.map +1 -1
  23. package/dist/actions/trigger-variable.js +7 -18
  24. package/dist/actions/trigger-variable.js.map +1 -1
  25. package/dist/actions/update-variable.d.ts +2 -4
  26. package/dist/actions/update-variable.d.ts.map +1 -1
  27. package/dist/actions/update-variable.js +17 -83
  28. package/dist/actions/update-variable.js.map +1 -1
  29. package/dist/api/websocket.d.ts +22 -2
  30. package/dist/api/websocket.d.ts.map +1 -1
  31. package/dist/api/websocket.js +11 -0
  32. package/dist/api/websocket.js.map +1 -1
  33. package/dist/auth/auth-wrapper.js +1 -1
  34. package/dist/auth/auth-wrapper.js.map +1 -1
  35. package/dist/components/router-content/router-content.d.ts.map +1 -1
  36. package/dist/components/router-content/router-content.js +1 -1
  37. package/dist/components/router-content/router-content.js.map +1 -1
  38. package/dist/{dara_core-1.3.2-py3-none-any.whl → dara_core-1.4.0-py3-none-any.whl} +0 -0
  39. package/dist/index.d.ts +4 -4
  40. package/dist/index.d.ts.map +1 -1
  41. package/dist/index.js +2 -2
  42. package/dist/index.js.map +1 -1
  43. package/dist/shared/index.d.ts +1 -1
  44. package/dist/shared/index.d.ts.map +1 -1
  45. package/dist/shared/index.js +1 -1
  46. package/dist/shared/index.js.map +1 -1
  47. package/dist/shared/interactivity/index.d.ts +2 -4
  48. package/dist/shared/interactivity/index.d.ts.map +1 -1
  49. package/dist/shared/interactivity/index.js +2 -3
  50. package/dist/shared/interactivity/index.js.map +1 -1
  51. package/dist/shared/interactivity/store.d.ts +8 -0
  52. package/dist/shared/interactivity/store.d.ts.map +1 -1
  53. package/dist/shared/interactivity/store.js +19 -0
  54. package/dist/shared/interactivity/store.js.map +1 -1
  55. package/dist/shared/interactivity/use-variable-value.d.ts +19 -7
  56. package/dist/shared/interactivity/use-variable-value.d.ts.map +1 -1
  57. package/dist/shared/interactivity/use-variable-value.js +54 -40
  58. package/dist/shared/interactivity/use-variable-value.js.map +1 -1
  59. package/dist/shared/private-route/private-route.d.ts +3 -7
  60. package/dist/shared/private-route/private-route.d.ts.map +1 -1
  61. package/dist/shared/private-route/private-route.js +12 -22
  62. package/dist/shared/private-route/private-route.js.map +1 -1
  63. package/dist/shared/utils/use-action-registry.d.ts +2 -2
  64. package/dist/shared/utils/use-action-registry.d.ts.map +1 -1
  65. package/dist/shared/utils/use-action-registry.js +6 -6
  66. package/dist/shared/utils/use-action-registry.js.map +1 -1
  67. package/dist/shared/utils/use-action.d.ts +14 -2
  68. package/dist/shared/utils/use-action.d.ts.map +1 -1
  69. package/dist/shared/utils/use-action.js +249 -55
  70. package/dist/shared/utils/use-action.js.map +1 -1
  71. package/dist/types/core.d.ts +80 -51
  72. package/dist/types/core.d.ts.map +1 -1
  73. package/dist/types/core.js.map +1 -1
  74. package/dist/types/index.d.ts +2 -2
  75. package/dist/types/index.d.ts.map +1 -1
  76. package/dist/types/index.js.map +1 -1
  77. package/dist/types/utils.d.ts +7 -1
  78. package/dist/types/utils.d.ts.map +1 -1
  79. package/dist/types/utils.js +8 -0
  80. package/dist/types/utils.js.map +1 -1
  81. package/dist/umd/dara.core.umd.js +5955 -6669
  82. package/package.json +6 -6
  83. package/dist/actions/download-content.d.ts +0 -8
  84. package/dist/actions/download-content.d.ts.map +0 -1
  85. package/dist/actions/download-content.js +0 -47
  86. package/dist/actions/download-content.js.map +0 -1
  87. package/dist/actions/logout.d.ts +0 -8
  88. package/dist/actions/logout.d.ts.map +0 -1
  89. package/dist/actions/logout.js +0 -25
  90. package/dist/actions/logout.js.map +0 -1
  91. package/dist/actions/side-effect.d.ts +0 -8
  92. package/dist/actions/side-effect.d.ts.map +0 -1
  93. package/dist/actions/side-effect.js +0 -45
  94. package/dist/actions/side-effect.js.map +0 -1
  95. package/dist/actions/utils.d.ts +0 -9
  96. package/dist/actions/utils.d.ts.map +0 -1
  97. package/dist/actions/utils.js +0 -38
  98. package/dist/actions/utils.js.map +0 -1
  99. package/dist/shared/interactivity/use-reset-variables.d.ts +0 -8
  100. package/dist/shared/interactivity/use-reset-variables.d.ts.map +0 -1
  101. package/dist/shared/interactivity/use-reset-variables.js +0 -46
  102. package/dist/shared/interactivity/use-reset-variables.js.map +0 -1
  103. package/dist/shared/interactivity/use-trigger-variable.d.ts +0 -9
  104. package/dist/shared/interactivity/use-trigger-variable.d.ts.map +0 -1
  105. package/dist/shared/interactivity/use-trigger-variable.js +0 -18
  106. package/dist/shared/interactivity/use-trigger-variable.js.map +0 -1
@@ -3,12 +3,60 @@ import { useContext } from 'react';
3
3
  import { useLocation } from 'react-router-dom';
4
4
  import { useRecoilCallback } from 'recoil';
5
5
  import { useDeepCompare } from '@darajs/ui-utils';
6
- // eslint-disable-next-line import/no-cycle
7
6
  import { useSessionToken } from '../../auth/auth-context';
8
7
  import { WebSocketCtx, useTaskContext } from '../../shared/context';
9
8
  import { normalizeRequest } from '../../shared/utils/normalization';
10
9
  import { isDataVariable, isDerivedDataVariable, isDerivedVariable, isResolvedDataVariable, isResolvedDerivedDataVariable, isResolvedDerivedVariable, isVariable, } from '../../types';
11
10
  import { fetchDataVariable, fetchDerivedDataVariable, fetchDerivedVariable, formatDerivedVariableRequest, isTaskResponse, resolveVariable, } from './internal';
11
+ /**
12
+ * Helper function that returns the current value of a variable.
13
+ *
14
+ * Plain variables are always resolved to their value.
15
+ * Computed (server-side) variables are resolved to their uid and dependency values, unless shouldFetchVariable is true.
16
+ */
17
+ export function getVariableValue(variable, shouldFetchVariable = false, ctx) {
18
+ // Using loadable since the resolver is only used for simple atoms and shouldn't cause problems
19
+ const resolved = resolveVariable(variable, ctx.client, ctx.taskContext, ctx.search, ctx.token, (v) => ctx.snapshot.getLoadable(v).getValue());
20
+ // if we're NOT forced to fetch, or if it's not a DV/DDV/data variable, return the resolved value
21
+ // variable is plain/url
22
+ if (!shouldFetchVariable ||
23
+ (!isDerivedVariable(variable) && !isDataVariable(variable) && !isDerivedDataVariable(variable))) {
24
+ return resolved;
25
+ }
26
+ // we're forced to fetch but the resolved variable is not a resolved DV/data var, return the resolved value
27
+ // variable is plain/url
28
+ if (!isResolvedDerivedVariable(resolved) &&
29
+ !isResolvedDataVariable(resolved) &&
30
+ !isResolvedDerivedDataVariable(resolved)) {
31
+ return resolved;
32
+ }
33
+ // data variable
34
+ if (isResolvedDataVariable(resolved)) {
35
+ return fetchDataVariable(resolved.uid, ctx.token, resolved.filters);
36
+ }
37
+ // derived variable
38
+ return fetchDerivedVariable({
39
+ cache: variable.cache,
40
+ force: false,
41
+ token: ctx.token,
42
+ uid: resolved.uid,
43
+ values: normalizeRequest(formatDerivedVariableRequest(resolved.values), variable.variables),
44
+ wsClient: ctx.client,
45
+ }).then((resp) => {
46
+ // This is really only used in DownloadVariable currently; we can add support for tasks
47
+ // if it is requested in the future
48
+ if (isTaskResponse(resp)) {
49
+ throw new Error('Task DerivedVariables are not supported in this context');
50
+ }
51
+ // for derived data variables we need to make another request to retrieve the filtered value
52
+ if (isDerivedDataVariable(variable)) {
53
+ return ctx.client
54
+ .getChannel()
55
+ .then((chan) => fetchDerivedDataVariable(variable.uid, ctx.token, resp.cache_key, chan, variable.filters));
56
+ }
57
+ return resp.value;
58
+ });
59
+ }
12
60
  /**
13
61
  * A helper hook that turns a Variable class into the actual value.
14
62
  * As opposed to the `useVariable` hook, this one returns a callback to retrieve the latest value
@@ -30,46 +78,12 @@ export default function useVariableValue(variable, shouldFetchVariable = false)
30
78
  }
31
79
  return useRecoilCallback(({ snapshot }) => {
32
80
  return () => {
33
- // Using loadable since the resolver is only used for simple atoms and shouldn't cause problems
34
- const resolved = resolveVariable(variable, client, taskContext, search, token, (v) => snapshot.getLoadable(v).getValue());
35
- // if we're NOT forced to fetch, or if it's not a DV/DDV/data variable, return the resolved value
36
- // variable is plain/url
37
- if (!shouldFetchVariable ||
38
- (!isDerivedVariable(variable) && !isDataVariable(variable) && !isDerivedDataVariable(variable))) {
39
- return resolved;
40
- }
41
- // we're forced to fetch but the resolved variable is not a resolved DV/data var, return the resolved value
42
- // variable is plain/url
43
- if (!isResolvedDerivedVariable(resolved) &&
44
- !isResolvedDataVariable(resolved) &&
45
- !isResolvedDerivedDataVariable(resolved)) {
46
- return resolved;
47
- }
48
- // data variable
49
- if (isResolvedDataVariable(resolved)) {
50
- return fetchDataVariable(resolved.uid, token, resolved.filters);
51
- }
52
- // derived variable
53
- return fetchDerivedVariable({
54
- cache: variable.cache,
55
- force: false,
81
+ return getVariableValue(variable, shouldFetchVariable, {
82
+ client,
83
+ search,
84
+ snapshot,
85
+ taskContext,
56
86
  token,
57
- uid: resolved.uid,
58
- values: normalizeRequest(formatDerivedVariableRequest(resolved.values), variable.variables),
59
- wsClient: client,
60
- }).then((resp) => {
61
- // This is really only used in DownloadVariable currently; we can add support for tasks
62
- // if it is requested in the future
63
- if (isTaskResponse(resp)) {
64
- throw new Error('Task DerivedVariables are not supported in this context');
65
- }
66
- // for derived data variables we need to make another request to retrieve the filtered value
67
- if (isDerivedDataVariable(variable)) {
68
- return client
69
- .getChannel()
70
- .then((chan) => fetchDerivedDataVariable(variable.uid, token, resp.cache_key, chan, variable.filters));
71
- }
72
- return resp.value;
73
87
  });
74
88
  };
75
89
  }, [variable.uid, useDeepCompare(taskContext), client, search, token]);
@@ -1 +1 @@
1
- {"version":3,"file":"use-variable-value.js","sourceRoot":"","sources":["../../../js/shared/interactivity/use-variable-value.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"use-variable-value.js","sourceRoot":"","sources":["../../../js/shared/interactivity/use-variable-value.tsx"],"names":[],"mappings":"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"}
@@ -1,16 +1,12 @@
1
1
  import { ReactNode } from 'react';
2
- import { Variable } from '../../types';
2
+ import { Action } from '../../types';
3
3
  interface PrivateRouteProps {
4
4
  /** The children to wrap */
5
5
  children: ReactNode;
6
- /** To have exact matching for the route path */
7
- exact?: boolean;
8
6
  /** Name of the page this route links to */
9
7
  name?: string;
10
- /** The route for the private route */
11
- path: string;
12
8
  /** Variables which should be reset upon visiting the page */
13
- reset_vars_on_load?: Variable<any>[];
9
+ on_load?: Action;
14
10
  }
15
11
  /**
16
12
  * The PrivateRoute component takes a private route object and checks for authentication.
@@ -18,6 +14,6 @@ interface PrivateRouteProps {
18
14
  *
19
15
  * @param props - the component props
20
16
  */
21
- declare function PrivateRoute({ children, path, exact, reset_vars_on_load, name, ...rest }: PrivateRouteProps): JSX.Element;
17
+ declare function PrivateRoute({ children, on_load, name }: PrivateRouteProps): ReactNode;
22
18
  export default PrivateRoute;
23
19
  //# sourceMappingURL=private-route.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"private-route.d.ts","sourceRoot":"","sources":["../../../js/shared/private-route/private-route.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAa,MAAM,OAAO,CAAC;AAM7C,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,UAAU,iBAAiB;IACvB,2BAA2B;IAC3B,QAAQ,EAAE,SAAS,CAAC;IACpB,gDAAgD;IAChD,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,2CAA2C;IAC3C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,sCAAsC;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,6DAA6D;IAC7D,kBAAkB,CAAC,EAAE,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;CACxC;AAED;;;;;GAKG;AACH,iBAAS,YAAY,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,kBAAkB,EAAE,IAAI,EAAE,GAAG,IAAI,EAAE,EAAE,iBAAiB,GAAG,GAAG,CAAC,OAAO,CA8BlH;AAED,eAAe,YAAY,CAAC"}
1
+ {"version":3,"file":"private-route.d.ts","sourceRoot":"","sources":["../../../js/shared/private-route/private-route.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAa,MAAM,OAAO,CAAC;AAO7C,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEjC,UAAU,iBAAiB;IACvB,2BAA2B;IAC3B,QAAQ,EAAE,SAAS,CAAC;IACpB,2CAA2C;IAC3C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,6DAA6D;IAC7D,OAAO,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;GAKG;AACH,iBAAS,YAAY,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,iBAAiB,GAAG,SAAS,CAiB/E;AAED,eAAe,YAAY,CAAC"}
@@ -1,20 +1,10 @@
1
- var __rest = (this && this.__rest) || function (s, e) {
2
- var t = {};
3
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
4
- t[p] = s[p];
5
- if (s != null && typeof Object.getOwnPropertySymbols === "function")
6
- for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
7
- if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
8
- t[p[i]] = s[p[i]];
9
- }
10
- return t;
11
- };
12
1
  import { jsx as _jsx } from "react/jsx-runtime";
13
2
  /* eslint-disable react-hooks/exhaustive-deps */
14
3
  import { useEffect } from 'react';
15
- import { Redirect, Route } from 'react-router-dom';
4
+ import { Redirect } from 'react-router-dom';
16
5
  import { useSessionToken } from '../../auth/auth-context';
17
- import { useResetVariables } from '../../shared/interactivity';
6
+ import DefaultFallback from '../../components/fallback/default';
7
+ import useAction from '../../shared/utils/use-action';
18
8
  import useWindowTitle from '../../shared/utils/use-window-title';
19
9
  /**
20
10
  * The PrivateRoute component takes a private route object and checks for authentication.
@@ -22,19 +12,19 @@ import useWindowTitle from '../../shared/utils/use-window-title';
22
12
  *
23
13
  * @param props - the component props
24
14
  */
25
- function PrivateRoute(_a) {
26
- var { children, path, exact, reset_vars_on_load, name } = _a, rest = __rest(_a, ["children", "path", "exact", "reset_vars_on_load", "name"]);
15
+ function PrivateRoute({ children, on_load, name }) {
27
16
  const token = useSessionToken();
28
- const resetVariables = useResetVariables(reset_vars_on_load !== null && reset_vars_on_load !== void 0 ? reset_vars_on_load : []);
17
+ const [onLoad, isLoading] = useAction(on_load);
29
18
  useWindowTitle(name);
30
19
  useEffect(() => {
31
- // On mount, reset variables which were specified
32
- resetVariables();
20
+ // On mount, call the on_load action
21
+ onLoad();
33
22
  }, []);
34
- return (_jsx(Route, Object.assign({}, rest, { exact: exact, path: path, render: ({ location }) => token ? (children) : (_jsx(Redirect, { to: {
35
- pathname: '/login',
36
- state: { from: location },
37
- } })) })));
23
+ if (!token) {
24
+ return _jsx(Redirect, { to: "/login" });
25
+ }
26
+ // Show fallback while the onLoad action is in progress
27
+ return isLoading ? _jsx(DefaultFallback, {}) : children;
38
28
  }
39
29
  export default PrivateRoute;
40
30
  //# sourceMappingURL=private-route.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"private-route.js","sourceRoot":"","sources":["../../../js/shared/private-route/private-route.tsx"],"names":[],"mappings":";;;;;;;;;;;;AAAA,gDAAgD;AAEhD,OAAO,EAAa,SAAS,EAAE,MAAM,OAAO,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAEnD,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,cAAc,MAAM,iCAAiC,CAAC;AAgB7D;;;;;GAKG;AACH,SAAS,YAAY,CAAC,EAA+E;QAA/E,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,kBAAkB,EAAE,IAAI,OAA8B,EAAzB,IAAI,cAA1D,2DAA4D,CAAF;IAC5E,MAAM,KAAK,GAAG,eAAe,EAAE,CAAC;IAChC,MAAM,cAAc,GAAG,iBAAiB,CAAC,kBAAkB,aAAlB,kBAAkB,cAAlB,kBAAkB,GAAI,EAAE,CAAC,CAAC;IAEnE,cAAc,CAAC,IAAI,CAAC,CAAC;IAErB,SAAS,CAAC,GAAG,EAAE;QACX,iDAAiD;QACjD,cAAc,EAAE,CAAC;IACrB,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO,CACH,KAAC,KAAK,oBACE,IAAI,IACR,KAAK,EAAE,KAAK,EACZ,IAAI,EAAE,IAAI,EACV,MAAM,EAAE,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CACrB,KAAK,CAAC,CAAC,CAAC,CACJ,QAAQ,CACX,CAAC,CAAC,CAAC,CACA,KAAC,QAAQ,IACL,EAAE,EAAE;gBACA,QAAQ,EAAE,QAAQ;gBAClB,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;aAC5B,GACH,CACL,IAEP,CACL,CAAC;AACN,CAAC;AAED,eAAe,YAAY,CAAC"}
1
+ {"version":3,"file":"private-route.js","sourceRoot":"","sources":["../../../js/shared/private-route/private-route.tsx"],"names":[],"mappings":";AAAA,gDAAgD;AAEhD,OAAO,EAAa,SAAS,EAAE,MAAM,OAAO,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,eAAe,MAAM,+BAA+B,CAAC;AAC5D,OAAO,SAAS,MAAM,2BAA2B,CAAC;AAClD,OAAO,cAAc,MAAM,iCAAiC,CAAC;AAY7D;;;;;GAKG;AACH,SAAS,YAAY,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAqB;IAChE,MAAM,KAAK,GAAG,eAAe,EAAE,CAAC;IAChC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC;IAE/C,cAAc,CAAC,IAAI,CAAC,CAAC;IAErB,SAAS,CAAC,GAAG,EAAE;QACX,oCAAoC;QACpC,MAAM,EAAE,CAAC;IACb,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,IAAI,CAAC,KAAK,EAAE;QACR,OAAO,KAAC,QAAQ,IAAC,EAAE,EAAC,QAAQ,GAAG,CAAC;KACnC;IAED,uDAAuD;IACvD,OAAO,SAAS,CAAC,CAAC,CAAC,KAAC,eAAe,KAAG,CAAC,CAAC,CAAC,QAAQ,CAAC;AACtD,CAAC;AAED,eAAe,YAAY,CAAC"}
@@ -1,6 +1,6 @@
1
- import { ActionDef, ActionInstance } from '../../types/core';
1
+ import { ActionDef, ActionImpl } from '../../types/core';
2
2
  interface ActionRegistryInterface {
3
- get: (instance: ActionInstance) => ActionDef;
3
+ get: (instance: ActionImpl) => ActionDef;
4
4
  }
5
5
  /**
6
6
  * The action registry pulls the full list of actions from the backend and then returns a function that allows a
@@ -1 +1 @@
1
- {"version":3,"file":"use-action-registry.d.ts","sourceRoot":"","sources":["../../../js/shared/utils/use-action-registry.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAEzD,UAAU,uBAAuB;IAC7B,GAAG,EAAE,CAAC,QAAQ,EAAE,cAAc,KAAK,SAAS,CAAC;CAChD;AAED;;;GAGG;AACH,iBAAS,iBAAiB,IAAI,uBAAuB,CAcpD;AAED,eAAe,iBAAiB,CAAC"}
1
+ {"version":3,"file":"use-action-registry.d.ts","sourceRoot":"","sources":["../../../js/shared/utils/use-action-registry.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAErD,UAAU,uBAAuB;IAC7B,GAAG,EAAE,CAAC,QAAQ,EAAE,UAAU,KAAK,SAAS,CAAC;CAC5C;AAED;;;GAGG;AACH,iBAAS,iBAAiB,IAAI,uBAAuB,CAapD;AAED,eAAe,iBAAiB,CAAC"}
@@ -1,4 +1,4 @@
1
- import { useCallback, useContext } from 'react';
1
+ import { useCallback, useContext, useMemo } from 'react';
2
2
  import RegistriesCtx from '../../shared/context/registries-context';
3
3
  /**
4
4
  * The action registry pulls the full list of actions from the backend and then returns a function that allows a
@@ -6,13 +6,13 @@ import RegistriesCtx from '../../shared/context/registries-context';
6
6
  */
7
7
  function useActionRegistry() {
8
8
  const { actionRegistry: actions } = useContext(RegistriesCtx);
9
- const get = useCallback((instance) => {
10
- if (actions && actions[instance.name]) {
11
- return actions[instance.name];
9
+ const get = useCallback((impl) => {
10
+ if (actions && actions[impl.name]) {
11
+ return actions[impl.name];
12
12
  }
13
- throw new Error(`Attempted to load an action (${instance.name}) that is not in the registry`);
13
+ throw new Error(`Attempted to load an action (${impl.name}) that is not in the registry`);
14
14
  }, [actions]);
15
- return { get };
15
+ return useMemo(() => ({ get }), [get]);
16
16
  }
17
17
  export default useActionRegistry;
18
18
  //# sourceMappingURL=use-action-registry.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"use-action-registry.js","sourceRoot":"","sources":["../../../js/shared/utils/use-action-registry.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AAEhD,OAAO,aAAa,MAAM,qCAAqC,CAAC;AAOhE;;;GAGG;AACH,SAAS,iBAAiB;IACtB,MAAM,EAAE,cAAc,EAAE,OAAO,EAAE,GAAG,UAAU,CAAC,aAAa,CAAC,CAAC;IAE9D,MAAM,GAAG,GAAG,WAAW,CACnB,CAAC,QAAwB,EAAa,EAAE;QACpC,IAAI,OAAO,IAAI,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE;YACnC,OAAO,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;SACjC;QACD,MAAM,IAAI,KAAK,CAAC,gCAAgC,QAAQ,CAAC,IAAI,+BAA+B,CAAC,CAAC;IAClG,CAAC,EACD,CAAC,OAAO,CAAC,CACZ,CAAC;IAEF,OAAO,EAAE,GAAG,EAAE,CAAC;AACnB,CAAC;AAED,eAAe,iBAAiB,CAAC"}
1
+ {"version":3,"file":"use-action-registry.js","sourceRoot":"","sources":["../../../js/shared/utils/use-action-registry.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAEzD,OAAO,aAAa,MAAM,qCAAqC,CAAC;AAOhE;;;GAGG;AACH,SAAS,iBAAiB;IACtB,MAAM,EAAE,cAAc,EAAE,OAAO,EAAE,GAAG,UAAU,CAAC,aAAa,CAAC,CAAC;IAE9D,MAAM,GAAG,GAAG,WAAW,CACnB,CAAC,IAAgB,EAAa,EAAE;QAC5B,IAAI,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;YAC/B,OAAO,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;SAC7B;QACD,MAAM,IAAI,KAAK,CAAC,gCAAgC,IAAI,CAAC,IAAI,+BAA+B,CAAC,CAAC;IAC9F,CAAC,EACD,CAAC,OAAO,CAAC,CACZ,CAAC;IACF,OAAO,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;AAC3C,CAAC;AAED,eAAe,iBAAiB,CAAC"}
@@ -1,9 +1,21 @@
1
1
  import { Action } from '../../types';
2
+ import { ActionContext, ActionImpl } from '../../types/core';
3
+ interface UseActionOptions {
4
+ /**
5
+ * Callback to invoke when an unhandled action is encountered.
6
+ * When not defined, an error notification will be shown instead.
7
+ *
8
+ * @param action action implementation
9
+ */
10
+ onUnhandledAction?: (action: ActionImpl, actionCtx: ActionContext) => void | Promise<void>;
11
+ }
2
12
  /**
3
13
  * Consume an action def from the framework and return a callback function that can be used to trigger it
4
14
  * and a loading state boolean indicating whether an action is currently in progress
5
15
  *
6
- * @param actionDefinition the action def passed in
16
+ * @param action the action passed in
17
+ * @param options optional extra options for the hook
7
18
  */
8
- export default function useAction(action: Action): [(value: any) => Promise<void>, boolean];
19
+ export default function useAction(action: Action, options?: UseActionOptions): [(input?: any) => Promise<void>, boolean];
20
+ export {};
9
21
  //# sourceMappingURL=use-action.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"use-action.d.ts","sourceRoot":"","sources":["../../../js/shared/utils/use-action.tsx"],"names":[],"mappings":"AAKA,OAAO,EAAE,MAAM,EAAyC,MAAM,SAAS,CAAC;AAuCxE;;;;;GAKG;AACH,MAAM,CAAC,OAAO,UAAU,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,CAAC,CAAC,KAAK,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,CA6C1F"}
1
+ {"version":3,"file":"use-action.d.ts","sourceRoot":"","sources":["../../../js/shared/utils/use-action.tsx"],"names":[],"mappings":"AAcA,OAAO,EAAE,MAAM,EAAiB,MAAM,SAAS,CAAC;AAChD,OAAO,EAAE,aAAa,EAAa,UAAU,EAAmB,MAAM,cAAc,CAAC;AAoOrF,UAAU,gBAAgB;IACtB;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,aAAa,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9F;AAED;;;;;;GAMG;AACH,MAAM,CAAC,OAAO,UAAU,SAAS,CAC7B,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,gBAAgB,GAC3B,CAAC,CAAC,KAAK,CAAC,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,CA4F3C"}
@@ -7,79 +7,273 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
7
7
  step((generator = generator.apply(thisArg, _arguments || [])).next());
8
8
  });
9
9
  };
10
- import { useCallback, useContext, useState } from 'react';
11
- import { useAsyncResource } from 'use-async-resource';
12
- import { useActionContext } from '../../actions/utils';
13
- import { ImportersCtx } from '../../shared/context';
10
+ import { useContext, useRef, useState } from 'react';
11
+ import { useHistory, useLocation } from 'react-router-dom';
12
+ import { useRecoilCallback } from 'recoil';
13
+ import { concatMap, takeWhile } from 'rxjs/operators';
14
+ import shortid from 'shortid';
15
+ import { useNotifications } from '@darajs/ui-notifications';
16
+ import { HTTP_METHOD, Status, validateResponse } from '@darajs/ui-utils';
17
+ import { fetchTaskResult } from '../../api';
18
+ import { request } from '../../api/http';
19
+ import { useSessionToken } from '../../auth/auth-context';
20
+ import { ImportersCtx, WebSocketCtx, useTaskContext } from '../../shared/context';
21
+ import { isActionImpl } from '../../types/utils';
22
+ import { resolveVariable } from '../interactivity/resolve-variable';
23
+ import { normalizeRequest } from './normalization';
14
24
  import useActionRegistry from './use-action-registry';
15
- // Disabling rules of hook since the followiing function are willingly breaking the rules, making the assumption that the components call
16
- // the exported functions with values which don't change the hook order etc
17
- /* eslint-disable react-hooks/rules-of-hooks */
18
- /* eslint-disable react-hooks/exhaustive-deps */
19
25
  /**
20
- * Helper method which converts an action into a list of hooks.
26
+ * Invoke a server-side action.
27
+ * This is used for annotated actions, sends a POST request to the server to start an action execution.
21
28
  *
22
- * @param action action(s) to import
23
- * @param getAction method to convert an action instance into its definition
29
+ * @param input input value for the action
30
+ * @param executionId unique id for the action execution; this should be used to subscribe to action messages **before** calling fetchAction
31
+ * @param annotatedAction annotated action instance
32
+ * @param actionCtx action context
33
+ */
34
+ function invokeAction(input, executionId, annotatedAction, actionCtx) {
35
+ return __awaiter(this, void 0, void 0, function* () {
36
+ // resolve kwargs to primitives, this registers variables if not already registered
37
+ const resolvedKwargs = Object.keys(annotatedAction.dynamic_kwargs).reduce((acc, k) => {
38
+ const value = annotatedAction.dynamic_kwargs[k];
39
+ acc[k] = resolveVariable(value, actionCtx.wsClient, actionCtx.taskCtx, actionCtx.location.search, actionCtx.sessionToken, (v) =>
40
+ // This is only called for primitive variables so it should always resolve successfully
41
+ // hence not using a promise
42
+ actionCtx.snapshot.getLoadable(v).getValue());
43
+ return acc;
44
+ }, {});
45
+ const ws_channel = yield actionCtx.wsClient.getChannel();
46
+ const res = yield request(`/api/core/action/${annotatedAction.definition_uid}`, {
47
+ body: JSON.stringify({
48
+ execution_id: executionId,
49
+ input,
50
+ uid: annotatedAction.uid,
51
+ values: normalizeRequest(resolvedKwargs, annotatedAction.dynamic_kwargs),
52
+ ws_channel,
53
+ }),
54
+ method: HTTP_METHOD.POST,
55
+ }, actionCtx.sessionToken);
56
+ yield validateResponse(res, `Failed to fetch the action value with uid: ${annotatedAction.uid}`);
57
+ const resContent = yield res.json();
58
+ // for tasks, wait for it to finish and fetch the result
59
+ // this is only used to pick up errors in the task execution
60
+ if ('task_id' in resContent) {
61
+ const taskId = resContent.task_id;
62
+ actionCtx.taskCtx.startTask(taskId);
63
+ yield actionCtx.wsClient.waitForTask(taskId);
64
+ actionCtx.taskCtx.endTask(taskId);
65
+ // We don't need the result as the MetaTask will send WS messages with actions as per usual
66
+ // fetchTaskResult will pick up on errors and raise them
67
+ yield fetchTaskResult(taskId, actionCtx.sessionToken);
68
+ }
69
+ });
70
+ }
71
+ /**
72
+ * Global cache of action handlers by name. Used for perf so each action will only have to be
73
+ * resolved once.
74
+ */
75
+ const ACTION_HANDLER_BY_NAME = {};
76
+ /**
77
+ * Error thrown when an action is not handled by the app.
78
+ */
79
+ class UnhandledActionError extends Error {
80
+ constructor(message, actionImpl) {
81
+ super(message);
82
+ this.actionImpl = actionImpl;
83
+ }
84
+ }
85
+ /**
86
+ * Resolve an action implementation into an action handler function.
87
+ *
88
+ * @param actionImpl action implementation
89
+ * @param getAction callback to get the action definition from the action implementation
24
90
  * @param importers importers available in the app
25
91
  */
26
- function getActionHooks(action, getAction, importers) {
92
+ function resolveActionImpl(actionImpl, getAction, importers) {
27
93
  return __awaiter(this, void 0, void 0, function* () {
28
- const hooks = [];
29
- const actions = Array.isArray(action) ? action : [action];
30
- for (const act of actions) {
31
- const actDef = getAction(act);
32
- // Doing this sequentially to preserve order and not break rules of hooks
33
- // eslint-disable-next-line no-await-in-loop
34
- const moduleContent = yield importers[actDef.py_module]();
35
- const Hook = moduleContent[actDef.name];
36
- hooks.push(Hook);
94
+ // cache action handler globally for performance, they are pure functions so it's safe to do so
95
+ if (!ACTION_HANDLER_BY_NAME[actionImpl.name]) {
96
+ // resolve action handler function by name
97
+ let actionDef;
98
+ try {
99
+ actionDef = getAction(actionImpl);
100
+ }
101
+ catch (_a) {
102
+ throw new UnhandledActionError(`Action definition for impl "${actionImpl.name}" not found`, actionImpl);
103
+ }
104
+ const moduleContent = yield importers[actionDef.py_module]();
105
+ ACTION_HANDLER_BY_NAME[actionImpl.name] = moduleContent[actionImpl.name];
37
106
  }
38
- return hooks;
107
+ return ACTION_HANDLER_BY_NAME[actionImpl.name];
39
108
  });
40
109
  }
110
+ /**
111
+ * Execute a given action.
112
+ *
113
+ * @param input component input value
114
+ * @param action action implementation or annotated action
115
+ * @param actionCtx action execution context
116
+ * @param getAction callback to get the action definition from the action implementation
117
+ * @param importers available importers in the app
118
+ */
119
+ function executeAction(input, action, actionCtx, getAction, importers) {
120
+ return __awaiter(this, void 0, void 0, function* () {
121
+ // if it's a simple action implementation, run the handler directly
122
+ if (isActionImpl(action)) {
123
+ const handler = yield resolveActionImpl(action, getAction, importers);
124
+ const result = handler(actionCtx, action);
125
+ // handle async handlers
126
+ if (result instanceof Promise) {
127
+ yield result;
128
+ }
129
+ return;
130
+ }
131
+ // otherwise call back to the server to execute the annotated action
132
+ // subscribe to action messages before even calling the action to avoid races
133
+ const executionId = shortid.generate();
134
+ const observable = actionCtx.wsClient.actionMessages$(executionId);
135
+ return new Promise((resolve, reject) => {
136
+ let activeTasks = 0; // Counter to keep track of active tasks
137
+ let streamCompleted = false; // Flag to check if the stream is completed
138
+ let isSettled = false;
139
+ let sub;
140
+ const checkForCompletion = () => {
141
+ if (!isSettled && streamCompleted && activeTasks === 0) {
142
+ isSettled = true;
143
+ sub.unsubscribe();
144
+ resolve();
145
+ }
146
+ };
147
+ const onError = (error) => {
148
+ // eslint-disable-next-line no-console
149
+ console.error('Error executing action:', error);
150
+ if (!isSettled) {
151
+ isSettled = true;
152
+ sub.unsubscribe();
153
+ reject(error);
154
+ }
155
+ };
156
+ sub = observable
157
+ .pipe(concatMap((actionImpl) => __awaiter(this, void 0, void 0, function* () {
158
+ if (actionImpl) {
159
+ const handler = yield resolveActionImpl(actionImpl, getAction, importers);
160
+ return [handler, actionImpl];
161
+ }
162
+ return null;
163
+ })), takeWhile((res) => !!res) // stop when falsy is returned from concatMap
164
+ )
165
+ .subscribe({
166
+ complete: () => {
167
+ streamCompleted = true; // Set the flag when the stream is complete
168
+ checkForCompletion();
169
+ },
170
+ error: onError,
171
+ next: ([handler, actionImpl]) => __awaiter(this, void 0, void 0, function* () {
172
+ try {
173
+ activeTasks += 1;
174
+ const result = handler(actionCtx, actionImpl);
175
+ // If it's a promise, await it to ensure sequential execution
176
+ if (result instanceof Promise) {
177
+ yield result;
178
+ }
179
+ }
180
+ catch (error) {
181
+ onError(error);
182
+ }
183
+ finally {
184
+ if (activeTasks > 0) {
185
+ activeTasks -= 1;
186
+ }
187
+ checkForCompletion();
188
+ }
189
+ }),
190
+ });
191
+ // now request the action to be executed
192
+ invokeAction(input, executionId, action, actionCtx).catch(onError);
193
+ });
194
+ });
195
+ }
196
+ const noop = () => Promise.resolve();
41
197
  /**
42
198
  * Consume an action def from the framework and return a callback function that can be used to trigger it
43
199
  * and a loading state boolean indicating whether an action is currently in progress
44
200
  *
45
- * @param actionDefinition the action def passed in
201
+ * @param action the action passed in
202
+ * @param options optional extra options for the hook
46
203
  */
47
- export default function useAction(action) {
48
- // Sanity check - it's technically possible to pass an ActionInstance or empty array and pydantic accepts them and converts to an ActionInstance
49
- if ((action === null || action === void 0 ? void 0 : action.name) === 'ActionInstance') {
50
- throw new Error('Expected a registered sub-class of "ActionInstance", base class detected');
51
- }
52
- // No action passed - noop
53
- if (!action || (Array.isArray(action) && action.length === 0)) {
54
- return [() => Promise.resolve(), false];
55
- }
56
- const [loading, setLoading] = useState(false);
204
+ export default function useAction(action, options) {
205
+ const { client: wsClient } = useContext(WebSocketCtx);
57
206
  const importers = useContext(ImportersCtx);
58
- const actionContext = useActionContext();
59
207
  const { get: getAction } = useActionRegistry();
60
- const [actionHooksReader] = useAsyncResource(getActionHooks, action, getAction, importers);
61
- // Call all action hooks and collect the callbacks
62
- const actionHooks = actionHooksReader();
63
- const actionCallbacks = [];
64
- const actions = Array.isArray(action) ? action : [action];
65
- for (const [index, actionHook] of actionHooks.entries()) {
66
- actionCallbacks.push(actionHook(actions[index], actionContext));
67
- }
68
- const actionCallback = useCallback((value) => __awaiter(this, void 0, void 0, function* () {
69
- // Track loading state for all actions
70
- setLoading(true);
71
- try {
72
- for (const actionCb of actionCallbacks) {
73
- // Sequentially execute actions to ensure deterministic order of execution
208
+ const notificationCtx = useNotifications();
209
+ const sessionToken = useSessionToken();
210
+ const history = useHistory();
211
+ const taskCtx = useTaskContext();
212
+ const location = useLocation();
213
+ const [isLoading, setIsLoading] = useState(false);
214
+ // keep actionCtx in a ref to avoid re-creating the callbacks
215
+ const actionCtx = useRef();
216
+ actionCtx.current = {
217
+ history,
218
+ location,
219
+ notificationCtx,
220
+ sessionToken,
221
+ taskCtx,
222
+ wsClient,
223
+ };
224
+ const optionsRef = useRef(options);
225
+ optionsRef.current = options;
226
+ const callback = useRecoilCallback((cbInterface) => (input) => __awaiter(this, void 0, void 0, function* () {
227
+ var _a;
228
+ setIsLoading(true);
229
+ const actionsToExecute = Array.isArray(action) ? action : [action];
230
+ // execute actions sequentially
231
+ for (const actionToExecute of actionsToExecute) {
232
+ // this is redefined for each action to have up-to-date snapshot
233
+ /* eslint-disable sort-keys-fix/sort-keys-fix */
234
+ const fullActionContext = Object.assign(Object.assign({}, actionCtx.current), { input,
235
+ // Recoil callback interface cannot be spread as it is a Proxy
236
+ gotoSnapshot: cbInterface.gotoSnapshot, refresh: cbInterface.refresh, reset: cbInterface.reset, set: cbInterface.set, snapshot: cbInterface.snapshot, transact_UNSTABLE: cbInterface.transact_UNSTABLE });
237
+ /* eslint-enable sort-keys-fix/sort-keys-fix */
238
+ try {
74
239
  // eslint-disable-next-line no-await-in-loop
75
- yield actionCb(value);
240
+ yield executeAction(input, actionToExecute, fullActionContext, getAction, importers);
241
+ }
242
+ catch (error) {
243
+ // Handle unhandled action errors separately
244
+ if (error instanceof UnhandledActionError) {
245
+ // there is a callback defined for it, call it
246
+ if ((_a = optionsRef.current) === null || _a === void 0 ? void 0 : _a.onUnhandledAction) {
247
+ const result = optionsRef.current.onUnhandledAction(error.actionImpl, fullActionContext);
248
+ if (result instanceof Promise) {
249
+ // eslint-disable-next-line no-await-in-loop
250
+ yield result;
251
+ }
252
+ }
253
+ else {
254
+ actionCtx.current.notificationCtx.pushNotification({
255
+ key: '_actionError',
256
+ message: `Action "${error.actionImpl.name}" not registered`,
257
+ status: Status.ERROR,
258
+ title: 'Error executing action',
259
+ });
260
+ }
261
+ continue;
262
+ }
263
+ actionCtx.current.notificationCtx.pushNotification({
264
+ key: '_actionError',
265
+ message: 'Try again or contact the application owner',
266
+ status: Status.ERROR,
267
+ title: 'Error executing action',
268
+ });
76
269
  }
77
270
  }
78
- finally {
79
- // make sure to clean up loading state regardless of errors
80
- setLoading(false);
81
- }
82
- }), [action, ...actionCallbacks]);
83
- return [actionCallback, loading];
271
+ setIsLoading(false);
272
+ }), [action, getAction, importers]);
273
+ // return a noop if no action is passed
274
+ if (!action) {
275
+ return [noop, false];
276
+ }
277
+ return [callback, isLoading];
84
278
  }
85
279
  //# sourceMappingURL=use-action.js.map