@nnkogift/dhis2-form-utils-devtools 0.1.0-alpha.4 → 0.1.0-alpha.6

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 (80) hide show
  1. package/dist/EffectBadge.d.ts +17 -0
  2. package/dist/EffectBadge.js +55 -0
  3. package/dist/EffectBadge.js.map +1 -0
  4. package/dist/RuleDetailsModal.d.ts +30 -0
  5. package/dist/RuleDetailsModal.js +403 -0
  6. package/dist/RuleDetailsModal.js.map +1 -0
  7. package/dist/RuleDevtoolsScope.d.ts +14 -0
  8. package/dist/RuleDevtoolsScope.js +25 -0
  9. package/dist/RuleDevtoolsScope.js.map +1 -0
  10. package/dist/RuleGraphModal.d.ts +17 -0
  11. package/dist/RuleGraphModal.js +35 -0
  12. package/dist/RuleGraphModal.js.map +1 -0
  13. package/dist/RuleGraphView.d.ts +43 -0
  14. package/dist/RuleGraphView.js +401 -0
  15. package/dist/RuleGraphView.js.map +1 -0
  16. package/dist/RulesPanel.d.ts +19 -0
  17. package/dist/RulesPanel.js +463 -0
  18. package/dist/RulesPanel.js.map +1 -0
  19. package/dist/RulesPanelGraphFallback.d.ts +5 -0
  20. package/dist/RulesPanelGraphFallback.js +19 -0
  21. package/dist/RulesPanelGraphFallback.js.map +1 -0
  22. package/dist/TraceTimeline.d.ts +16 -0
  23. package/dist/TraceTimeline.js +227 -0
  24. package/dist/TraceTimeline.js.map +1 -0
  25. package/dist/attach.d.ts +12 -0
  26. package/dist/attach.js +14 -0
  27. package/dist/attach.js.map +1 -0
  28. package/dist/buildGraph.d.ts +25 -0
  29. package/dist/buildGraph.js +67 -0
  30. package/dist/buildGraph.js.map +1 -0
  31. package/dist/constants.d.ts +3 -0
  32. package/dist/constants.js +5 -0
  33. package/dist/constants.js.map +1 -0
  34. package/dist/createLabelLookup.d.ts +25 -0
  35. package/dist/createLabelLookup.js +81 -0
  36. package/dist/createLabelLookup.js.map +1 -0
  37. package/dist/effectStyles.d.ts +28 -0
  38. package/dist/effectStyles.js +142 -0
  39. package/dist/effectStyles.js.map +1 -0
  40. package/dist/formatAgo.d.ts +3 -0
  41. package/dist/formatAgo.js +25 -0
  42. package/dist/formatAgo.js.map +1 -0
  43. package/dist/formatRuleActionSummary.d.ts +33 -0
  44. package/dist/formatRuleActionSummary.js +61 -0
  45. package/dist/formatRuleActionSummary.js.map +1 -0
  46. package/dist/graphLayout.d.ts +48 -0
  47. package/dist/graphLayout.js +137 -0
  48. package/dist/graphLayout.js.map +1 -0
  49. package/dist/graphNodeStyles.d.ts +9 -0
  50. package/dist/graphNodeStyles.js +22 -0
  51. package/dist/graphNodeStyles.js.map +1 -0
  52. package/dist/i18n.d.ts +4 -0
  53. package/dist/i18n.js +9 -0
  54. package/dist/i18n.js.map +1 -0
  55. package/dist/index.cjs +1364 -651
  56. package/dist/index.cjs.map +1 -1
  57. package/dist/index.css +1 -1
  58. package/dist/index.d.cts +12 -63
  59. package/dist/index.d.ts +12 -63
  60. package/dist/index.js +5 -1669
  61. package/dist/index.js.map +1 -1
  62. package/dist/programRuleDetailQuery.d.ts +70 -0
  63. package/dist/programRuleDetailQuery.js +42 -0
  64. package/dist/programRuleDetailQuery.js.map +1 -0
  65. package/dist/resolveProgramRulesList.d.ts +21 -0
  66. package/dist/resolveProgramRulesList.js +45 -0
  67. package/dist/resolveProgramRulesList.js.map +1 -0
  68. package/dist/traceEntry.d.ts +12 -0
  69. package/dist/traceEntry.js +20 -0
  70. package/dist/traceEntry.js.map +1 -0
  71. package/dist/traceStore.d.ts +12 -0
  72. package/dist/traceStore.js +39 -0
  73. package/dist/traceStore.js.map +1 -0
  74. package/dist/useFlipReorder.d.ts +8 -0
  75. package/dist/useFlipReorder.js +52 -0
  76. package/dist/useFlipReorder.js.map +1 -0
  77. package/dist/useProgramRuleDetail.d.ts +17 -0
  78. package/dist/useProgramRuleDetail.js +30 -0
  79. package/dist/useProgramRuleDetail.js.map +1 -0
  80. package/package.json +27 -4
@@ -0,0 +1,142 @@
1
+ import { IconInfo16, IconLink16, IconMail16, IconMessages16, IconErrorFilled16, IconWarningFilled16, IconStarFilled16, IconEdit16, IconView16, IconViewOff16 } from '@dhis2/ui';
2
+
3
+ const EFFECT_VARIANT = {
4
+ HIDEFIELD: "hide",
5
+ HIDEOPTION: "hide",
6
+ HIDEOPTIONGROUP: "hide",
7
+ HIDESECTION: "hide",
8
+ HIDEPROGRAMSTAGE: "hide",
9
+ SHOWFIELD: "show",
10
+ SHOWOPTION: "show",
11
+ SHOWOPTIONGROUP: "show",
12
+ ASSIGN: "assign",
13
+ SETMANDATORYFIELD: "mandatory",
14
+ UNSETMANDATORYFIELD: "mandatory",
15
+ SHOWWARNING: "warning",
16
+ WARNINGONCOMPLETE: "warning",
17
+ SHOWERROR: "error",
18
+ ERRORONCOMPLETE: "error",
19
+ DISPLAYTEXT: "feedback",
20
+ DISPLAYKEYVALUEPAIR: "feedback",
21
+ SENDMESSAGE: "message",
22
+ SCHEDULEMESSAGE: "message",
23
+ read: "read"
24
+ };
25
+ const EFFECT_VISUALS = {
26
+ hide: {
27
+ tagClassName: "bg-dhis2-grey-200 text-dhis2-grey-900",
28
+ edgeStroke: "#494949",
29
+ shortLabel: "hide"
30
+ },
31
+ show: {
32
+ tagClassName: "bg-dhis2-green-100 text-dhis2-green-900",
33
+ edgeStroke: "#388e3c",
34
+ shortLabel: "show"
35
+ },
36
+ assign: {
37
+ tagClassName: "bg-dhis2-blue-100 text-dhis2-blue-900",
38
+ edgeStroke: "#1565c0",
39
+ shortLabel: "assign"
40
+ },
41
+ mandatory: {
42
+ tagClassName: "bg-dhis2-yellow-100 text-dhis2-yellow-900",
43
+ edgeStroke: "#e56408",
44
+ shortLabel: "required"
45
+ },
46
+ warning: {
47
+ tagClassName: "bg-dhis2-yellow-100 text-dhis2-yellow-900",
48
+ edgeStroke: "#ff8302",
49
+ shortLabel: "warn"
50
+ },
51
+ error: {
52
+ tagClassName: "bg-dhis2-red-100 text-dhis2-red-900",
53
+ edgeStroke: "#c62828",
54
+ shortLabel: "error"
55
+ },
56
+ feedback: {
57
+ tagClassName: "bg-dhis2-purple-100 text-dhis2-purple-900",
58
+ edgeStroke: "#9c27b0",
59
+ shortLabel: "feedback"
60
+ },
61
+ message: {
62
+ tagClassName: "bg-dhis2-teal-100 text-dhis2-teal-900",
63
+ edgeStroke: "#00796b",
64
+ shortLabel: "message"
65
+ },
66
+ read: {
67
+ tagClassName: "bg-dhis2-teal-100 text-dhis2-teal-900",
68
+ edgeStroke: "#00796b",
69
+ shortLabel: "read"
70
+ },
71
+ default: {
72
+ tagClassName: "bg-dhis2-grey-100 text-dhis2-grey-800",
73
+ edgeStroke: "#494949",
74
+ shortLabel: "effect"
75
+ }
76
+ };
77
+ const EFFECT_ICONS = {
78
+ hide: IconViewOff16,
79
+ show: IconView16,
80
+ assign: IconEdit16,
81
+ mandatory: IconStarFilled16,
82
+ warning: IconWarningFilled16,
83
+ error: IconErrorFilled16,
84
+ feedback: IconMessages16,
85
+ message: IconMail16,
86
+ read: IconLink16,
87
+ default: IconInfo16
88
+ };
89
+ function getEffectVariant(type) {
90
+ return EFFECT_VARIANT[type] ?? "default";
91
+ }
92
+ function getEffectVisual(type) {
93
+ const variant = getEffectVariant(type);
94
+ return { variant, ...EFFECT_VISUALS[variant] };
95
+ }
96
+ function getEffectTagVariant(type) {
97
+ return getEffectVariant(type);
98
+ }
99
+ const TAG_LAYOUT_CLASS = "max-w-full break-words";
100
+ function tagPropsForVariant(variant) {
101
+ switch (variant) {
102
+ case "show":
103
+ return { positive: true, className: TAG_LAYOUT_CLASS };
104
+ case "error":
105
+ return { negative: true, className: TAG_LAYOUT_CLASS };
106
+ case "assign":
107
+ return { neutral: true, className: TAG_LAYOUT_CLASS };
108
+ case "hide":
109
+ case "mandatory":
110
+ case "warning":
111
+ case "feedback":
112
+ case "message":
113
+ case "read":
114
+ return {
115
+ className: `${TAG_LAYOUT_CLASS} ${EFFECT_VISUALS[variant].tagClassName}`
116
+ };
117
+ default:
118
+ return {
119
+ className: `${TAG_LAYOUT_CLASS} ${EFFECT_VISUALS.default.tagClassName}`
120
+ };
121
+ }
122
+ }
123
+ function getEffectTagRenderProps(type) {
124
+ return tagPropsForVariant(getEffectVariant(type));
125
+ }
126
+ function getEffectTagRenderPropsForVariant(variant) {
127
+ return tagPropsForVariant(variant);
128
+ }
129
+ function getEffectEdgeStroke(type, highlighted = true) {
130
+ const { edgeStroke } = getEffectVisual(type);
131
+ if (highlighted) {
132
+ return edgeStroke;
133
+ }
134
+ return "#bdbdbd";
135
+ }
136
+ function getEffectShortLabel(type) {
137
+ return getEffectVisual(type).shortLabel;
138
+ }
139
+
140
+ export { EFFECT_ICONS, getEffectEdgeStroke, getEffectShortLabel, getEffectTagRenderProps, getEffectTagRenderPropsForVariant, getEffectTagVariant, getEffectVariant, getEffectVisual };
141
+ //# sourceMappingURL=effectStyles.js.map
142
+ //# sourceMappingURL=effectStyles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/effectStyles.ts"],"names":[],"mappings":"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","file":"effectStyles.js","sourcesContent":["import type { FC } from 'react';\nimport {\n IconEdit16,\n IconErrorFilled16,\n IconInfo16,\n IconLink16,\n IconMail16,\n IconMessages16,\n IconStarFilled16,\n IconView16,\n IconViewOff16,\n IconWarningFilled16,\n type IconProps,\n} from '@dhis2/ui';\n\nexport type EffectVisualVariant =\n | 'hide'\n | 'show'\n | 'assign'\n | 'mandatory'\n | 'warning'\n | 'error'\n | 'feedback'\n | 'message'\n | 'read'\n | 'default';\n\nexport type EffectVisual = {\n variant: EffectVisualVariant;\n tagClassName: string;\n edgeStroke: string;\n shortLabel: string;\n};\n\nconst EFFECT_VARIANT: Record<string, EffectVisualVariant> = {\n HIDEFIELD: 'hide',\n HIDEOPTION: 'hide',\n HIDEOPTIONGROUP: 'hide',\n HIDESECTION: 'hide',\n HIDEPROGRAMSTAGE: 'hide',\n SHOWFIELD: 'show',\n SHOWOPTION: 'show',\n SHOWOPTIONGROUP: 'show',\n ASSIGN: 'assign',\n SETMANDATORYFIELD: 'mandatory',\n UNSETMANDATORYFIELD: 'mandatory',\n SHOWWARNING: 'warning',\n WARNINGONCOMPLETE: 'warning',\n SHOWERROR: 'error',\n ERRORONCOMPLETE: 'error',\n DISPLAYTEXT: 'feedback',\n DISPLAYKEYVALUEPAIR: 'feedback',\n SENDMESSAGE: 'message',\n SCHEDULEMESSAGE: 'message',\n read: 'read',\n};\n\nconst EFFECT_VISUALS: Record<EffectVisualVariant, Omit<EffectVisual, 'variant'>> = {\n hide: {\n tagClassName: 'bg-dhis2-grey-200 text-dhis2-grey-900',\n edgeStroke: '#494949',\n shortLabel: 'hide',\n },\n show: {\n tagClassName: 'bg-dhis2-green-100 text-dhis2-green-900',\n edgeStroke: '#388e3c',\n shortLabel: 'show',\n },\n assign: {\n tagClassName: 'bg-dhis2-blue-100 text-dhis2-blue-900',\n edgeStroke: '#1565c0',\n shortLabel: 'assign',\n },\n mandatory: {\n tagClassName: 'bg-dhis2-yellow-100 text-dhis2-yellow-900',\n edgeStroke: '#e56408',\n shortLabel: 'required',\n },\n warning: {\n tagClassName: 'bg-dhis2-yellow-100 text-dhis2-yellow-900',\n edgeStroke: '#ff8302',\n shortLabel: 'warn',\n },\n error: {\n tagClassName: 'bg-dhis2-red-100 text-dhis2-red-900',\n edgeStroke: '#c62828',\n shortLabel: 'error',\n },\n feedback: {\n tagClassName: 'bg-dhis2-purple-100 text-dhis2-purple-900',\n edgeStroke: '#9c27b0',\n shortLabel: 'feedback',\n },\n message: {\n tagClassName: 'bg-dhis2-teal-100 text-dhis2-teal-900',\n edgeStroke: '#00796b',\n shortLabel: 'message',\n },\n read: {\n tagClassName: 'bg-dhis2-teal-100 text-dhis2-teal-900',\n edgeStroke: '#00796b',\n shortLabel: 'read',\n },\n default: {\n tagClassName: 'bg-dhis2-grey-100 text-dhis2-grey-800',\n edgeStroke: '#494949',\n shortLabel: 'effect',\n },\n};\n\nexport const EFFECT_ICONS: Record<EffectVisualVariant, FC<IconProps>> = {\n hide: IconViewOff16,\n show: IconView16,\n assign: IconEdit16,\n mandatory: IconStarFilled16,\n warning: IconWarningFilled16,\n error: IconErrorFilled16,\n feedback: IconMessages16,\n message: IconMail16,\n read: IconLink16,\n default: IconInfo16,\n};\n\n/** @deprecated Use getEffectVisual().variant */\nexport type EffectTagVariant = EffectVisualVariant;\n\nexport function getEffectVariant(type: string): EffectVisualVariant {\n return EFFECT_VARIANT[type] ?? 'default';\n}\n\nexport function getEffectVisual(type: string): EffectVisual {\n const variant = getEffectVariant(type);\n return { variant, ...EFFECT_VISUALS[variant] };\n}\n\nexport function getEffectTagVariant(type: string): EffectVisualVariant {\n return getEffectVariant(type);\n}\n\nexport type EffectTagRenderProps = {\n neutral?: boolean;\n positive?: boolean;\n negative?: boolean;\n className?: string;\n};\n\nconst TAG_LAYOUT_CLASS = 'max-w-full break-words';\n\nfunction tagPropsForVariant(variant: EffectVisualVariant): EffectTagRenderProps {\n switch (variant) {\n case 'show':\n return { positive: true, className: TAG_LAYOUT_CLASS };\n case 'error':\n return { negative: true, className: TAG_LAYOUT_CLASS };\n case 'assign':\n return { neutral: true, className: TAG_LAYOUT_CLASS };\n case 'hide':\n case 'mandatory':\n case 'warning':\n case 'feedback':\n case 'message':\n case 'read':\n return {\n className: `${TAG_LAYOUT_CLASS} ${EFFECT_VISUALS[variant].tagClassName}`,\n };\n default:\n return {\n className: `${TAG_LAYOUT_CLASS} ${EFFECT_VISUALS.default.tagClassName}`,\n };\n }\n}\n\nexport function getEffectTagRenderProps(type: string): EffectTagRenderProps {\n return tagPropsForVariant(getEffectVariant(type));\n}\n\nexport function getEffectTagRenderPropsForVariant(\n variant: EffectVisualVariant\n): EffectTagRenderProps {\n return tagPropsForVariant(variant);\n}\n\nexport function getEffectEdgeStroke(type: string, highlighted = true): string {\n const { edgeStroke } = getEffectVisual(type);\n if (highlighted) {\n return edgeStroke;\n }\n return '#bdbdbd';\n}\n\nexport function getEffectShortLabel(type: string): string {\n return getEffectVisual(type).shortLabel;\n}\n"]}
@@ -0,0 +1,3 @@
1
+ declare function formatAgo(timestamp: number, now?: number): string;
2
+
3
+ export { formatAgo };
@@ -0,0 +1,25 @@
1
+ import { translate } from './i18n.js';
2
+
3
+ function formatAgo(timestamp, now = Date.now()) {
4
+ const diffMs = Math.max(0, now - timestamp);
5
+ if (diffMs < 5e3) {
6
+ return translate("just now");
7
+ }
8
+ const seconds = Math.floor(diffMs / 1e3);
9
+ if (seconds < 60) {
10
+ return translate("{{seconds}}s ago", { seconds });
11
+ }
12
+ const minutes = Math.floor(seconds / 60);
13
+ if (minutes < 60) {
14
+ return translate("{{minutes}}m ago", { minutes });
15
+ }
16
+ const hours = Math.floor(minutes / 60);
17
+ if (hours < 24) {
18
+ return translate("{{hours}}h ago", { hours });
19
+ }
20
+ return new Date(timestamp).toLocaleString();
21
+ }
22
+
23
+ export { formatAgo };
24
+ //# sourceMappingURL=formatAgo.js.map
25
+ //# sourceMappingURL=formatAgo.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/formatAgo.ts"],"names":[],"mappings":";;AAEO,SAAS,SAAA,CAAU,SAAA,EAAmB,GAAA,GAAM,IAAA,CAAK,KAAI,EAAW;AACnE,EAAA,MAAM,MAAA,GAAS,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,MAAM,SAAS,CAAA;AAE1C,EAAA,IAAI,SAAS,GAAA,EAAO;AAChB,IAAA,OAAO,UAAU,UAAU,CAAA;AAAA,EAC/B;AAEA,EAAA,MAAM,OAAA,GAAU,IAAA,CAAK,KAAA,CAAM,MAAA,GAAS,GAAK,CAAA;AACzC,EAAA,IAAI,UAAU,EAAA,EAAI;AACd,IAAA,OAAO,SAAA,CAAU,kBAAA,EAAoB,EAAE,OAAA,EAAS,CAAA;AAAA,EACpD;AAEA,EAAA,MAAM,OAAA,GAAU,IAAA,CAAK,KAAA,CAAM,OAAA,GAAU,EAAE,CAAA;AACvC,EAAA,IAAI,UAAU,EAAA,EAAI;AACd,IAAA,OAAO,SAAA,CAAU,kBAAA,EAAoB,EAAE,OAAA,EAAS,CAAA;AAAA,EACpD;AAEA,EAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,KAAA,CAAM,OAAA,GAAU,EAAE,CAAA;AACrC,EAAA,IAAI,QAAQ,EAAA,EAAI;AACZ,IAAA,OAAO,SAAA,CAAU,gBAAA,EAAkB,EAAE,KAAA,EAAO,CAAA;AAAA,EAChD;AAEA,EAAA,OAAO,IAAI,IAAA,CAAK,SAAS,CAAA,CAAE,cAAA,EAAe;AAC9C","file":"formatAgo.js","sourcesContent":["import { translate } from './i18n.js';\n\nexport function formatAgo(timestamp: number, now = Date.now()): string {\n const diffMs = Math.max(0, now - timestamp);\n\n if (diffMs < 5_000) {\n return translate('just now');\n }\n\n const seconds = Math.floor(diffMs / 1_000);\n if (seconds < 60) {\n return translate('{{seconds}}s ago', { seconds });\n }\n\n const minutes = Math.floor(seconds / 60);\n if (minutes < 60) {\n return translate('{{minutes}}m ago', { minutes });\n }\n\n const hours = Math.floor(minutes / 60);\n if (hours < 24) {\n return translate('{{hours}}h ago', { hours });\n }\n\n return new Date(timestamp).toLocaleString();\n}\n"]}
@@ -0,0 +1,33 @@
1
+ import { DevtoolsLabelLookup } from './createLabelLookup.js';
2
+ import '@nnkogift/dhis2-form-utils-metadata';
3
+
4
+ type RuleActionLike = {
5
+ programRuleActionType?: string;
6
+ dataElement?: {
7
+ id?: string;
8
+ displayName?: string;
9
+ };
10
+ trackedEntityAttribute?: {
11
+ id?: string;
12
+ displayName?: string;
13
+ };
14
+ programStageSection?: {
15
+ id?: string;
16
+ displayName?: string;
17
+ };
18
+ programSection?: {
19
+ id?: string;
20
+ displayName?: string;
21
+ };
22
+ data?: string | null;
23
+ content?: string | null;
24
+ location?: string | null;
25
+ };
26
+ type FormattedRuleAction = {
27
+ type: string;
28
+ targetLabel: string;
29
+ detail?: string;
30
+ };
31
+ declare function formatRuleActionSummary(action: RuleActionLike, labelLookup?: DevtoolsLabelLookup): FormattedRuleAction;
32
+
33
+ export { type FormattedRuleAction, type RuleActionLike, formatRuleActionSummary };
@@ -0,0 +1,61 @@
1
+ function resolveFieldLabel(id, displayName, labelLookup) {
2
+ if (labelLookup) {
3
+ const resolved = labelLookup.resolveFieldName(id);
4
+ if (resolved !== id) {
5
+ return resolved;
6
+ }
7
+ }
8
+ return displayName ?? id;
9
+ }
10
+ function resolveSectionLabel(id, displayName, labelLookup) {
11
+ if (labelLookup) {
12
+ const resolved = labelLookup.resolveSectionName(id);
13
+ if (resolved !== id) {
14
+ return resolved;
15
+ }
16
+ }
17
+ return displayName ?? id;
18
+ }
19
+ function formatRuleActionSummary(action, labelLookup) {
20
+ const type = action.programRuleActionType ?? "UNKNOWN";
21
+ let targetLabel = "";
22
+ if (action.dataElement?.id) {
23
+ targetLabel = resolveFieldLabel(
24
+ action.dataElement.id,
25
+ action.dataElement.displayName,
26
+ labelLookup
27
+ );
28
+ } else if (action.trackedEntityAttribute?.id) {
29
+ targetLabel = resolveFieldLabel(
30
+ action.trackedEntityAttribute.id,
31
+ action.trackedEntityAttribute.displayName,
32
+ labelLookup
33
+ );
34
+ } else if (action.programStageSection?.id) {
35
+ targetLabel = resolveSectionLabel(
36
+ action.programStageSection.id,
37
+ action.programStageSection.displayName,
38
+ labelLookup
39
+ );
40
+ } else if (action.programSection?.id) {
41
+ targetLabel = resolveSectionLabel(
42
+ action.programSection.id,
43
+ action.programSection.displayName,
44
+ labelLookup
45
+ );
46
+ } else if (type === "DISPLAYTEXT" || type === "DISPLAYKEYVALUEPAIR") {
47
+ targetLabel = action.location ?? "feedback";
48
+ }
49
+ let detail;
50
+ if (action.data) {
51
+ detail = action.data;
52
+ }
53
+ if (action.content && (type === "DISPLAYTEXT" || type === "DISPLAYKEYVALUEPAIR")) {
54
+ detail = action.content;
55
+ }
56
+ return { type, targetLabel, detail };
57
+ }
58
+
59
+ export { formatRuleActionSummary };
60
+ //# sourceMappingURL=formatRuleActionSummary.js.map
61
+ //# sourceMappingURL=formatRuleActionSummary.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/formatRuleActionSummary.ts"],"names":[],"mappings":"AAmBA,SAAS,iBAAA,CACL,EAAA,EACA,WAAA,EACA,WAAA,EACM;AACN,EAAA,IAAI,WAAA,EAAa;AACb,IAAA,MAAM,QAAA,GAAW,WAAA,CAAY,gBAAA,CAAiB,EAAE,CAAA;AAChD,IAAA,IAAI,aAAa,EAAA,EAAI;AACjB,MAAA,OAAO,QAAA;AAAA,IACX;AAAA,EACJ;AACA,EAAA,OAAO,WAAA,IAAe,EAAA;AAC1B;AAEA,SAAS,mBAAA,CACL,EAAA,EACA,WAAA,EACA,WAAA,EACM;AACN,EAAA,IAAI,WAAA,EAAa;AACb,IAAA,MAAM,QAAA,GAAW,WAAA,CAAY,kBAAA,CAAmB,EAAE,CAAA;AAClD,IAAA,IAAI,aAAa,EAAA,EAAI;AACjB,MAAA,OAAO,QAAA;AAAA,IACX;AAAA,EACJ;AACA,EAAA,OAAO,WAAA,IAAe,EAAA;AAC1B;AAEO,SAAS,uBAAA,CACZ,QACA,WAAA,EACmB;AACnB,EAAA,MAAM,IAAA,GAAO,OAAO,qBAAA,IAAyB,SAAA;AAE7C,EAAA,IAAI,WAAA,GAAc,EAAA;AAClB,EAAA,IAAI,MAAA,CAAO,aAAa,EAAA,EAAI;AACxB,IAAA,WAAA,GAAc,iBAAA;AAAA,MACV,OAAO,WAAA,CAAY,EAAA;AAAA,MACnB,OAAO,WAAA,CAAY,WAAA;AAAA,MACnB;AAAA,KACJ;AAAA,EACJ,CAAA,MAAA,IAAW,MAAA,CAAO,sBAAA,EAAwB,EAAA,EAAI;AAC1C,IAAA,WAAA,GAAc,iBAAA;AAAA,MACV,OAAO,sBAAA,CAAuB,EAAA;AAAA,MAC9B,OAAO,sBAAA,CAAuB,WAAA;AAAA,MAC9B;AAAA,KACJ;AAAA,EACJ,CAAA,MAAA,IAAW,MAAA,CAAO,mBAAA,EAAqB,EAAA,EAAI;AACvC,IAAA,WAAA,GAAc,mBAAA;AAAA,MACV,OAAO,mBAAA,CAAoB,EAAA;AAAA,MAC3B,OAAO,mBAAA,CAAoB,WAAA;AAAA,MAC3B;AAAA,KACJ;AAAA,EACJ,CAAA,MAAA,IAAW,MAAA,CAAO,cAAA,EAAgB,EAAA,EAAI;AAClC,IAAA,WAAA,GAAc,mBAAA;AAAA,MACV,OAAO,cAAA,CAAe,EAAA;AAAA,MACtB,OAAO,cAAA,CAAe,WAAA;AAAA,MACtB;AAAA,KACJ;AAAA,EACJ,CAAA,MAAA,IAAW,IAAA,KAAS,aAAA,IAAiB,IAAA,KAAS,qBAAA,EAAuB;AACjE,IAAA,WAAA,GAAc,OAAO,QAAA,IAAY,UAAA;AAAA,EACrC;AAEA,EAAA,IAAI,MAAA;AACJ,EAAA,IAAI,OAAO,IAAA,EAAM;AACb,IAAA,MAAA,GAAS,MAAA,CAAO,IAAA;AAAA,EACpB;AACA,EAAA,IAAI,MAAA,CAAO,OAAA,KAAY,IAAA,KAAS,aAAA,IAAiB,SAAS,qBAAA,CAAA,EAAwB;AAC9E,IAAA,MAAA,GAAS,MAAA,CAAO,OAAA;AAAA,EACpB;AAEA,EAAA,OAAO,EAAE,IAAA,EAAM,WAAA,EAAa,MAAA,EAAO;AACvC","file":"formatRuleActionSummary.js","sourcesContent":["import type { DevtoolsLabelLookup } from './createLabelLookup.js';\n\nexport type RuleActionLike = {\n programRuleActionType?: string;\n dataElement?: { id?: string; displayName?: string };\n trackedEntityAttribute?: { id?: string; displayName?: string };\n programStageSection?: { id?: string; displayName?: string };\n programSection?: { id?: string; displayName?: string };\n data?: string | null;\n content?: string | null;\n location?: string | null;\n};\n\nexport type FormattedRuleAction = {\n type: string;\n targetLabel: string;\n detail?: string;\n};\n\nfunction resolveFieldLabel(\n id: string,\n displayName: string | undefined,\n labelLookup?: DevtoolsLabelLookup\n): string {\n if (labelLookup) {\n const resolved = labelLookup.resolveFieldName(id);\n if (resolved !== id) {\n return resolved;\n }\n }\n return displayName ?? id;\n}\n\nfunction resolveSectionLabel(\n id: string,\n displayName: string | undefined,\n labelLookup?: DevtoolsLabelLookup\n): string {\n if (labelLookup) {\n const resolved = labelLookup.resolveSectionName(id);\n if (resolved !== id) {\n return resolved;\n }\n }\n return displayName ?? id;\n}\n\nexport function formatRuleActionSummary(\n action: RuleActionLike,\n labelLookup?: DevtoolsLabelLookup\n): FormattedRuleAction {\n const type = action.programRuleActionType ?? 'UNKNOWN';\n\n let targetLabel = '';\n if (action.dataElement?.id) {\n targetLabel = resolveFieldLabel(\n action.dataElement.id,\n action.dataElement.displayName,\n labelLookup\n );\n } else if (action.trackedEntityAttribute?.id) {\n targetLabel = resolveFieldLabel(\n action.trackedEntityAttribute.id,\n action.trackedEntityAttribute.displayName,\n labelLookup\n );\n } else if (action.programStageSection?.id) {\n targetLabel = resolveSectionLabel(\n action.programStageSection.id,\n action.programStageSection.displayName,\n labelLookup\n );\n } else if (action.programSection?.id) {\n targetLabel = resolveSectionLabel(\n action.programSection.id,\n action.programSection.displayName,\n labelLookup\n );\n } else if (type === 'DISPLAYTEXT' || type === 'DISPLAYKEYVALUEPAIR') {\n targetLabel = action.location ?? 'feedback';\n }\n\n let detail: string | undefined;\n if (action.data) {\n detail = action.data;\n }\n if (action.content && (type === 'DISPLAYTEXT' || type === 'DISPLAYKEYVALUEPAIR')) {\n detail = action.content;\n }\n\n return { type, targetLabel, detail };\n}\n"]}
@@ -0,0 +1,48 @@
1
+ import { GraphNodeKind, GraphEdge, RuleDependencyGraph } from './buildGraph.js';
2
+ import '@nnkogift/dhis2-form-utils-hooks';
3
+ import './createLabelLookup.js';
4
+ import '@nnkogift/dhis2-form-utils-metadata';
5
+
6
+ type GraphNodePosition = {
7
+ x: number;
8
+ y: number;
9
+ };
10
+ type FlowGraphRole = 'source' | 'rule' | 'target';
11
+ /** A single visual node in the React Flow canvas (may differ from the semantic graph node). */
12
+ type FlowGraphNode = {
13
+ id: string;
14
+ graphNodeId: string;
15
+ kind: GraphNodeKind;
16
+ label: string;
17
+ role: FlowGraphRole;
18
+ };
19
+ type PreparedFlowGraph = {
20
+ nodes: FlowGraphNode[];
21
+ edges: GraphEdge[];
22
+ };
23
+ /** Column x-coordinates by node role. Effect targets always sit to the right of rules. */
24
+ declare const ROLE_COLUMNS: Record<FlowGraphRole, number>;
25
+ /** Feedback targets get an extra column so they never overlap sections/field targets. */
26
+ declare const FEEDBACK_COLUMN = 720;
27
+ /** Vertical distance between rule lanes. */
28
+ declare const LANE_HEIGHT = 104;
29
+ /**
30
+ * Expands the semantic graph into flow nodes so every edge runs left → right.
31
+ * Fields that are both read sources and effect targets are split into `@src` /
32
+ * `@tgt` copies at the source and target columns respectively.
33
+ */
34
+ declare function prepareFlowGraph(graph: RuleDependencyGraph): PreparedFlowGraph;
35
+ /**
36
+ * Rule-centric lane layout on flow nodes. Each rule owns one horizontal lane;
37
+ * sources sit left, targets right, so every edge flows in the same direction.
38
+ */
39
+ declare function computeGraphLayout(flowNodes: FlowGraphNode[], flowEdges: GraphEdge[]): Map<string, GraphNodePosition>;
40
+ /** @deprecated Use ROLE_COLUMNS.source */
41
+ declare const KIND_COLUMNS: {
42
+ readonly field: number;
43
+ readonly rule: number;
44
+ readonly section: number;
45
+ readonly feedback: 720;
46
+ };
47
+
48
+ export { FEEDBACK_COLUMN, type FlowGraphNode, type FlowGraphRole, type GraphNodePosition, KIND_COLUMNS, LANE_HEIGHT, type PreparedFlowGraph, ROLE_COLUMNS, computeGraphLayout, prepareFlowGraph };
@@ -0,0 +1,137 @@
1
+ const ROLE_COLUMNS = {
2
+ source: 0,
3
+ rule: 280,
4
+ target: 560
5
+ };
6
+ const FEEDBACK_COLUMN = 720;
7
+ const LANE_HEIGHT = 104;
8
+ const STAGGER = 24;
9
+ function median(values) {
10
+ const sorted = [...values].sort((a, b) => a - b);
11
+ const mid = Math.floor(sorted.length / 2);
12
+ return sorted.length % 2 === 0 ? (sorted[mid - 1] + sorted[mid]) / 2 : sorted[mid];
13
+ }
14
+ function staggerOffset(indexInBucket) {
15
+ if (indexInBucket === 0) {
16
+ return 0;
17
+ }
18
+ const magnitude = Math.ceil(indexInBucket / 2) * STAGGER;
19
+ return indexInBucket % 2 === 1 ? magnitude : -magnitude;
20
+ }
21
+ function columnFor(node) {
22
+ if (node.role === "target" && node.kind === "feedback") {
23
+ return FEEDBACK_COLUMN;
24
+ }
25
+ return ROLE_COLUMNS[node.role];
26
+ }
27
+ function prepareFlowGraph(graph) {
28
+ const readSources = /* @__PURE__ */ new Set();
29
+ const effectTargets = /* @__PURE__ */ new Set();
30
+ for (const edge of graph.edges) {
31
+ if (edge.effectType === "read") {
32
+ readSources.add(edge.source);
33
+ } else {
34
+ effectTargets.add(edge.target);
35
+ }
36
+ }
37
+ const flowNodes = [];
38
+ const endpointByGraphId = /* @__PURE__ */ new Map();
39
+ for (const node of graph.nodes) {
40
+ if (node.kind === "rule") {
41
+ flowNodes.push({
42
+ id: node.id,
43
+ graphNodeId: node.id,
44
+ kind: node.kind,
45
+ label: node.label,
46
+ role: "rule"
47
+ });
48
+ continue;
49
+ }
50
+ const isSource = readSources.has(node.id);
51
+ const isTarget = effectTargets.has(node.id);
52
+ const endpoints = {};
53
+ if (isSource) {
54
+ const flowId = isTarget ? `${node.id}@src` : node.id;
55
+ endpoints.source = flowId;
56
+ flowNodes.push({
57
+ id: flowId,
58
+ graphNodeId: node.id,
59
+ kind: node.kind,
60
+ label: node.label,
61
+ role: "source"
62
+ });
63
+ }
64
+ if (isTarget) {
65
+ const flowId = isSource ? `${node.id}@tgt` : node.id;
66
+ endpoints.target = flowId;
67
+ flowNodes.push({
68
+ id: flowId,
69
+ graphNodeId: node.id,
70
+ kind: node.kind,
71
+ label: node.label,
72
+ role: "target"
73
+ });
74
+ }
75
+ endpointByGraphId.set(node.id, endpoints);
76
+ }
77
+ const flowEdges = graph.edges.map((edge) => {
78
+ if (edge.effectType === "read") {
79
+ const endpoints2 = endpointByGraphId.get(edge.source);
80
+ return { ...edge, source: endpoints2?.source ?? edge.source };
81
+ }
82
+ const endpoints = endpointByGraphId.get(edge.target);
83
+ return { ...edge, target: endpoints?.target ?? edge.target };
84
+ });
85
+ return { nodes: flowNodes, edges: flowEdges };
86
+ }
87
+ function computeGraphLayout(flowNodes, flowEdges) {
88
+ const positions = /* @__PURE__ */ new Map();
89
+ const ruleLane = /* @__PURE__ */ new Map();
90
+ flowNodes.filter((node) => node.role === "rule").forEach((node, index) => {
91
+ ruleLane.set(node.id, index);
92
+ positions.set(node.id, { x: ROLE_COLUMNS.rule, y: index * LANE_HEIGHT });
93
+ });
94
+ const connectedRuleLanes = /* @__PURE__ */ new Map();
95
+ const addLane = (nodeId, lane) => {
96
+ const lanes = connectedRuleLanes.get(nodeId) ?? /* @__PURE__ */ new Set();
97
+ lanes.add(lane);
98
+ connectedRuleLanes.set(nodeId, lanes);
99
+ };
100
+ for (const edge of flowEdges) {
101
+ const sourceLane = ruleLane.get(edge.source);
102
+ const targetLane = ruleLane.get(edge.target);
103
+ if (targetLane !== void 0 && sourceLane === void 0) {
104
+ addLane(edge.source, targetLane);
105
+ }
106
+ if (sourceLane !== void 0 && targetLane === void 0) {
107
+ addLane(edge.target, sourceLane);
108
+ }
109
+ }
110
+ const bucketCounts = /* @__PURE__ */ new Map();
111
+ for (const node of flowNodes) {
112
+ if (node.role === "rule") {
113
+ continue;
114
+ }
115
+ const lanes = connectedRuleLanes.get(node.id);
116
+ const lane = lanes && lanes.size > 0 ? median([...lanes]) : 0;
117
+ const column = columnFor(node);
118
+ const bucketKey = `${String(column)}:${String(lane)}`;
119
+ const indexInBucket = bucketCounts.get(bucketKey) ?? 0;
120
+ bucketCounts.set(bucketKey, indexInBucket + 1);
121
+ positions.set(node.id, {
122
+ x: column,
123
+ y: lane * LANE_HEIGHT + staggerOffset(indexInBucket)
124
+ });
125
+ }
126
+ return positions;
127
+ }
128
+ const KIND_COLUMNS = {
129
+ field: ROLE_COLUMNS.source,
130
+ rule: ROLE_COLUMNS.rule,
131
+ section: ROLE_COLUMNS.target,
132
+ feedback: FEEDBACK_COLUMN
133
+ };
134
+
135
+ export { FEEDBACK_COLUMN, KIND_COLUMNS, LANE_HEIGHT, ROLE_COLUMNS, computeGraphLayout, prepareFlowGraph };
136
+ //# sourceMappingURL=graphLayout.js.map
137
+ //# sourceMappingURL=graphLayout.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/graphLayout.ts"],"names":["endpoints"],"mappings":"AAqBO,MAAM,YAAA,GAA8C;AAAA,EACvD,MAAA,EAAQ,CAAA;AAAA,EACR,IAAA,EAAM,GAAA;AAAA,EACN,MAAA,EAAQ;AACZ;AAGO,MAAM,eAAA,GAAkB;AAGxB,MAAM,WAAA,GAAc;AAG3B,MAAM,OAAA,GAAU,EAAA;AAEhB,SAAS,OAAO,MAAA,EAA0B;AACtC,EAAA,MAAM,MAAA,GAAS,CAAC,GAAG,MAAM,CAAA,CAAE,KAAK,CAAC,CAAA,EAAG,CAAA,KAAM,CAAA,GAAI,CAAC,CAAA;AAC/C,EAAA,MAAM,GAAA,GAAM,IAAA,CAAK,KAAA,CAAM,MAAA,CAAO,SAAS,CAAC,CAAA;AACxC,EAAA,OAAO,MAAA,CAAO,MAAA,GAAS,CAAA,KAAM,CAAA,GAAA,CAAK,MAAA,CAAO,GAAA,GAAM,CAAC,CAAA,GAAI,MAAA,CAAO,GAAG,CAAA,IAAK,CAAA,GAAI,OAAO,GAAG,CAAA;AACrF;AAGA,SAAS,cAAc,aAAA,EAA+B;AAClD,EAAA,IAAI,kBAAkB,CAAA,EAAG;AACrB,IAAA,OAAO,CAAA;AAAA,EACX;AACA,EAAA,MAAM,SAAA,GAAY,IAAA,CAAK,IAAA,CAAK,aAAA,GAAgB,CAAC,CAAA,GAAI,OAAA;AACjD,EAAA,OAAO,aAAA,GAAgB,CAAA,KAAM,CAAA,GAAI,SAAA,GAAY,CAAC,SAAA;AAClD;AAEA,SAAS,UAAU,IAAA,EAA6B;AAC5C,EAAA,IAAI,IAAA,CAAK,IAAA,KAAS,QAAA,IAAY,IAAA,CAAK,SAAS,UAAA,EAAY;AACpD,IAAA,OAAO,eAAA;AAAA,EACX;AACA,EAAA,OAAO,YAAA,CAAa,KAAK,IAAI,CAAA;AACjC;AAOO,SAAS,iBAAiB,KAAA,EAA+C;AAC5E,EAAA,MAAM,WAAA,uBAAkB,GAAA,EAAY;AACpC,EAAA,MAAM,aAAA,uBAAoB,GAAA,EAAY;AAEtC,EAAA,KAAA,MAAW,IAAA,IAAQ,MAAM,KAAA,EAAO;AAC5B,IAAA,IAAI,IAAA,CAAK,eAAe,MAAA,EAAQ;AAC5B,MAAA,WAAA,CAAY,GAAA,CAAI,KAAK,MAAM,CAAA;AAAA,IAC/B,CAAA,MAAO;AACH,MAAA,aAAA,CAAc,GAAA,CAAI,KAAK,MAAM,CAAA;AAAA,IACjC;AAAA,EACJ;AAEA,EAAA,MAAM,YAA6B,EAAC;AACpC,EAAA,MAAM,iBAAA,uBAAwB,GAAA,EAAkD;AAEhF,EAAA,KAAA,MAAW,IAAA,IAAQ,MAAM,KAAA,EAAO;AAC5B,IAAA,IAAI,IAAA,CAAK,SAAS,MAAA,EAAQ;AACtB,MAAA,SAAA,CAAU,IAAA,CAAK;AAAA,QACX,IAAI,IAAA,CAAK,EAAA;AAAA,QACT,aAAa,IAAA,CAAK,EAAA;AAAA,QAClB,MAAM,IAAA,CAAK,IAAA;AAAA,QACX,OAAO,IAAA,CAAK,KAAA;AAAA,QACZ,IAAA,EAAM;AAAA,OACT,CAAA;AACD,MAAA;AAAA,IACJ;AAEA,IAAA,MAAM,QAAA,GAAW,WAAA,CAAY,GAAA,CAAI,IAAA,CAAK,EAAE,CAAA;AACxC,IAAA,MAAM,QAAA,GAAW,aAAA,CAAc,GAAA,CAAI,IAAA,CAAK,EAAE,CAAA;AAC1C,IAAA,MAAM,YAAkD,EAAC;AAEzD,IAAA,IAAI,QAAA,EAAU;AACV,MAAA,MAAM,SAAS,QAAA,GAAW,CAAA,EAAG,IAAA,CAAK,EAAE,SAAS,IAAA,CAAK,EAAA;AAClD,MAAA,SAAA,CAAU,MAAA,GAAS,MAAA;AACnB,MAAA,SAAA,CAAU,IAAA,CAAK;AAAA,QACX,EAAA,EAAI,MAAA;AAAA,QACJ,aAAa,IAAA,CAAK,EAAA;AAAA,QAClB,MAAM,IAAA,CAAK,IAAA;AAAA,QACX,OAAO,IAAA,CAAK,KAAA;AAAA,QACZ,IAAA,EAAM;AAAA,OACT,CAAA;AAAA,IACL;AAEA,IAAA,IAAI,QAAA,EAAU;AACV,MAAA,MAAM,SAAS,QAAA,GAAW,CAAA,EAAG,IAAA,CAAK,EAAE,SAAS,IAAA,CAAK,EAAA;AAClD,MAAA,SAAA,CAAU,MAAA,GAAS,MAAA;AACnB,MAAA,SAAA,CAAU,IAAA,CAAK;AAAA,QACX,EAAA,EAAI,MAAA;AAAA,QACJ,aAAa,IAAA,CAAK,EAAA;AAAA,QAClB,MAAM,IAAA,CAAK,IAAA;AAAA,QACX,OAAO,IAAA,CAAK,KAAA;AAAA,QACZ,IAAA,EAAM;AAAA,OACT,CAAA;AAAA,IACL;AAEA,IAAA,iBAAA,CAAkB,GAAA,CAAI,IAAA,CAAK,EAAA,EAAI,SAAS,CAAA;AAAA,EAC5C;AAEA,EAAA,MAAM,SAAA,GAAY,KAAA,CAAM,KAAA,CAAM,GAAA,CAAI,CAAC,IAAA,KAAS;AACxC,IAAA,IAAI,IAAA,CAAK,eAAe,MAAA,EAAQ;AAC5B,MAAA,MAAMA,UAAAA,GAAY,iBAAA,CAAkB,GAAA,CAAI,IAAA,CAAK,MAAM,CAAA;AACnD,MAAA,OAAO,EAAE,GAAG,IAAA,EAAM,QAAQA,UAAAA,EAAW,MAAA,IAAU,KAAK,MAAA,EAAO;AAAA,IAC/D;AACA,IAAA,MAAM,SAAA,GAAY,iBAAA,CAAkB,GAAA,CAAI,IAAA,CAAK,MAAM,CAAA;AACnD,IAAA,OAAO,EAAE,GAAG,IAAA,EAAM,QAAQ,SAAA,EAAW,MAAA,IAAU,KAAK,MAAA,EAAO;AAAA,EAC/D,CAAC,CAAA;AAED,EAAA,OAAO,EAAE,KAAA,EAAO,SAAA,EAAW,KAAA,EAAO,SAAA,EAAU;AAChD;AAMO,SAAS,kBAAA,CACZ,WACA,SAAA,EAC8B;AAC9B,EAAA,MAAM,SAAA,uBAAgB,GAAA,EAA+B;AAErD,EAAA,MAAM,QAAA,uBAAe,GAAA,EAAoB;AACzC,EAAA,SAAA,CACK,MAAA,CAAO,CAAC,IAAA,KAAS,IAAA,CAAK,IAAA,KAAS,MAAM,CAAA,CACrC,OAAA,CAAQ,CAAC,IAAA,EAAM,KAAA,KAAU;AACtB,IAAA,QAAA,CAAS,GAAA,CAAI,IAAA,CAAK,EAAA,EAAI,KAAK,CAAA;AAC3B,IAAA,SAAA,CAAU,GAAA,CAAI,IAAA,CAAK,EAAA,EAAI,EAAE,CAAA,EAAG,aAAa,IAAA,EAAM,CAAA,EAAG,KAAA,GAAQ,WAAA,EAAa,CAAA;AAAA,EAC3E,CAAC,CAAA;AAEL,EAAA,MAAM,kBAAA,uBAAyB,GAAA,EAAyB;AACxD,EAAA,MAAM,OAAA,GAAU,CAAC,MAAA,EAAgB,IAAA,KAAiB;AAC9C,IAAA,MAAM,QAAQ,kBAAA,CAAmB,GAAA,CAAI,MAAM,CAAA,wBAAS,GAAA,EAAY;AAChE,IAAA,KAAA,CAAM,IAAI,IAAI,CAAA;AACd,IAAA,kBAAA,CAAmB,GAAA,CAAI,QAAQ,KAAK,CAAA;AAAA,EACxC,CAAA;AAEA,EAAA,KAAA,MAAW,QAAQ,SAAA,EAAW;AAC1B,IAAA,MAAM,UAAA,GAAa,QAAA,CAAS,GAAA,CAAI,IAAA,CAAK,MAAM,CAAA;AAC3C,IAAA,MAAM,UAAA,GAAa,QAAA,CAAS,GAAA,CAAI,IAAA,CAAK,MAAM,CAAA;AAC3C,IAAA,IAAI,UAAA,KAAe,MAAA,IAAa,UAAA,KAAe,MAAA,EAAW;AACtD,MAAA,OAAA,CAAQ,IAAA,CAAK,QAAQ,UAAU,CAAA;AAAA,IACnC;AACA,IAAA,IAAI,UAAA,KAAe,MAAA,IAAa,UAAA,KAAe,MAAA,EAAW;AACtD,MAAA,OAAA,CAAQ,IAAA,CAAK,QAAQ,UAAU,CAAA;AAAA,IACnC;AAAA,EACJ;AAEA,EAAA,MAAM,YAAA,uBAAmB,GAAA,EAAoB;AAC7C,EAAA,KAAA,MAAW,QAAQ,SAAA,EAAW;AAC1B,IAAA,IAAI,IAAA,CAAK,SAAS,MAAA,EAAQ;AACtB,MAAA;AAAA,IACJ;AACA,IAAA,MAAM,KAAA,GAAQ,kBAAA,CAAmB,GAAA,CAAI,IAAA,CAAK,EAAE,CAAA;AAC5C,IAAA,MAAM,IAAA,GAAO,KAAA,IAAS,KAAA,CAAM,IAAA,GAAO,CAAA,GAAI,OAAO,CAAC,GAAG,KAAK,CAAC,CAAA,GAAI,CAAA;AAC5D,IAAA,MAAM,MAAA,GAAS,UAAU,IAAI,CAAA;AAC7B,IAAA,MAAM,SAAA,GAAY,GAAG,MAAA,CAAO,MAAM,CAAC,CAAA,CAAA,EAAI,MAAA,CAAO,IAAI,CAAC,CAAA,CAAA;AACnD,IAAA,MAAM,aAAA,GAAgB,YAAA,CAAa,GAAA,CAAI,SAAS,CAAA,IAAK,CAAA;AACrD,IAAA,YAAA,CAAa,GAAA,CAAI,SAAA,EAAW,aAAA,GAAgB,CAAC,CAAA;AAC7C,IAAA,SAAA,CAAU,GAAA,CAAI,KAAK,EAAA,EAAI;AAAA,MACnB,CAAA,EAAG,MAAA;AAAA,MACH,CAAA,EAAG,IAAA,GAAO,WAAA,GAAc,aAAA,CAAc,aAAa;AAAA,KACtD,CAAA;AAAA,EACL;AAEA,EAAA,OAAO,SAAA;AACX;AAGO,MAAM,YAAA,GAAe;AAAA,EACxB,OAAO,YAAA,CAAa,MAAA;AAAA,EACpB,MAAM,YAAA,CAAa,IAAA;AAAA,EACnB,SAAS,YAAA,CAAa,MAAA;AAAA,EACtB,QAAA,EAAU;AACd","file":"graphLayout.js","sourcesContent":["import type { GraphEdge, GraphNodeKind, RuleDependencyGraph } from './buildGraph.js';\n\nexport type GraphNodePosition = { x: number; y: number };\n\nexport type FlowGraphRole = 'source' | 'rule' | 'target';\n\n/** A single visual node in the React Flow canvas (may differ from the semantic graph node). */\nexport type FlowGraphNode = {\n id: string;\n graphNodeId: string;\n kind: GraphNodeKind;\n label: string;\n role: FlowGraphRole;\n};\n\nexport type PreparedFlowGraph = {\n nodes: FlowGraphNode[];\n edges: GraphEdge[];\n};\n\n/** Column x-coordinates by node role. Effect targets always sit to the right of rules. */\nexport const ROLE_COLUMNS: Record<FlowGraphRole, number> = {\n source: 0,\n rule: 280,\n target: 560,\n};\n\n/** Feedback targets get an extra column so they never overlap sections/field targets. */\nexport const FEEDBACK_COLUMN = 720;\n\n/** Vertical distance between rule lanes. */\nexport const LANE_HEIGHT = 104;\n\n/** Vertical spread applied to nodes that land in the same column and lane. */\nconst STAGGER = 24;\n\nfunction median(values: number[]): number {\n const sorted = [...values].sort((a, b) => a - b);\n const mid = Math.floor(sorted.length / 2);\n return sorted.length % 2 === 0 ? (sorted[mid - 1] + sorted[mid]) / 2 : sorted[mid];\n}\n\n/** Centered spread: 0, +24, -24, +48, -48, … so a bucket fans out around its lane. */\nfunction staggerOffset(indexInBucket: number): number {\n if (indexInBucket === 0) {\n return 0;\n }\n const magnitude = Math.ceil(indexInBucket / 2) * STAGGER;\n return indexInBucket % 2 === 1 ? magnitude : -magnitude;\n}\n\nfunction columnFor(node: FlowGraphNode): number {\n if (node.role === 'target' && node.kind === 'feedback') {\n return FEEDBACK_COLUMN;\n }\n return ROLE_COLUMNS[node.role];\n}\n\n/**\n * Expands the semantic graph into flow nodes so every edge runs left → right.\n * Fields that are both read sources and effect targets are split into `@src` /\n * `@tgt` copies at the source and target columns respectively.\n */\nexport function prepareFlowGraph(graph: RuleDependencyGraph): PreparedFlowGraph {\n const readSources = new Set<string>();\n const effectTargets = new Set<string>();\n\n for (const edge of graph.edges) {\n if (edge.effectType === 'read') {\n readSources.add(edge.source);\n } else {\n effectTargets.add(edge.target);\n }\n }\n\n const flowNodes: FlowGraphNode[] = [];\n const endpointByGraphId = new Map<string, { source?: string; target?: string }>();\n\n for (const node of graph.nodes) {\n if (node.kind === 'rule') {\n flowNodes.push({\n id: node.id,\n graphNodeId: node.id,\n kind: node.kind,\n label: node.label,\n role: 'rule',\n });\n continue;\n }\n\n const isSource = readSources.has(node.id);\n const isTarget = effectTargets.has(node.id);\n const endpoints: { source?: string; target?: string } = {};\n\n if (isSource) {\n const flowId = isTarget ? `${node.id}@src` : node.id;\n endpoints.source = flowId;\n flowNodes.push({\n id: flowId,\n graphNodeId: node.id,\n kind: node.kind,\n label: node.label,\n role: 'source',\n });\n }\n\n if (isTarget) {\n const flowId = isSource ? `${node.id}@tgt` : node.id;\n endpoints.target = flowId;\n flowNodes.push({\n id: flowId,\n graphNodeId: node.id,\n kind: node.kind,\n label: node.label,\n role: 'target',\n });\n }\n\n endpointByGraphId.set(node.id, endpoints);\n }\n\n const flowEdges = graph.edges.map((edge) => {\n if (edge.effectType === 'read') {\n const endpoints = endpointByGraphId.get(edge.source);\n return { ...edge, source: endpoints?.source ?? edge.source };\n }\n const endpoints = endpointByGraphId.get(edge.target);\n return { ...edge, target: endpoints?.target ?? edge.target };\n });\n\n return { nodes: flowNodes, edges: flowEdges };\n}\n\n/**\n * Rule-centric lane layout on flow nodes. Each rule owns one horizontal lane;\n * sources sit left, targets right, so every edge flows in the same direction.\n */\nexport function computeGraphLayout(\n flowNodes: FlowGraphNode[],\n flowEdges: GraphEdge[]\n): Map<string, GraphNodePosition> {\n const positions = new Map<string, GraphNodePosition>();\n\n const ruleLane = new Map<string, number>();\n flowNodes\n .filter((node) => node.role === 'rule')\n .forEach((node, index) => {\n ruleLane.set(node.id, index);\n positions.set(node.id, { x: ROLE_COLUMNS.rule, y: index * LANE_HEIGHT });\n });\n\n const connectedRuleLanes = new Map<string, Set<number>>();\n const addLane = (nodeId: string, lane: number) => {\n const lanes = connectedRuleLanes.get(nodeId) ?? new Set<number>();\n lanes.add(lane);\n connectedRuleLanes.set(nodeId, lanes);\n };\n\n for (const edge of flowEdges) {\n const sourceLane = ruleLane.get(edge.source);\n const targetLane = ruleLane.get(edge.target);\n if (targetLane !== undefined && sourceLane === undefined) {\n addLane(edge.source, targetLane);\n }\n if (sourceLane !== undefined && targetLane === undefined) {\n addLane(edge.target, sourceLane);\n }\n }\n\n const bucketCounts = new Map<string, number>();\n for (const node of flowNodes) {\n if (node.role === 'rule') {\n continue;\n }\n const lanes = connectedRuleLanes.get(node.id);\n const lane = lanes && lanes.size > 0 ? median([...lanes]) : 0;\n const column = columnFor(node);\n const bucketKey = `${String(column)}:${String(lane)}`;\n const indexInBucket = bucketCounts.get(bucketKey) ?? 0;\n bucketCounts.set(bucketKey, indexInBucket + 1);\n positions.set(node.id, {\n x: column,\n y: lane * LANE_HEIGHT + staggerOffset(indexInBucket),\n });\n }\n\n return positions;\n}\n\n/** @deprecated Use ROLE_COLUMNS.source */\nexport const KIND_COLUMNS = {\n field: ROLE_COLUMNS.source,\n rule: ROLE_COLUMNS.rule,\n section: ROLE_COLUMNS.target,\n feedback: FEEDBACK_COLUMN,\n} as const;\n"]}
@@ -0,0 +1,9 @@
1
+ import { GraphNode } from './buildGraph.js';
2
+ import '@nnkogift/dhis2-form-utils-hooks';
3
+ import './createLabelLookup.js';
4
+ import '@nnkogift/dhis2-form-utils-metadata';
5
+
6
+ declare function getGraphNodeClassName(kind: GraphNode['kind'], highlighted: boolean): string;
7
+ declare function getLegendSwatchClassName(kind: GraphNode['kind']): string;
8
+
9
+ export { getGraphNodeClassName, getLegendSwatchClassName };
@@ -0,0 +1,22 @@
1
+ const GRAPH_NODE_CLASSES = {
2
+ field: "border-dhis2-blue-500",
3
+ rule: "border-dhis2-teal-600 bg-dhis2-teal-050",
4
+ section: "border-dhis2-grey-600",
5
+ feedback: "border-dhis2-purple-500"
6
+ };
7
+ const LEGEND_SWATCH_CLASSES = {
8
+ field: "bg-dhis2-blue-500",
9
+ rule: "bg-dhis2-teal-600",
10
+ section: "bg-dhis2-grey-600",
11
+ feedback: "bg-dhis2-purple-500"
12
+ };
13
+ function getGraphNodeClassName(kind, highlighted) {
14
+ return `p-dp8 rounded border bg-white min-w-28 max-w-[180px] text-xs shadow-[0_1px_2px_rgb(0_0_0/6%)] transition-opacity duration-150 ease-out cursor-grab active:cursor-grabbing ${GRAPH_NODE_CLASSES[kind]} ${highlighted ? "" : "opacity-35"}`;
15
+ }
16
+ function getLegendSwatchClassName(kind) {
17
+ return `size-2.5 shrink-0 rounded-sm ${LEGEND_SWATCH_CLASSES[kind]}`;
18
+ }
19
+
20
+ export { getGraphNodeClassName, getLegendSwatchClassName };
21
+ //# sourceMappingURL=graphNodeStyles.js.map
22
+ //# sourceMappingURL=graphNodeStyles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/graphNodeStyles.ts"],"names":[],"mappings":"AAEA,MAAM,kBAAA,GAAwD;AAAA,EAC1D,KAAA,EAAO,uBAAA;AAAA,EACP,IAAA,EAAM,yCAAA;AAAA,EACN,OAAA,EAAS,uBAAA;AAAA,EACT,QAAA,EAAU;AACd,CAAA;AAEA,MAAM,qBAAA,GAA2D;AAAA,EAC7D,KAAA,EAAO,mBAAA;AAAA,EACP,IAAA,EAAM,mBAAA;AAAA,EACN,OAAA,EAAS,mBAAA;AAAA,EACT,QAAA,EAAU;AACd,CAAA;AAEO,SAAS,qBAAA,CAAsB,MAAyB,WAAA,EAA8B;AACzF,EAAA,OAAO,6KAA6K,kBAAA,CAAmB,IAAI,CAAC,CAAA,CAAA,EACxM,WAAA,GAAc,KAAK,YACvB,CAAA,CAAA;AACJ;AAEO,SAAS,yBAAyB,IAAA,EAAiC;AACtE,EAAA,OAAO,CAAA,6BAAA,EAAgC,qBAAA,CAAsB,IAAI,CAAC,CAAA,CAAA;AACtE","file":"graphNodeStyles.js","sourcesContent":["import type { GraphNode } from './buildGraph.js';\n\nconst GRAPH_NODE_CLASSES: Record<GraphNode['kind'], string> = {\n field: 'border-dhis2-blue-500',\n rule: 'border-dhis2-teal-600 bg-dhis2-teal-050',\n section: 'border-dhis2-grey-600',\n feedback: 'border-dhis2-purple-500',\n};\n\nconst LEGEND_SWATCH_CLASSES: Record<GraphNode['kind'], string> = {\n field: 'bg-dhis2-blue-500',\n rule: 'bg-dhis2-teal-600',\n section: 'bg-dhis2-grey-600',\n feedback: 'bg-dhis2-purple-500',\n};\n\nexport function getGraphNodeClassName(kind: GraphNode['kind'], highlighted: boolean): string {\n return `p-dp8 rounded border bg-white min-w-28 max-w-[180px] text-xs shadow-[0_1px_2px_rgb(0_0_0/6%)] transition-opacity duration-150 ease-out cursor-grab active:cursor-grabbing ${GRAPH_NODE_CLASSES[kind]} ${\n highlighted ? '' : 'opacity-35'\n }`;\n}\n\nexport function getLegendSwatchClassName(kind: GraphNode['kind']): string {\n return `size-2.5 shrink-0 rounded-sm ${LEGEND_SWATCH_CLASSES[kind]}`;\n}\n"]}
package/dist/i18n.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ type TranslateVariables = Record<string, string | number>;
2
+ declare function translate(message: string, variables?: TranslateVariables): string;
3
+
4
+ export { translate };
package/dist/i18n.js ADDED
@@ -0,0 +1,9 @@
1
+ import i18n from '@dhis2/d2-i18n';
2
+
3
+ function translate(message, variables) {
4
+ return String(i18n.t(message, variables));
5
+ }
6
+
7
+ export { translate };
8
+ //# sourceMappingURL=i18n.js.map
9
+ //# sourceMappingURL=i18n.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/i18n.ts"],"names":[],"mappings":";;AAIO,SAAS,SAAA,CAAU,SAAiB,SAAA,EAAwC;AAC/E,EAAA,OAAO,MAAA,CAAO,IAAA,CAAK,CAAA,CAAE,OAAA,EAAS,SAAS,CAAC,CAAA;AAC5C","file":"i18n.js","sourcesContent":["import i18n from '@dhis2/d2-i18n';\n\ntype TranslateVariables = Record<string, string | number>;\n\nexport function translate(message: string, variables?: TranslateVariables): string {\n return String(i18n.t(message, variables));\n}\n"]}