nucleus-core-ts 0.9.781 → 0.9.783

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 (154) hide show
  1. package/dist/client.js +1 -1
  2. package/dist/fe/components/IntegrationsPage/components/ConnectionAuthFields.d.ts +2 -0
  3. package/dist/fe/components/IntegrationsPage/components/ConnectionAuthFields.js +85 -0
  4. package/dist/fe/components/IntegrationsPage/components/ConnectionBasicFields.d.ts +2 -0
  5. package/dist/fe/components/IntegrationsPage/components/ConnectionBasicFields.js +165 -0
  6. package/dist/fe/components/IntegrationsPage/components/ConnectionForm.d.ts +10 -0
  7. package/dist/fe/components/IntegrationsPage/components/ConnectionForm.js +112 -0
  8. package/dist/fe/components/IntegrationsPage/components/ConnectionList.d.ts +9 -0
  9. package/dist/fe/components/IntegrationsPage/components/ConnectionList.js +184 -0
  10. package/dist/fe/components/IntegrationsPage/components/ConnectionOauthFields.d.ts +2 -0
  11. package/dist/fe/components/IntegrationsPage/components/ConnectionOauthFields.js +131 -0
  12. package/dist/fe/components/IntegrationsPage/components/ConnectionSettingsTab.d.ts +21 -0
  13. package/dist/fe/components/IntegrationsPage/components/ConnectionSettingsTab.js +49 -0
  14. package/dist/fe/components/IntegrationsPage/components/ConnectionTabs.d.ts +12 -0
  15. package/dist/fe/components/IntegrationsPage/components/ConnectionTabs.js +95 -0
  16. package/dist/fe/components/IntegrationsPage/components/ConnectionTest.d.ts +9 -0
  17. package/dist/fe/components/IntegrationsPage/components/ConnectionTest.js +116 -0
  18. package/dist/fe/components/IntegrationsPage/components/CredentialFields.d.ts +9 -0
  19. package/dist/fe/components/IntegrationsPage/components/CredentialFields.js +171 -0
  20. package/dist/fe/components/IntegrationsPage/components/CredentialSlotRow.d.ts +13 -0
  21. package/dist/fe/components/IntegrationsPage/components/CredentialSlotRow.js +63 -0
  22. package/dist/fe/components/IntegrationsPage/components/EndpointForm.d.ts +11 -0
  23. package/dist/fe/components/IntegrationsPage/components/EndpointForm.js +166 -0
  24. package/dist/fe/components/IntegrationsPage/components/EndpointFormFields.d.ts +19 -0
  25. package/dist/fe/components/IntegrationsPage/components/EndpointFormFields.js +162 -0
  26. package/dist/fe/components/IntegrationsPage/components/EndpointList.d.ts +12 -0
  27. package/dist/fe/components/IntegrationsPage/components/EndpointList.js +205 -0
  28. package/dist/fe/components/IntegrationsPage/components/EndpointSample.d.ts +6 -0
  29. package/dist/fe/components/IntegrationsPage/components/EndpointSample.js +204 -0
  30. package/dist/fe/components/IntegrationsPage/components/EndpointsTab.d.ts +5 -0
  31. package/dist/fe/components/IntegrationsPage/components/EndpointsTab.js +101 -0
  32. package/dist/fe/components/IntegrationsPage/components/FieldMappingRow.d.ts +17 -0
  33. package/dist/fe/components/IntegrationsPage/components/FieldMappingRow.js +179 -0
  34. package/dist/fe/components/IntegrationsPage/components/FieldMappingRows.d.ts +11 -0
  35. package/dist/fe/components/IntegrationsPage/components/FieldMappingRows.js +115 -0
  36. package/dist/fe/components/IntegrationsPage/components/IntegrationsPage.d.ts +2 -0
  37. package/dist/fe/components/IntegrationsPage/components/IntegrationsPage.js +175 -0
  38. package/dist/fe/components/IntegrationsPage/components/MappingEditor.d.ts +15 -0
  39. package/dist/fe/components/IntegrationsPage/components/MappingEditor.js +193 -0
  40. package/dist/fe/components/IntegrationsPage/components/MappingList.d.ts +11 -0
  41. package/dist/fe/components/IntegrationsPage/components/MappingList.js +191 -0
  42. package/dist/fe/components/IntegrationsPage/components/MappingWriteModeFields.d.ts +19 -0
  43. package/dist/fe/components/IntegrationsPage/components/MappingWriteModeFields.js +150 -0
  44. package/dist/fe/components/IntegrationsPage/components/MappingsTab.d.ts +5 -0
  45. package/dist/fe/components/IntegrationsPage/components/MappingsTab.js +154 -0
  46. package/dist/fe/components/IntegrationsPage/components/PaginationFields.d.ts +9 -0
  47. package/dist/fe/components/IntegrationsPage/components/PaginationFields.js +218 -0
  48. package/dist/fe/components/IntegrationsPage/components/ParamBindingRow.d.ts +24 -0
  49. package/dist/fe/components/IntegrationsPage/components/ParamBindingRow.js +180 -0
  50. package/dist/fe/components/IntegrationsPage/components/ParamBindingRows.d.ts +33 -0
  51. package/dist/fe/components/IntegrationsPage/components/ParamBindingRows.js +100 -0
  52. package/dist/fe/components/IntegrationsPage/components/Primitives.d.ts +65 -0
  53. package/dist/fe/components/IntegrationsPage/components/Primitives.js +94 -0
  54. package/dist/fe/components/IntegrationsPage/components/RunConfirmStep.d.ts +10 -0
  55. package/dist/fe/components/IntegrationsPage/components/RunConfirmStep.js +48 -0
  56. package/dist/fe/components/IntegrationsPage/components/RunHistory.d.ts +10 -0
  57. package/dist/fe/components/IntegrationsPage/components/RunHistory.js +124 -0
  58. package/dist/fe/components/IntegrationsPage/components/RunHistoryRow.d.ts +7 -0
  59. package/dist/fe/components/IntegrationsPage/components/RunHistoryRow.js +129 -0
  60. package/dist/fe/components/IntegrationsPage/components/RunPanel.d.ts +9 -0
  61. package/dist/fe/components/IntegrationsPage/components/RunPanel.js +160 -0
  62. package/dist/fe/components/IntegrationsPage/components/RunPlanIssues.d.ts +5 -0
  63. package/dist/fe/components/IntegrationsPage/components/RunPlanIssues.js +43 -0
  64. package/dist/fe/components/IntegrationsPage/components/RunPlanSummary.d.ts +5 -0
  65. package/dist/fe/components/IntegrationsPage/components/RunPlanSummary.js +92 -0
  66. package/dist/fe/components/IntegrationsPage/components/RunProgressBar.d.ts +8 -0
  67. package/dist/fe/components/IntegrationsPage/components/RunProgressBar.js +77 -0
  68. package/dist/fe/components/IntegrationsPage/components/RunRevertConflicts.d.ts +13 -0
  69. package/dist/fe/components/IntegrationsPage/components/RunRevertConflicts.js +65 -0
  70. package/dist/fe/components/IntegrationsPage/components/RunsTab.d.ts +13 -0
  71. package/dist/fe/components/IntegrationsPage/components/RunsTab.js +39 -0
  72. package/dist/fe/components/IntegrationsPage/components/Skeletons.d.ts +9 -0
  73. package/dist/fe/components/IntegrationsPage/components/Skeletons.js +139 -0
  74. package/dist/fe/components/IntegrationsPage/components/authOptions.d.ts +29 -0
  75. package/dist/fe/components/IntegrationsPage/components/authOptions.js +71 -0
  76. package/dist/fe/components/IntegrationsPage/components/connectionDraft.d.ts +64 -0
  77. package/dist/fe/components/IntegrationsPage/components/connectionDraft.js +112 -0
  78. package/dist/fe/components/IntegrationsPage/components/credentialSlots.d.ts +25 -0
  79. package/dist/fe/components/IntegrationsPage/components/credentialSlots.js +67 -0
  80. package/dist/fe/components/IntegrationsPage/components/fieldMappingOptions.d.ts +16 -0
  81. package/dist/fe/components/IntegrationsPage/components/fieldMappingOptions.js +41 -0
  82. package/dist/fe/components/IntegrationsPage/components/formSupport.d.ts +19 -0
  83. package/dist/fe/components/IntegrationsPage/components/formSupport.js +25 -0
  84. package/dist/fe/components/IntegrationsPage/components/mappingDraft.d.ts +40 -0
  85. package/dist/fe/components/IntegrationsPage/components/mappingDraft.js +44 -0
  86. package/dist/fe/components/IntegrationsPage/components/pathParams.d.ts +9 -0
  87. package/dist/fe/components/IntegrationsPage/components/pathParams.js +15 -0
  88. package/dist/fe/components/IntegrationsPage/components/runFormat.d.ts +33 -0
  89. package/dist/fe/components/IntegrationsPage/components/runFormat.js +85 -0
  90. package/dist/fe/components/IntegrationsPage/components/useInfiniteList.d.ts +40 -0
  91. package/dist/fe/components/IntegrationsPage/components/useInfiniteList.js +110 -0
  92. package/dist/fe/components/IntegrationsPage/index.d.ts +18 -0
  93. package/dist/fe/components/IntegrationsPage/index.js +11 -0
  94. package/dist/fe/components/IntegrationsPage/store/index.d.ts +2 -0
  95. package/dist/fe/components/IntegrationsPage/store/index.js +124 -0
  96. package/dist/fe/components/IntegrationsPage/store/state.d.ts +80 -0
  97. package/dist/fe/components/IntegrationsPage/store/state.js +32 -0
  98. package/dist/fe/components/IntegrationsPage/theme/index.d.ts +103 -0
  99. package/dist/fe/components/IntegrationsPage/theme/index.js +113 -0
  100. package/dist/fe/components/IntegrationsPage/types/actions.d.ts +91 -0
  101. package/dist/fe/components/IntegrationsPage/types/actions.js +1 -0
  102. package/dist/fe/components/IntegrationsPage/types/index.d.ts +3 -0
  103. package/dist/fe/components/IntegrationsPage/types/index.js +3 -0
  104. package/dist/fe/components/IntegrationsPage/types/records.d.ts +139 -0
  105. package/dist/fe/components/IntegrationsPage/types/records.js +11 -0
  106. package/dist/fe/components/IntegrationsPage/types/results.d.ts +52 -0
  107. package/dist/fe/components/IntegrationsPage/types/results.js +4 -0
  108. package/dist/fe/index.d.ts +2 -0
  109. package/dist/fe/index.js +1 -0
  110. package/dist/index.js +14 -14
  111. package/dist/src/Client/ApiCaller/system-tables.d.ts +505 -0
  112. package/dist/src/Client/Proxy/wsProxy.js +25 -1
  113. package/dist/src/ElysiaPlugin/routes/backup/types.d.ts +3 -1
  114. package/dist/src/ElysiaPlugin/routes/integrations/index.d.ts +49 -0
  115. package/dist/src/ElysiaPlugin/routes/integrations/inspect.d.ts +87 -0
  116. package/dist/src/ElysiaPlugin/routes/integrations/inspectRoutes.d.ts +41 -0
  117. package/dist/src/ElysiaPlugin/routes/integrations/repository.d.ts +88 -0
  118. package/dist/src/ElysiaPlugin/routes/integrations/types.d.ts +22 -0
  119. package/dist/src/ElysiaPlugin/routes/pubsub/frame.d.ts +37 -0
  120. package/dist/src/ElysiaPlugin/routes/pubsub/frame.test.d.ts +1 -0
  121. package/dist/src/Services/Backup/BackupService.d.ts +16 -8
  122. package/dist/src/Services/Backup/types.d.ts +25 -0
  123. package/dist/src/Services/Integrations/bindings.d.ts +116 -0
  124. package/dist/src/Services/Integrations/bindings.test.d.ts +1 -0
  125. package/dist/src/Services/Integrations/collect.d.ts +68 -0
  126. package/dist/src/Services/Integrations/collect.test.d.ts +1 -0
  127. package/dist/src/Services/Integrations/fetcher.d.ts +100 -0
  128. package/dist/src/Services/Integrations/fetcher.test.d.ts +1 -0
  129. package/dist/src/Services/Integrations/lock.d.ts +77 -0
  130. package/dist/src/Services/Integrations/lock.test.d.ts +1 -0
  131. package/dist/src/Services/Integrations/mapping.d.ts +63 -0
  132. package/dist/src/Services/Integrations/mapping.test.d.ts +1 -0
  133. package/dist/src/Services/Integrations/oauth.d.ts +89 -0
  134. package/dist/src/Services/Integrations/oauth.test.d.ts +1 -0
  135. package/dist/src/Services/Integrations/pagination.d.ts +97 -0
  136. package/dist/src/Services/Integrations/pagination.test.d.ts +1 -0
  137. package/dist/src/Services/Integrations/plan.d.ts +74 -0
  138. package/dist/src/Services/Integrations/plan.test.d.ts +1 -0
  139. package/dist/src/Services/Integrations/revert.d.ts +78 -0
  140. package/dist/src/Services/Integrations/revert.test.d.ts +1 -0
  141. package/dist/src/Services/Integrations/runner.d.ts +126 -0
  142. package/dist/src/Services/Integrations/runner.test.d.ts +1 -0
  143. package/dist/src/Services/Integrations/types.d.ts +208 -0
  144. package/dist/src/Services/Integrations/writer.d.ts +105 -0
  145. package/dist/src/Services/Integrations/writer.test.d.ts +1 -0
  146. package/dist/src/Utils/cron.d.ts +65 -0
  147. package/dist/src/Utils/cron.test.d.ts +1 -0
  148. package/dist/src/types.d.ts +67 -1
  149. package/package.json +1 -1
  150. package/schemas/config.nucleus.json +43 -0
  151. package/schemas/table.schema.json +2 -1
  152. package/scripts/generate-schema.test.ts +78 -0
  153. package/scripts/generate-schema.ts +43 -5
  154. package/src/system.tables.json +362 -0
@@ -0,0 +1,129 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useEffect, useEffectEvent, useState } from 'react';
4
+ import { cn } from '../../../utils/cn';
5
+ import { useIntegrationsStore } from '../store';
6
+ import { integrationsPageTheme } from '../theme';
7
+ import { Badge } from './Primitives';
8
+ import { RunRevertConflicts } from './RunRevertConflicts';
9
+ import { countersLine, errorText, formatDuration, formatMoment, RUN_STATUS_TONE, toEpochMs } from './runFormat';
10
+ /**
11
+ * One past run, and the one thing an operator can still do to it.
12
+ *
13
+ * Undo is offered only while the pre-images behind it still exist; once they are
14
+ * gone the button stays visible but disabled, with the reason spelled out, because
15
+ * a button that quietly disappears reads as a bug rather than as an expiry.
16
+ */ const theme = integrationsPageTheme;
17
+ export function RunHistoryRow({ run, actions, onReverted }) {
18
+ const store = useIntegrationsStore();
19
+ const [reverting, setReverting] = useState(false);
20
+ const [conflicts, setConflicts] = useState(null);
21
+ const [conflictMessage, setConflictMessage] = useState('');
22
+ // Read after mount, never during render: `Date.now()` on the server and in the
23
+ // browser are different numbers, and the disabled state would tear on hydration.
24
+ const [nowMs, setNowMs] = useState(0);
25
+ const readClock = useEffectEvent(()=>{
26
+ setNowMs(Date.now());
27
+ });
28
+ useEffect(()=>{
29
+ readClock();
30
+ }, []);
31
+ const expiresAt = toEpochMs(run.preImagesExpireAt);
32
+ const clockRead = nowMs > 0;
33
+ const undoable = run.status === 'succeeded';
34
+ const withinWindow = clockRead && expiresAt !== null && expiresAt > nowMs;
35
+ const blockedReason = expiresAt === null ? 'This run kept no pre-images, so there is no earlier state to restore.' : 'This run is too old to undo — the earlier state of the rows it changed has been cleaned up.';
36
+ const reportedTotal = run.sourceReportedTotal;
37
+ const mismatch = reportedTotal !== null && reportedTotal !== undefined && reportedTotal !== run.totalFetched;
38
+ const revert = (force)=>{
39
+ store.setError(null);
40
+ setReverting(true);
41
+ actions.revertRun(run.id, force).then((result)=>{
42
+ setReverting(false);
43
+ if (result.ok) {
44
+ setConflicts(null);
45
+ onReverted();
46
+ return;
47
+ }
48
+ const found = result.conflicts ?? [];
49
+ if (found.length > 0) {
50
+ setConflicts(found);
51
+ setConflictMessage(result.message);
52
+ return;
53
+ }
54
+ store.setError(result.message);
55
+ }).catch((error)=>{
56
+ setReverting(false);
57
+ store.setError(errorText(error, 'The run could not be undone.'));
58
+ });
59
+ };
60
+ return /*#__PURE__*/ _jsxs("li", {
61
+ className: cn(theme.card.wrapper, 'flex flex-col gap-2 p-3'),
62
+ children: [
63
+ /*#__PURE__*/ _jsxs("div", {
64
+ className: "flex flex-wrap items-center gap-2",
65
+ children: [
66
+ /*#__PURE__*/ _jsx(Badge, {
67
+ tone: RUN_STATUS_TONE[run.status],
68
+ children: run.status
69
+ }),
70
+ /*#__PURE__*/ _jsx("span", {
71
+ className: theme.card.title,
72
+ children: run.targetEntity ?? 'unknown target'
73
+ }),
74
+ run.writeMode ? /*#__PURE__*/ _jsx(Badge, {
75
+ tone: "neutral",
76
+ children: run.writeMode
77
+ }) : null,
78
+ run.trigger ? /*#__PURE__*/ _jsx(Badge, {
79
+ tone: "neutral",
80
+ children: run.trigger
81
+ }) : null,
82
+ mismatch ? /*#__PURE__*/ _jsx(Badge, {
83
+ tone: "warning",
84
+ children: `read ${run.totalFetched} of ${reportedTotal}`
85
+ }) : null
86
+ ]
87
+ }),
88
+ /*#__PURE__*/ _jsx("p", {
89
+ className: theme.field.hint,
90
+ children: countersLine(run)
91
+ }),
92
+ /*#__PURE__*/ _jsx("p", {
93
+ className: theme.field.hint,
94
+ children: `${formatMoment(run.startedAt ?? run.createdAt)} · took ${formatDuration(run.startedAt, run.finishedAt)} · ${run.totalFetched} fetched`
95
+ }),
96
+ undoable ? /*#__PURE__*/ _jsxs("div", {
97
+ className: "flex flex-wrap items-center gap-2",
98
+ children: [
99
+ /*#__PURE__*/ _jsx("button", {
100
+ className: theme.button.secondary,
101
+ disabled: !withinWindow || reverting,
102
+ onClick: ()=>revert(false),
103
+ type: "button",
104
+ children: reverting ? 'Undoing…' : 'Undo'
105
+ }),
106
+ withinWindow ? /*#__PURE__*/ _jsx("span", {
107
+ className: theme.field.hint,
108
+ children: `Can be undone until ${formatMoment(run.preImagesExpireAt)}`
109
+ }) : null,
110
+ clockRead && !withinWindow ? /*#__PURE__*/ _jsx("span", {
111
+ className: theme.field.hint,
112
+ children: blockedReason
113
+ }) : null
114
+ ]
115
+ }) : null,
116
+ run.revertedAt ? /*#__PURE__*/ _jsx("p", {
117
+ className: theme.field.hint,
118
+ children: `Undone at ${formatMoment(run.revertedAt)}`
119
+ }) : null,
120
+ conflicts ? /*#__PURE__*/ _jsx(RunRevertConflicts, {
121
+ conflicts: conflicts,
122
+ message: conflictMessage,
123
+ onDismiss: ()=>setConflicts(null),
124
+ onOverwrite: ()=>revert(true),
125
+ working: reverting
126
+ }) : null
127
+ ]
128
+ });
129
+ }
@@ -0,0 +1,9 @@
1
+ import type { IntegrationMapping, IntegrationsActions, RunProgressValue } from '../types';
2
+ export type RunPanelProps = {
3
+ mapping: IntegrationMapping;
4
+ actions: IntegrationsActions;
5
+ onSubscribeProgress?: (handler: (progress: RunProgressValue) => void) => () => void;
6
+ /** Called when a run reaches its end, so the history beneath can refetch. */
7
+ onRunSettled?: () => void;
8
+ };
9
+ export declare function RunPanel({ mapping, actions, onSubscribeProgress, onRunSettled }: RunPanelProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,160 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useEffect, useEffectEvent, useState } from 'react';
4
+ import { useIntegrationsStore } from '../store';
5
+ import { integrationsPageTheme } from '../theme';
6
+ import { Notice } from './Primitives';
7
+ import { RunConfirmStep } from './RunConfirmStep';
8
+ import { RunPlanSummary } from './RunPlanSummary';
9
+ import { RunProgressBar } from './RunProgressBar';
10
+ import { describeLosses, errorText } from './runFormat';
11
+ import { StatGridSkeleton } from './Skeletons';
12
+ /**
13
+ * Preview, then run.
14
+ *
15
+ * The two are separate on purpose: a preview writes nothing and can be repeated,
16
+ * and the counts it reports are what the confirmation step later quotes back. The
17
+ * panel owns no data of its own — the plan, the progress and the active run all
18
+ * live in the store, so a tab switch cannot lose a running import.
19
+ */ const theme = integrationsPageTheme;
20
+ export function RunPanel({ mapping, actions, onSubscribeProgress, onRunSettled }) {
21
+ const store = useIntegrationsStore();
22
+ const [confirming, setConfirming] = useState(false);
23
+ const [starting, setStarting] = useState(false);
24
+ const [cancelling, setCancelling] = useState(false);
25
+ const activeRunId = store.activeRunId;
26
+ const plan = store.plan;
27
+ const preview = ()=>{
28
+ store.setError(null);
29
+ store.setPlanning(true);
30
+ actions.previewRun(mapping.id).then((result)=>{
31
+ if (result.error) store.setError(result.error);
32
+ store.setPlan(result.plan);
33
+ }).catch((error)=>{
34
+ store.setPlanning(false);
35
+ store.setError(errorText(error, 'The preview could not be computed.'));
36
+ });
37
+ };
38
+ const start = (confirm)=>{
39
+ store.setError(null);
40
+ setStarting(true);
41
+ actions.startRun(mapping.id, confirm).then((result)=>{
42
+ setStarting(false);
43
+ // The server decides what counts as destructive; the panel only asks.
44
+ if (result.needsConfirm) {
45
+ setConfirming(true);
46
+ return;
47
+ }
48
+ if (result.error) {
49
+ store.setError(result.error);
50
+ return;
51
+ }
52
+ if (!result.runId) {
53
+ store.setError('The import was accepted but no run id came back, so it cannot be tracked.');
54
+ return;
55
+ }
56
+ setConfirming(false);
57
+ store.setActiveRun(result.runId);
58
+ }).catch((error)=>{
59
+ setStarting(false);
60
+ store.setError(errorText(error, 'The import could not be started.'));
61
+ });
62
+ };
63
+ const cancel = ()=>{
64
+ const runId = store.activeRunId;
65
+ if (!runId) return;
66
+ setCancelling(true);
67
+ actions.cancelRun(runId).then((accepted)=>{
68
+ setCancelling(false);
69
+ if (!accepted) store.setError('The run did not accept the cancel request.');
70
+ }).catch((error)=>{
71
+ setCancelling(false);
72
+ store.setError(errorText(error, 'The cancel request failed.'));
73
+ });
74
+ };
75
+ // Progress for SOMEONE ELSE'S run is dropped: the topic is shared, and a
76
+ // second operator's import must not drive this panel's bar.
77
+ const applyProgress = useEffectEvent((progress)=>{
78
+ if (store.activeRunId !== progress.runId) return;
79
+ store.setProgress(progress);
80
+ if (progress.phase === 'done') {
81
+ store.setActiveRun(null);
82
+ onRunSettled?.();
83
+ }
84
+ });
85
+ const openProgressStream = useEffectEvent(()=>onSubscribeProgress?.(applyProgress));
86
+ useEffect(()=>{
87
+ // The app hands back its own unsubscribe; returning it is the cleanup.
88
+ const close = openProgressStream();
89
+ return close;
90
+ }, []);
91
+ return /*#__PURE__*/ _jsxs("section", {
92
+ className: theme.card.wrapper,
93
+ children: [
94
+ /*#__PURE__*/ _jsxs("header", {
95
+ className: theme.card.header,
96
+ children: [
97
+ /*#__PURE__*/ _jsxs("div", {
98
+ className: "flex min-w-0 flex-col gap-0.5",
99
+ children: [
100
+ /*#__PURE__*/ _jsx("h3", {
101
+ className: theme.card.title,
102
+ children: mapping.name
103
+ }),
104
+ /*#__PURE__*/ _jsx("p", {
105
+ className: theme.field.hint,
106
+ children: `Writes into ${mapping.targetEntity} · ${mapping.writeMode} · missing rows: ${mapping.missingRecordPolicy}`
107
+ })
108
+ ]
109
+ }),
110
+ /*#__PURE__*/ _jsxs("div", {
111
+ className: theme.header.actions,
112
+ children: [
113
+ /*#__PURE__*/ _jsx("button", {
114
+ className: theme.button.secondary,
115
+ disabled: store.planning || activeRunId !== null,
116
+ onClick: preview,
117
+ type: "button",
118
+ children: store.planning ? 'Previewing…' : 'Preview'
119
+ }),
120
+ /*#__PURE__*/ _jsx("button", {
121
+ className: theme.button.primary,
122
+ disabled: starting || confirming || activeRunId !== null,
123
+ onClick: ()=>start(false),
124
+ type: "button",
125
+ children: starting ? 'Starting…' : 'Run import'
126
+ })
127
+ ]
128
+ })
129
+ ]
130
+ }),
131
+ /*#__PURE__*/ _jsxs("div", {
132
+ className: theme.card.body,
133
+ children: [
134
+ activeRunId ? /*#__PURE__*/ _jsx(RunProgressBar, {
135
+ cancelling: cancelling,
136
+ onCancel: cancel,
137
+ progress: store.progress,
138
+ runId: activeRunId
139
+ }) : null,
140
+ confirming ? /*#__PURE__*/ _jsx(RunConfirmStep, {
141
+ counted: plan !== null,
142
+ lines: describeLosses(mapping, plan),
143
+ onConfirm: ()=>start(true),
144
+ onDismiss: ()=>setConfirming(false),
145
+ working: starting
146
+ }) : null,
147
+ store.planning ? /*#__PURE__*/ _jsx(StatGridSkeleton, {}) : null,
148
+ !store.planning && plan ? /*#__PURE__*/ _jsx(RunPlanSummary, {
149
+ plan: plan
150
+ }) : null,
151
+ !(store.planning || plan || activeRunId) ? /*#__PURE__*/ _jsx(Notice, {
152
+ tone: "info",
153
+ title: "Preview before you run",
154
+ children: "A preview reads the source without writing anything, and reports how many rows would be created, updated, skipped, and how many rows in the target the source no longer returns."
155
+ }) : null
156
+ ]
157
+ })
158
+ ]
159
+ });
160
+ }
@@ -0,0 +1,5 @@
1
+ import type { RunIssueValue } from '../types';
2
+ export type RunPlanIssuesProps = {
3
+ issues: RunIssueValue[];
4
+ };
5
+ export declare function RunPlanIssues({ issues }: RunPlanIssuesProps): import("react/jsx-runtime").JSX.Element | null;
@@ -0,0 +1,43 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { cn } from '../../../utils/cn';
4
+ import { integrationsPageTheme } from '../theme';
5
+ /**
6
+ * The records the planner could not use, folded away.
7
+ *
8
+ * Folded because a healthy plan has none and an unhealthy one can have hundreds;
9
+ * open because the source index is the only way back to the offending record.
10
+ * Messages wrap rather than truncate — a clipped reason is a reason nobody acts on.
11
+ */ const theme = integrationsPageTheme;
12
+ export function RunPlanIssues({ issues }) {
13
+ if (issues.length === 0) return null;
14
+ return /*#__PURE__*/ _jsxs("details", {
15
+ className: cn(theme.card.wrapper, 'px-3 py-2.5 sm:px-4 sm:py-3'),
16
+ children: [
17
+ /*#__PURE__*/ _jsx("summary", {
18
+ className: cn(theme.card.title, 'cursor-pointer'),
19
+ children: `${issues.length} record(s) the plan could not use`
20
+ }),
21
+ /*#__PURE__*/ _jsx("ul", {
22
+ className: "mt-2 flex flex-col gap-2",
23
+ children: issues.map((issue, index)=>/*#__PURE__*/ _jsxs("li", {
24
+ className: "flex flex-col gap-0.5",
25
+ children: [
26
+ /*#__PURE__*/ _jsx("span", {
27
+ className: theme.card.title,
28
+ children: `Source record #${issue.sourceIndex} — ${issue.kind}`
29
+ }),
30
+ /*#__PURE__*/ _jsx("span", {
31
+ className: theme.field.hint,
32
+ children: issue.message
33
+ }),
34
+ issue.dedupKey ? /*#__PURE__*/ _jsx("span", {
35
+ className: theme.field.hint,
36
+ children: `Dedup key: ${issue.dedupKey}`
37
+ }) : null
38
+ ]
39
+ }, `${issue.sourceIndex}-${issue.kind}-${index}`))
40
+ })
41
+ ]
42
+ });
43
+ }
@@ -0,0 +1,5 @@
1
+ import type { RunPlanValue } from '../types';
2
+ export type RunPlanSummaryProps = {
3
+ plan: RunPlanValue;
4
+ };
5
+ export declare function RunPlanSummary({ plan }: RunPlanSummaryProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,92 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { integrationsPageTheme } from '../theme';
4
+ import { Badge, Notice, Stat } from './Primitives';
5
+ import { RunPlanIssues } from './RunPlanIssues';
6
+ /**
7
+ * What the run WOULD do, before it does any of it.
8
+ *
9
+ * The counts come first because they are what gets approved; the server's own
10
+ * warnings are reproduced word for word underneath, never shortened — a warning
11
+ * an operator has to expand to read is a warning they run past.
12
+ */ const theme = integrationsPageTheme;
13
+ /** Missing rows are only alarming when the policy actually does something to them. */ function missingTone(plan) {
14
+ if (plan.missing === 0) return undefined;
15
+ if (plan.missingPolicy === 'delete') return 'danger';
16
+ if (plan.missingPolicy === 'deactivate') return 'warning';
17
+ return undefined;
18
+ }
19
+ export function RunPlanSummary({ plan }) {
20
+ // A source that reports a total and hands over a different number of records
21
+ // is the loudest symptom of a wrong pagination profile, and the run that
22
+ // follows treats everything it never saw as missing.
23
+ const countMismatch = plan.reportedTotal !== null && plan.reportedTotal !== plan.totalFetched;
24
+ return /*#__PURE__*/ _jsxs("section", {
25
+ className: "flex flex-col gap-3",
26
+ children: [
27
+ /*#__PURE__*/ _jsxs("div", {
28
+ className: "flex flex-wrap items-center gap-2",
29
+ children: [
30
+ /*#__PURE__*/ _jsx(Badge, {
31
+ tone: "neutral",
32
+ children: plan.targetEntity
33
+ }),
34
+ /*#__PURE__*/ _jsx(Badge, {
35
+ tone: "info",
36
+ children: plan.writeMode
37
+ }),
38
+ /*#__PURE__*/ _jsx(Badge, {
39
+ tone: plan.dedupConfigured ? 'neutral' : 'warning',
40
+ children: plan.dedupConfigured ? 'dedup key set' : 'no dedup key'
41
+ }),
42
+ /*#__PURE__*/ _jsx(Badge, {
43
+ tone: "neutral",
44
+ children: `missing rows: ${plan.missingPolicy}`
45
+ })
46
+ ]
47
+ }),
48
+ countMismatch ? /*#__PURE__*/ _jsx(Notice, {
49
+ tone: "danger",
50
+ title: "The source and the reader disagree on how many records exist",
51
+ children: `The source reports ${plan.reportedTotal} record(s); ${plan.totalFetched} were actually read. Check the endpoint's pagination profile before running: a wrong profile reads one page, and every record it never saw counts as missing.`
52
+ }) : null,
53
+ /*#__PURE__*/ _jsxs("div", {
54
+ className: theme.stat.grid,
55
+ children: [
56
+ /*#__PURE__*/ _jsx(Stat, {
57
+ label: "To create",
58
+ value: plan.toCreate
59
+ }),
60
+ /*#__PURE__*/ _jsx(Stat, {
61
+ label: "To update",
62
+ value: plan.toUpdate
63
+ }),
64
+ /*#__PURE__*/ _jsx(Stat, {
65
+ label: "To skip",
66
+ value: plan.toSkip
67
+ }),
68
+ /*#__PURE__*/ _jsx(Stat, {
69
+ label: "Missing",
70
+ tone: missingTone(plan),
71
+ value: plan.missing
72
+ }),
73
+ /*#__PURE__*/ _jsx(Stat, {
74
+ label: "Already there",
75
+ value: plan.existingCount
76
+ }),
77
+ /*#__PURE__*/ _jsx(Stat, {
78
+ label: "Fetched",
79
+ value: plan.totalFetched
80
+ })
81
+ ]
82
+ }),
83
+ plan.warnings.map((warning, index)=>/*#__PURE__*/ _jsx(Notice, {
84
+ title: warning,
85
+ tone: "warning"
86
+ }, `${index}-${warning}`)),
87
+ /*#__PURE__*/ _jsx(RunPlanIssues, {
88
+ issues: plan.issues
89
+ })
90
+ ]
91
+ });
92
+ }
@@ -0,0 +1,8 @@
1
+ import type { RunProgressValue } from '../types';
2
+ export type RunProgressBarProps = {
3
+ runId: string;
4
+ progress: RunProgressValue | null;
5
+ cancelling: boolean;
6
+ onCancel: () => void;
7
+ };
8
+ export declare function RunProgressBar({ runId, progress, cancelling, onCancel }: RunProgressBarProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,77 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { cn } from '../../../utils/cn';
4
+ import { integrationsPageTheme } from '../theme';
5
+ /**
6
+ * How far the run this panel started has got.
7
+ *
8
+ * A run that reports no total still gets a bar — an indeterminate one — because
9
+ * the alternative is a screen that looks frozen while the source is being paged.
10
+ * Cancel lives here, next to the thing it stops, and nowhere else.
11
+ */ const theme = integrationsPageTheme;
12
+ const PHASE_LABEL = {
13
+ fetching: 'Reading from the source',
14
+ mapping: 'Mapping fields',
15
+ validating: 'Validating records',
16
+ writing: 'Writing to the target',
17
+ done: 'Finished'
18
+ };
19
+ export function RunProgressBar({ runId, progress, cancelling, onCancel }) {
20
+ const total = progress?.total ?? 0;
21
+ const processed = progress?.processed ?? 0;
22
+ const determinate = total > 0;
23
+ const percent = determinate ? Math.min(100, Math.max(0, Math.round(processed / total * 100))) : 0;
24
+ return /*#__PURE__*/ _jsxs("section", {
25
+ "aria-live": "polite",
26
+ className: "flex flex-col gap-2",
27
+ children: [
28
+ /*#__PURE__*/ _jsxs("div", {
29
+ className: "flex flex-wrap items-center justify-between gap-2",
30
+ children: [
31
+ /*#__PURE__*/ _jsx("span", {
32
+ className: theme.progress.label,
33
+ children: progress ? PHASE_LABEL[progress.phase] : 'Waiting for the first update'
34
+ }),
35
+ /*#__PURE__*/ _jsx("span", {
36
+ className: theme.progress.label,
37
+ children: determinate ? `${processed} / ${total} (${percent}%)` : `${processed} processed`
38
+ })
39
+ ]
40
+ }),
41
+ /*#__PURE__*/ _jsx("div", {
42
+ "aria-label": "Import progress",
43
+ "aria-valuemax": determinate ? total : undefined,
44
+ "aria-valuemin": determinate ? 0 : undefined,
45
+ "aria-valuenow": determinate ? processed : undefined,
46
+ className: theme.progress.track,
47
+ role: "progressbar",
48
+ children: /*#__PURE__*/ _jsx("div", {
49
+ className: cn(theme.progress.bar, !determinate && 'animate-pulse'),
50
+ style: {
51
+ width: determinate ? `${percent}%` : '100%'
52
+ }
53
+ })
54
+ }),
55
+ progress?.message ? /*#__PURE__*/ _jsx("p", {
56
+ className: theme.progress.label,
57
+ children: progress.message
58
+ }) : null,
59
+ /*#__PURE__*/ _jsxs("div", {
60
+ className: "flex flex-wrap items-center justify-between gap-2",
61
+ children: [
62
+ /*#__PURE__*/ _jsx("span", {
63
+ className: theme.progress.label,
64
+ children: `Run ${runId}`
65
+ }),
66
+ /*#__PURE__*/ _jsx("button", {
67
+ className: theme.button.danger,
68
+ disabled: cancelling,
69
+ onClick: onCancel,
70
+ type: "button",
71
+ children: cancelling ? 'Cancelling…' : 'Cancel'
72
+ })
73
+ ]
74
+ })
75
+ ]
76
+ });
77
+ }
@@ -0,0 +1,13 @@
1
+ export type RevertConflictValue = {
2
+ id: string;
3
+ reason: string;
4
+ };
5
+ export type RunRevertConflictsProps = {
6
+ conflicts: RevertConflictValue[];
7
+ /** What the server said when it refused. Shown as it came. */
8
+ message: string;
9
+ working: boolean;
10
+ onOverwrite: () => void;
11
+ onDismiss: () => void;
12
+ };
13
+ export declare function RunRevertConflicts({ conflicts, message, working, onOverwrite, onDismiss, }: RunRevertConflictsProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,65 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { integrationsPageTheme } from '../theme';
4
+ /**
5
+ * The rows somebody edited by hand after the import wrote them.
6
+ *
7
+ * Undoing the run would restore the pre-image over that person's work, so the
8
+ * first Undo stops here and names every row it would trample. Overwriting is a
9
+ * SECOND, separate decision — it never rides along on the first click.
10
+ */ const theme = integrationsPageTheme;
11
+ export function RunRevertConflicts({ conflicts, message, working, onOverwrite, onDismiss }) {
12
+ return /*#__PURE__*/ _jsxs("section", {
13
+ className: theme.notice.danger,
14
+ role: "alert",
15
+ children: [
16
+ /*#__PURE__*/ _jsx("p", {
17
+ className: theme.notice.title,
18
+ children: `${conflicts.length} row(s) changed after this run. Undoing would overwrite those changes.`
19
+ }),
20
+ /*#__PURE__*/ _jsxs("div", {
21
+ className: theme.notice.body,
22
+ children: [
23
+ message ? /*#__PURE__*/ _jsx("p", {
24
+ children: message
25
+ }) : null,
26
+ /*#__PURE__*/ _jsx("ul", {
27
+ className: "mt-2 flex flex-col gap-1",
28
+ children: conflicts.map((conflict)=>/*#__PURE__*/ _jsxs("li", {
29
+ className: "flex flex-col gap-0.5",
30
+ children: [
31
+ /*#__PURE__*/ _jsx("span", {
32
+ className: "font-mono text-xs",
33
+ children: conflict.id
34
+ }),
35
+ /*#__PURE__*/ _jsx("span", {
36
+ className: "text-xs opacity-90",
37
+ children: conflict.reason
38
+ })
39
+ ]
40
+ }, conflict.id))
41
+ }),
42
+ /*#__PURE__*/ _jsxs("div", {
43
+ className: "mt-3 flex flex-wrap items-center gap-2",
44
+ children: [
45
+ /*#__PURE__*/ _jsx("button", {
46
+ className: theme.button.danger,
47
+ disabled: working,
48
+ onClick: onOverwrite,
49
+ type: "button",
50
+ children: working ? 'Overwriting…' : 'Overwrite them anyway'
51
+ }),
52
+ /*#__PURE__*/ _jsx("button", {
53
+ className: theme.button.secondary,
54
+ disabled: working,
55
+ onClick: onDismiss,
56
+ type: "button",
57
+ children: "Leave those rows alone"
58
+ })
59
+ ]
60
+ })
61
+ ]
62
+ })
63
+ ]
64
+ });
65
+ }
@@ -0,0 +1,13 @@
1
+ import type { IntegrationsActions, RunProgressValue } from '../types';
2
+ /**
3
+ * The runs tab: what an import would do, and what every import has done.
4
+ *
5
+ * The panel needs a mapping — it is the mapping that names a target and a write
6
+ * mode — but the history does not, so a connection with no mapping selected still
7
+ * shows its past runs instead of an empty screen.
8
+ */
9
+ export type RunsTabProps = {
10
+ actions: IntegrationsActions;
11
+ onSubscribeProgress?: (handler: (progress: RunProgressValue) => void) => () => void;
12
+ };
13
+ export declare function RunsTab({ actions, onSubscribeProgress }: RunsTabProps): import("react/jsx-runtime").JSX.Element;