datastake-daf 0.6.842 → 0.6.844

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 (30) hide show
  1. package/dist/components/index.js +800 -774
  2. package/dist/hooks/index.js +4 -6
  3. package/dist/layouts/index.js +6 -0
  4. package/dist/pages/index.js +172 -115
  5. package/package.json +1 -1
  6. package/src/@daf/core/components/DynamicForm/hook.js +2 -2
  7. package/src/@daf/core/components/DynamicForm/index.jsx +1 -1
  8. package/src/@daf/core/components/Filters/selectFilters/index.jsx +7 -1
  9. package/src/@daf/core/components/Graphs/TradeRelationship/index.jsx +1 -27
  10. package/src/@daf/core/components/Graphs/components/BaseGraph.jsx +22 -18
  11. package/src/@daf/core/components/Screens/Admin/AdminModals/NewAccount/index.jsx +19 -6
  12. package/src/@daf/core/components/Screens/Admin/AdminScreens/Accounts.jsx +4 -1
  13. package/src/@daf/core/components/Screens/Admin/AdminTables/AccountTable/index.jsx +2 -0
  14. package/src/@daf/core/components/Select/MultiSelect/style.js +1 -1
  15. package/src/@daf/core/components/ViewForm/components/DataLink/flat.js +7 -3
  16. package/src/@daf/core/components/ViewForm/components/DataLink/index.js +6 -2
  17. package/src/@daf/core/components/ViewForm/components/input.js +7 -7
  18. package/src/@daf/hooks/useWidgetFetch.js +26 -35
  19. package/src/@daf/pages/Dashboards/ConflictManagement/components/RisksWidget/components/IncidentsTime/index.js +1 -0
  20. package/src/@daf/pages/ResetPassword/index.jsx +228 -228
  21. package/src/@daf/pages/Summary/Operator/components/KeyInformation/config.js +0 -1
  22. package/src/@daf/pages/Summary/Operator/components/TradeRelationships/helper.js +7 -5
  23. package/src/@daf/pages/Summary/Operator/components/TradeRelationships/hook.js +29 -14
  24. package/src/@daf/pages/Summary/Operator/components/TradeRelationships/index.js +69 -20
  25. package/src/@daf/pages/Summary/Operator/index.jsx +1 -0
  26. package/src/@daf/pages/Template/components/LinkingTemplate/config.js +1 -0
  27. package/src/@daf/pages/Template/components/LinkingTemplate/index.jsx +3 -1
  28. package/src/@daf/pages/View/index.jsx +1 -1
  29. package/src/@daf/services/LinkedSubjects.js +1 -0
  30. package/src/helpers/Forms.js +7 -5
@@ -1,6 +1,6 @@
1
1
  import PropTypes from 'prop-types'
2
2
  import { Button, Input, Tooltip } from 'antd';
3
- import React, { useMemo, useState } from 'react';
3
+ import React, { useMemo, useState, useEffect } from 'react';
4
4
  import { CustomSelect } from './Select.jsx';
5
5
  import { Timeframe } from './Timeframe.jsx';
6
6
  import { AjaxSelect } from "./AjaxSelect.jsx";
@@ -26,6 +26,12 @@ const SelectFilters = ({
26
26
  const [filters, setFilters] = useState(selectedFilters || {});
27
27
  const [initFilters, setInitFilters] = useState(selectedFilters || {})
28
28
 
29
+ // Sync internal state with selectedFilters prop when it changes
30
+ useEffect(() => {
31
+ setFilters(selectedFilters || {});
32
+ setInitFilters(selectedFilters || {});
33
+ }, [selectedFilters]);
34
+
29
35
  const getClearLabel = () => {
30
36
  switch (type) {
31
37
  case 'small':
@@ -21,7 +21,6 @@ function TradeRelationship({
21
21
  onFilterChange = () => {},
22
22
  renderTooltipItems = () => [],
23
23
  getTotal = () => 0,
24
- onRenderComplete = () => {},
25
24
  }) {
26
25
  const reactFlowWrapper = useRef(null);
27
26
  const [nodes, setNodes] = useNodesState([]);
@@ -31,31 +30,6 @@ function TradeRelationship({
31
30
  // const [initCenter, setInitCenter] = useState(true);
32
31
  const [associatedNodes, setAssociatedNodes] = useState(null);
33
32
 
34
- const isFullyRenderedRef = useRef(false);
35
- const [isFullyRendered, setIsFullyRendered] = useState(false);
36
-
37
- useEffect(() => {
38
- isFullyRenderedRef.current = false;
39
- setIsFullyRendered(false);
40
- setActiveNode(null);
41
- }, [data]);
42
-
43
- useEffect(() => {
44
- if (nodes.length > 0 && edges.length > 0 && !isFullyRenderedRef.current) {
45
- const timeoutId = setTimeout(() => {
46
- isFullyRenderedRef.current = true;
47
- setIsFullyRendered(true);
48
- onRenderComplete(true);
49
- }, 200);
50
-
51
- return () => clearTimeout(timeoutId);
52
- }
53
- if(nodes.length === 0 || edges.length === 0) {
54
- setIsFullyRendered(true);
55
- onRenderComplete(true);
56
- }
57
- }, [nodes.length, edges.length, associatedNodes]);
58
-
59
33
  useEffect(() => {
60
34
  setActiveNode(null);
61
35
  }, [data]);
@@ -274,7 +248,7 @@ function TradeRelationship({
274
248
 
275
249
  // Cleanup to prevent memory leaks if component unmounts quickly
276
250
  return () => clearTimeout(timeoutId);
277
- }, [data, activeNode]);
251
+ }, [data]);
278
252
 
279
253
  useEffect(() => {
280
254
  if (activeNode) {
@@ -2,7 +2,7 @@ import { ReactFlow, Controls, ControlButton, useReactFlow } from "@xyflow/react"
2
2
  import { UpOutlined, DownOutlined, AimOutlined } from "@ant-design/icons";
3
3
 
4
4
  import ComponentWithFocus from "../../Dashboard/ComponentWithFocus/index.jsx";
5
- import { forwardRef } from "react";
5
+ import { forwardRef, useRef } from "react";
6
6
  import { PrimaryNode, IconNode, NameNode, ExpandedNode } from "./Nodes/index.jsx";
7
7
  import { ToolTipEdge, VerticalPathEdge, DefaultEdge } from "./Edges/index.jsx";
8
8
  import Filters from "../../Filters/FloatingFilters/index.js";
@@ -38,6 +38,7 @@ const BaseGraph = forwardRef(function BaseGraph(
38
38
  ref,
39
39
  ) {
40
40
  const { setViewport, getViewport, fitView } = useReactFlow();
41
+ const hasInitialFitRef = useRef(false);
41
42
 
42
43
  const nodesToFit = useMemo(() => {
43
44
  let result;
@@ -49,31 +50,34 @@ const BaseGraph = forwardRef(function BaseGraph(
49
50
  return result;
50
51
  }, [nodes.length, mandatoryNodesToFit?.length, mandatoryNodesToFit]);
51
52
 
52
- // In BaseGraph.jsx, replace the useEffect with:
53
+ // Only auto-fit on initial render or when node count changes, not on property changes
53
54
  useEffect(() => {
54
55
  if (nodesToFit.length === 0) return;
55
56
 
56
- // Use setTimeout instead of requestAnimationFrame to ensure nodes are rendered
57
- const timer = setTimeout(() => {
58
- fitView({
59
- padding: 0.4,
60
- nodes: [...nodesToFit],
61
- // duration: withDuration ? 300 : undefined,
62
- maxZoom: 0.9,
63
- });
64
- }, 100); // Small delay to ensure nodes are rendered
57
+ // Only auto-fit on initial render or when node count changes
58
+ if (!hasInitialFitRef.current) {
59
+ hasInitialFitRef.current = true;
60
+
61
+ const timer = setTimeout(() => {
62
+ fitView({
63
+ padding: 0.4,
64
+ nodes: [...nodesToFit],
65
+ maxZoom: 0.9,
66
+ });
67
+ }, 100);
65
68
 
66
- return () => clearTimeout(timer);
67
- }, [nodesToFit.length, nodesToFit.map(n => `${n.id}-${n.width}-${n.height}`).join(','), withDuration]);
69
+ return () => clearTimeout(timer);
70
+ }
71
+ }, [nodesToFit.length, withDuration]);
68
72
 
69
73
  return (
70
74
  <ComponentWithFocus>
71
- <div style={{ height: "100%", width: "100%" }} ref={ref}>
72
- {filtersConfig ? (
73
- <Filters t={t} filtersConfig={filtersConfig} onFilterChange={onFilterChange} />
74
- ) : null}
75
+ <div style={{ height: "100%", width: "100%", position: "relative" }} ref={ref}>
76
+ {filtersConfig ? (
77
+ <Filters t={t} filtersConfig={filtersConfig} onFilterChange={onFilterChange} />
78
+ ) : null}
75
79
 
76
- <ReactFlow
80
+ <ReactFlow
77
81
  nodes={nodes}
78
82
  edges={edges}
79
83
  zoomOnDoubleClick={false}
@@ -1,7 +1,7 @@
1
1
  import Modal from "../../../../Modal/index.jsx";
2
- import { Form, Select, Input, Alert } from "antd";
2
+ import { Form, Select, Input, Alert, message } from "antd";
3
3
  import { useState, useEffect, useMemo } from "react";
4
-
4
+ import { findOptions } from "../../../../../../../helpers/StringHelper.js";
5
5
  export default function NewAccount({
6
6
  t,
7
7
  isOpen,
@@ -12,26 +12,32 @@ export default function NewAccount({
12
12
  inviteAccount,
13
13
  isPending=false,
14
14
  accountToEdit,
15
+ countries
15
16
  }) {
16
17
  const [MainForm] = Form.useForm();
17
18
  const [loading, setLoading] = useState(false);
18
19
  const [accountUsed, setAccountUsed] = useState(false);
19
20
 
20
21
 
21
-
22
22
  const isEdit = useMemo(() => accountToEdit && typeof accountToEdit === "object", [accountToEdit]);
23
23
 
24
+ const selectedCountry = useMemo(
25
+ () => findOptions(accountToEdit?.otherData?.country, countries),
26
+ [accountToEdit?.otherData?.country, countries]
27
+ );
28
+ console.log(selectedCountry, "selectedCountry");
24
29
  useEffect(() => {
25
30
  if (accountToEdit && typeof accountToEdit === "object") {
26
31
  MainForm.setFieldsValue({
27
32
  name: accountToEdit.name,
28
33
  email: accountToEdit.email,
29
34
  type: accountToEdit?.otherData?.interface,
35
+ country: selectedCountry,
30
36
  });
31
37
  } else {
32
38
  MainForm.resetFields();
33
39
  }
34
- }, [accountToEdit, MainForm]);
40
+ }, [accountToEdit, MainForm, selectedCountry]);
35
41
 
36
42
  const onSubmit = async () => {
37
43
  try {
@@ -45,6 +51,7 @@ export default function NewAccount({
45
51
  data: val,
46
52
  isPending: accountToEdit.status === 'pending' || isPending
47
53
  });
54
+ message.success(t("Account successfully updated"));
48
55
  } else {
49
56
  if (!inviteAccount) {
50
57
  throw new Error("inviteAccount function is required for creating new accounts");
@@ -80,7 +87,7 @@ export default function NewAccount({
80
87
  <Input placeholder={t("Type")} />
81
88
  </Form.Item>
82
89
 
83
-
90
+ {!isEdit && (
84
91
  <Form.Item
85
92
  name="email"
86
93
  label={t("Email")}
@@ -88,7 +95,13 @@ export default function NewAccount({
88
95
  >
89
96
  <Input placeholder={t("Type")} />
90
97
  </Form.Item>
91
-
98
+ )}
99
+ {isEdit && (
100
+ <Form.Item name="country" label={t("Country")} rules={[{ required: true }]}>
101
+ <Select placeholder={t("Select")} options={countries} />
102
+ </Form.Item>
103
+
104
+ )}
92
105
  <Form.Item name="type" label={t("Type")} rules={[{ required: true }]}>
93
106
  <Select placeholder={t("Select")} options={accountTypes || []} />
94
107
  </Form.Item>
@@ -49,6 +49,7 @@ export default function AdminAccountsScreen({ config }) {
49
49
  const query = useQuery ? useQuery() : { get: () => null };
50
50
  const [addAccountVisible, setAddAccountVisible] = useState(!!query.get("create"));
51
51
  const [accountToEdit, setAccountToEdit] = useState(null);
52
+ const [refetchTrigger, setRefetchTrigger] = useState(0);
52
53
 
53
54
 
54
55
 
@@ -102,6 +103,7 @@ function handleCopyInvitation(account) {
102
103
  headerTitle="accounts"
103
104
  actionButton={actionButtons}
104
105
  getData={handleGetData}
106
+ refetchTrigger={refetchTrigger}
105
107
  config={{
106
108
  accountTypes,
107
109
  addAccountVisible,
@@ -125,8 +127,9 @@ function handleCopyInvitation(account) {
125
127
  setAccountToEdit(null);
126
128
  }}
127
129
  accountTypes={accountTypes}
128
- countriesOptions={options?.countries}
130
+ countries={options?.countries}
129
131
  fetchData={() => {
132
+ setRefetchTrigger((prev) => prev + 1);
130
133
  }}
131
134
  inviteAccount={(data) => AdminService.inviteAccount(data)}
132
135
  updateAccount={({ data, id, isPending }) => AdminService.updateAccount({ data, id, isPending })}
@@ -33,6 +33,7 @@ export default function AccountTable({
33
33
  defaultPageSize = 20,
34
34
  actionButton,
35
35
  inviteAccount,
36
+ refetchTrigger,
36
37
  }) {
37
38
  const accountTypes = config?.accountTypes;
38
39
  const [showFilters, setShowFilters] = useState(false);
@@ -61,6 +62,7 @@ export default function AccountTable({
61
62
  getRedirectLink,
62
63
  getData,
63
64
  fetchPendingOnMount: true,
65
+ refetchTrigger,
64
66
  });
65
67
 
66
68
  const selectOptions = useMemo(() => {
@@ -5,7 +5,7 @@ const MultiSelectStyled = styled(Select)`
5
5
  &.ant-select-single {
6
6
  .ant-select-selector {
7
7
  padding-inline-end: 24px !important;
8
- padding: 0 !important;
8
+ padding: 3px !important;
9
9
  max-width: 56px !important;
10
10
  width: 56px !important;
11
11
  }
@@ -177,9 +177,13 @@ export default function DataLinkFlat({
177
177
  }, [entity, values.linking])
178
178
 
179
179
  const dataLinkFormData = useMemo(() => {
180
- const _formData = isSingle ? formData && !Array.isArray(formData)
181
- ? [{ ...form?.meta?.prefilledValues, ...formData }] : []
182
- : (Array.isArray(formData) ? formData : []).map((f) => ({ ...form?.meta?.prefilledValues, ...f }));
180
+ const filteredPrefilledValues = Object.entries(form?.meta?.prefilledValues || {})
181
+ .filter(([_, value]) => !(value && typeof value === 'object' && 'combine' in value))
182
+ .reduce((acc, [key, value]) => ({ ...acc, [key]: value }), {});
183
+
184
+ const _formData = isSingle ? formData && !Array.isArray(formData)
185
+ ? [{ ...filteredPrefilledValues, ...formData }] : []
186
+ : (Array.isArray(formData) ? formData : []).map((f) => ({ ...filteredPrefilledValues, ...f }));
183
187
 
184
188
  return (_formData || []).map((f, i) => {
185
189
  if (isAjaxModal && typeof f === 'string' && linkingData[f]) {
@@ -111,9 +111,13 @@ export default function DataLink({
111
111
  })
112
112
 
113
113
  const data = useMemo(() => {
114
+ const filteredPrefilledValues = Object.entries(form?.meta?.prefilledValues || {})
115
+ .filter(([_, value]) => !(value && typeof value === 'object' && 'combine' in value))
116
+ .reduce((acc, [key, value]) => ({ ...acc, [key]: value }), {});
117
+
114
118
  const _formData = isSingle ? formData && !Array.isArray(formData)
115
- ? [{ ...form?.meta?.prefilledValues, ...formData }] : []
116
- : (Array.isArray(formData) ? formData : []).map((f) => ({ ...form?.meta?.prefilledValues, ...f }));
119
+ ? [{ ...filteredPrefilledValues, ...formData }] : []
120
+ : (Array.isArray(formData) ? formData : []).map((f) => ({ ...filteredPrefilledValues, ...f }));
117
121
 
118
122
  return (_formData || []).map((f, i) => {
119
123
  if (isAjaxModal && typeof f === 'string' && linkingData[f]) {
@@ -361,13 +361,13 @@ export const BasicInput = ({
361
361
  case 'phoneNumber':
362
362
  case 'textarea':
363
363
  return item
364
- ? (propHasValue(item[inputName]) ? item[inputName] : placeholder(item, inputName, withPlaceholder))
365
- : (propHasValue(data[inputName]) ? data[inputName] : placeholder(data, inputName, withPlaceholder));
364
+ ? (propHasValue(item[inputName]) && item[inputName] !== '' ? item[inputName] : placeholder(item, inputName, withPlaceholder))
365
+ : (propHasValue(data[inputName]) && data[inputName] !== '' ? data[inputName] : placeholder(data, inputName, withPlaceholder));
366
366
  case 'website':
367
367
  case 'link':
368
368
  const v = item
369
- ? (propHasValue(item[inputName]) ? item[inputName] : placeholder(item, inputName, withPlaceholder))
370
- : (propHasValue(data[inputName]) ? data[inputName] : placeholder(data, inputName, withPlaceholder))
369
+ ? (propHasValue(item[inputName]) && item[inputName] !== '' ? item[inputName] : placeholder(item, inputName, withPlaceholder))
370
+ : (propHasValue(data[inputName]) && data[inputName] !== '' ? data[inputName] : placeholder(data, inputName, withPlaceholder))
371
371
 
372
372
  if (isModal) {
373
373
  return (
@@ -1023,7 +1023,7 @@ const Input = ({
1023
1023
  >
1024
1024
  </BasicInput>
1025
1025
  })}
1026
- {isRepeatable && Array.isArray(modalData) && !modalData.length ? (
1026
+ {isRepeatable && Array.isArray(modalData) && !modalData.length || modalData === "" ? (
1027
1027
  <span className="text-muted">{t('Not answered')}</span>
1028
1028
  ) : null}
1029
1029
  </React.Fragment>
@@ -1068,7 +1068,7 @@ const Input = ({
1068
1068
  })
1069
1069
  }
1070
1070
  {
1071
- (!modalData || (Array.isArray(modalData) && !modalData.length)) ? (
1071
+ (!modalData || (Array.isArray(modalData) && !modalData.length) || modalData === "") ? (
1072
1072
  <span className="text-muted">{t('Not answered')}</span>
1073
1073
  ) : (
1074
1074
  (Array.isArray(modalData) ? modalData : [modalData]).map((item, itemId) => (
@@ -1174,7 +1174,7 @@ const Input = ({
1174
1174
  >
1175
1175
  </BasicInput>
1176
1176
  })}
1177
- {(!formData || (Array.isArray(formData) && !formData.length)) ? (
1177
+ {(!formData || (Array.isArray(formData) && !formData.length) || formData === "") ? (
1178
1178
  <span className="text-muted">{t('Not answered')}</span>
1179
1179
  ) : (
1180
1180
  (Array.isArray(formData) ? formData : [formData])?.map((item, itemId) => (
@@ -2,7 +2,6 @@ import { useState, useEffect, useRef } from "react";
2
2
  import DashboardService from "../services/DashboardService.js";
3
3
  import { isErrorResponse, getErrorMessage } from "../../helpers/errorHandling.js";
4
4
  import { message } from "antd";
5
-
6
5
  // config: {
7
6
  // stop: boolean,
8
7
  // defaultData: object,
@@ -10,56 +9,48 @@ import { message } from "antd";
10
9
  // url: string
11
10
  // basePath: string,
12
11
  // }
13
-
14
12
  export const useWidgetFetch = ({config, getData = DashboardService.getWidget, onFetch = () => {}}) => {
15
13
  const { stop, defaultData, ...rest} = config;
16
14
  const [ data, setData ] = useState(defaultData || {});
17
15
  const [ loading, setLoading ] = useState(false);
18
16
  const [ initFetchDone, setInitFetchDone ] = useState(false);
19
17
  const isMounted = useRef(true);
20
-
21
- const fetchData = async () => {
22
- if (stop) {
23
- return;
24
- }
25
-
26
- setLoading(true);
27
-
28
- try {
29
- const { data } = await getData(rest);
30
- if (!isMounted.current) return;
31
- setData(data || defaultData);
32
- if (isErrorResponse(data)) {
33
- const errorMessage = getErrorMessage(data);
34
- message.error(errorMessage);
35
- return;
36
- }
18
+
19
+ const fetchData = async () => {
20
+ setLoading(true);
21
+ try {
22
+ const { data } = await getData(rest);
23
+ if (!isMounted.current) return;
24
+ setData(data || defaultData);
25
+ if (isErrorResponse(data)) {
26
+ const errorMessage = getErrorMessage(data);
27
+ message.error(errorMessage);
28
+ return;
29
+ }
37
30
  onFetch();
38
31
  setInitFetchDone(true);
39
- } catch (err) {
40
- console.log(err);
41
- }
42
-
43
- if (isMounted.current) {
44
- setLoading(false);
45
- }
46
- };
47
-
32
+ } catch (err) {
33
+ console.log(err);
34
+ }
35
+ if (isMounted.current) {
36
+ setLoading(false);
37
+ }
38
+ };
48
39
  useEffect(() => {
49
40
  isMounted.current = true;
50
41
  return () => {
51
42
  isMounted.current = false;
52
43
  };
53
44
  }, []);
54
-
55
- useEffect(() => {
56
- fetchData();
57
- }, [JSON.stringify(config)]);
58
-
45
+ useEffect(() => {
46
+ if(!stop) {
47
+ fetchData();
48
+ }
49
+ }, [JSON.stringify(config), stop]);
59
50
  return {
60
51
  data,
61
52
  loading,
62
- setData,
53
+ setData,
63
54
  initFetchDone
64
55
  }
65
- }
56
+ }
@@ -92,6 +92,7 @@ export default function IncidentsTimeline({
92
92
  if (selectedRange === "12") return baseMonths.map((m) => m.label);
93
93
  return baseWeeks.map((w) => w.label);
94
94
  }, [selectedRange, baseMonths, baseWeeks]);
95
+ console.log({filtersConfig})
95
96
 
96
97
  const getTooltipContent = useCallback(
97
98
  ({ item }) => {