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,204 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import { useRef, useState } from 'react';
4
+ import { useIntegrationsStore } from '../store';
5
+ import { integrationsPageTheme } from '../theme';
6
+ import { Badge, CodeBlock, Field, Notice, Stat } from './Primitives';
7
+ import { pathParamNames } from './pathParams';
8
+ import { CardSkeleton, StatGridSkeleton } from './Skeletons';
9
+ /**
10
+ * One real request, shown in full.
11
+ *
12
+ * The interesting case is zero records, because that is when a configuration
13
+ * looks finished and imports nothing. The server already answers it — it returns
14
+ * the top-level keys of the body it actually received — so those keys are given
15
+ * their own block here rather than being folded into a generic "no data".
16
+ */ const theme = integrationsPageTheme;
17
+ export function EndpointSample({ endpoint, actions }) {
18
+ const store = useIntegrationsStore();
19
+ const [values, setValues] = useState({});
20
+ // Kept in step with the render so an in-flight reply can ask what is selected
21
+ // NOW, not what was selected when it was sent.
22
+ const selectedRef = useRef(store.selectedEndpointId);
23
+ selectedRef.current = store.selectedEndpointId;
24
+ const params = pathParamNames(endpoint.path);
25
+ const sample = store.sample;
26
+ let unfilled = 0;
27
+ for (const name of params){
28
+ if (!(values[name] ?? '').trim()) unfilled += 1;
29
+ }
30
+ const run = ()=>{
31
+ // The endpoint this request is FOR. A sample can take seconds against a slow
32
+ // source, and an operator who clicks another endpoint meanwhile would
33
+ // otherwise get the first one's answer written in as the second one's field
34
+ // list — and then map against fields the endpoint does not have.
35
+ const requestedFor = endpoint.id;
36
+ store.setSampling(true);
37
+ store.setError(null);
38
+ actions.sampleEndpoint(requestedFor, params.length > 0 ? values : undefined).then((result)=>{
39
+ if (selectedRef.current !== requestedFor) return;
40
+ store.setSample(result);
41
+ if (!result.ok && result.error) store.setError(result.error);
42
+ }).catch((error)=>{
43
+ if (selectedRef.current !== requestedFor) return;
44
+ store.setSample(null);
45
+ store.setError(error instanceof Error ? error.message : 'Sampling the endpoint failed.');
46
+ });
47
+ };
48
+ return /*#__PURE__*/ _jsxs("section", {
49
+ className: theme.card.wrapper,
50
+ children: [
51
+ /*#__PURE__*/ _jsxs("header", {
52
+ className: theme.card.header,
53
+ children: [
54
+ /*#__PURE__*/ _jsx("h3", {
55
+ className: theme.card.title,
56
+ children: "Response sample"
57
+ }),
58
+ /*#__PURE__*/ _jsx("button", {
59
+ className: theme.button.secondary,
60
+ disabled: store.sampling || unfilled > 0,
61
+ onClick: run,
62
+ type: "button",
63
+ children: store.sampling ? 'Sampling…' : 'Send one request'
64
+ })
65
+ ]
66
+ }),
67
+ /*#__PURE__*/ _jsxs("div", {
68
+ className: theme.card.body,
69
+ children: [
70
+ params.length > 0 ? /*#__PURE__*/ _jsxs("fieldset", {
71
+ className: "flex flex-col gap-2 border-0 p-0",
72
+ children: [
73
+ /*#__PURE__*/ _jsx("legend", {
74
+ className: theme.field.label,
75
+ children: "Example path parameter values"
76
+ }),
77
+ /*#__PURE__*/ _jsx("p", {
78
+ className: theme.field.hint,
79
+ children: "Used for this one request only. During a run each parameter takes its value from the binding configured for it."
80
+ }),
81
+ /*#__PURE__*/ _jsx("div", {
82
+ className: "grid grid-cols-1 gap-3 sm:grid-cols-2",
83
+ children: params.map((name)=>/*#__PURE__*/ _jsx(Field, {
84
+ htmlFor: `sample-param-${name}`,
85
+ label: name,
86
+ children: /*#__PURE__*/ _jsx("input", {
87
+ className: theme.field.input,
88
+ id: `sample-param-${name}`,
89
+ onChange: (event)=>setValues((previous)=>({
90
+ ...previous,
91
+ [name]: event.target.value
92
+ })),
93
+ placeholder: "example value",
94
+ type: "text",
95
+ value: values[name] ?? ''
96
+ })
97
+ }, name))
98
+ })
99
+ ]
100
+ }) : null,
101
+ store.sampling ? /*#__PURE__*/ _jsxs(_Fragment, {
102
+ children: [
103
+ /*#__PURE__*/ _jsx(StatGridSkeleton, {}),
104
+ /*#__PURE__*/ _jsx(CardSkeleton, {})
105
+ ]
106
+ }) : null,
107
+ !store.sampling && sample ? /*#__PURE__*/ _jsxs(_Fragment, {
108
+ children: [
109
+ /*#__PURE__*/ _jsxs("div", {
110
+ className: theme.stat.grid,
111
+ children: [
112
+ /*#__PURE__*/ _jsx(Stat, {
113
+ label: "HTTP status",
114
+ tone: sample.ok ? 'success' : 'danger',
115
+ value: sample.status
116
+ }),
117
+ /*#__PURE__*/ _jsx(Stat, {
118
+ label: "Records read",
119
+ tone: sample.recordCount === 0 ? 'warning' : undefined,
120
+ value: sample.recordCount
121
+ }),
122
+ /*#__PURE__*/ _jsx(Stat, {
123
+ label: "Fields",
124
+ value: sample.fields.length
125
+ }),
126
+ /*#__PURE__*/ _jsx(Stat, {
127
+ label: "Body keys",
128
+ value: sample.bodyKeys.length
129
+ })
130
+ ]
131
+ }),
132
+ sample.error ? /*#__PURE__*/ _jsx(Notice, {
133
+ title: "The source answered with an error",
134
+ tone: "danger",
135
+ children: sample.error
136
+ }) : null,
137
+ sample.recordCount === 0 ? /*#__PURE__*/ _jsxs(Notice, {
138
+ title: "The request succeeded and no records were read",
139
+ tone: "warning",
140
+ children: [
141
+ /*#__PURE__*/ _jsx("p", {
142
+ children: "These are the top-level keys of the body the source returned. Set the response root path to whichever holds the list."
143
+ }),
144
+ sample.bodyKeys.length > 0 ? /*#__PURE__*/ _jsx("ul", {
145
+ className: "mt-2 flex flex-wrap gap-1.5",
146
+ children: sample.bodyKeys.map((key)=>/*#__PURE__*/ _jsx("li", {
147
+ children: /*#__PURE__*/ _jsx(Badge, {
148
+ tone: "info",
149
+ children: key
150
+ })
151
+ }, key))
152
+ }) : /*#__PURE__*/ _jsx("p", {
153
+ className: "mt-2",
154
+ children: "The body has no top-level keys at all: it is empty, or it is a bare value rather than an object."
155
+ }),
156
+ sample.bodyPreview ? /*#__PURE__*/ _jsx("div", {
157
+ className: "mt-2",
158
+ children: /*#__PURE__*/ _jsx(CodeBlock, {
159
+ children: sample.bodyPreview
160
+ })
161
+ }) : null
162
+ ]
163
+ }) : null,
164
+ sample.fields.length > 0 ? /*#__PURE__*/ _jsxs("section", {
165
+ className: "flex flex-col gap-1.5",
166
+ children: [
167
+ /*#__PURE__*/ _jsx("h4", {
168
+ className: theme.field.label,
169
+ children: "Fields on the first record"
170
+ }),
171
+ /*#__PURE__*/ _jsx("ul", {
172
+ className: "flex flex-wrap gap-1.5",
173
+ children: sample.fields.map((field)=>/*#__PURE__*/ _jsx("li", {
174
+ children: /*#__PURE__*/ _jsx(Badge, {
175
+ tone: "neutral",
176
+ children: field
177
+ })
178
+ }, field))
179
+ })
180
+ ]
181
+ }) : null,
182
+ sample.sample.length > 0 ? /*#__PURE__*/ _jsxs("section", {
183
+ className: "flex flex-col gap-1.5",
184
+ children: [
185
+ /*#__PURE__*/ _jsx("h4", {
186
+ className: theme.field.label,
187
+ children: "Sample records"
188
+ }),
189
+ /*#__PURE__*/ _jsx(CodeBlock, {
190
+ children: JSON.stringify(sample.sample, null, 2)
191
+ })
192
+ ]
193
+ }) : null
194
+ ]
195
+ }) : null,
196
+ !store.sampling && !sample ? /*#__PURE__*/ _jsx("p", {
197
+ className: theme.field.hint,
198
+ children: "Nothing has been sampled yet. One request is sent, read-only, and the shape it comes back with is what the field mapping is built from."
199
+ }) : null
200
+ ]
201
+ })
202
+ ]
203
+ });
204
+ }
@@ -0,0 +1,5 @@
1
+ import type { IntegrationsActions } from '../types';
2
+ export type EndpointsTabProps = {
3
+ actions: IntegrationsActions;
4
+ };
5
+ export declare function EndpointsTab({ actions }: EndpointsTabProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,101 @@
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 { EndpointForm } from './EndpointForm';
7
+ import { EndpointList } from './EndpointList';
8
+ import { EndpointSample } from './EndpointSample';
9
+ /**
10
+ * The endpoints section: the list on one side, the selected call on the other.
11
+ *
12
+ * The record the list hands over is the record the form edits, so opening an
13
+ * endpoint costs no extra request. The form is keyed by that record's id, which
14
+ * is what makes switching selection a fresh form rather than a merged one.
15
+ */ const theme = integrationsPageTheme;
16
+ export function EndpointsTab({ actions }) {
17
+ const store = useIntegrationsStore();
18
+ const sourceId = store.selectedSourceId;
19
+ const [selected, setSelected] = useState(null);
20
+ const [creating, setCreating] = useState(false);
21
+ const [reloadToken, setReloadToken] = useState(0);
22
+ // Another connection is another set of endpoints. A form left open across the
23
+ // change would be editing a record this connection does not own.
24
+ const reset = useEffectEvent(()=>{
25
+ setSelected(null);
26
+ setCreating(false);
27
+ });
28
+ useEffect(()=>{
29
+ reset();
30
+ }, [
31
+ sourceId
32
+ ]);
33
+ const handleNew = ()=>{
34
+ setSelected(null);
35
+ setCreating(true);
36
+ };
37
+ const handleSelect = (endpoint)=>{
38
+ setSelected(endpoint);
39
+ setCreating(false);
40
+ };
41
+ const handleSaved = (saved)=>{
42
+ setSelected(saved);
43
+ setCreating(false);
44
+ // Re-selecting drops the old sample: it described the endpoint as it was
45
+ // configured a moment ago, and the mapping would be built from it.
46
+ store.selectEndpoint(saved.id);
47
+ setReloadToken((token)=>token + 1);
48
+ };
49
+ const handleDeleted = ()=>{
50
+ setSelected(null);
51
+ setCreating(false);
52
+ store.selectEndpoint(null);
53
+ setReloadToken((token)=>token + 1);
54
+ };
55
+ const handleCancel = ()=>{
56
+ setSelected(null);
57
+ setCreating(false);
58
+ store.selectEndpoint(null);
59
+ };
60
+ if (!sourceId) {
61
+ return /*#__PURE__*/ _jsx("p", {
62
+ className: theme.list.empty,
63
+ children: "Select a connection to see its endpoints."
64
+ });
65
+ }
66
+ // Guarded against the store: the selection is the store's, and a record left
67
+ // over from the previous one must not be what the form shows.
68
+ const editing = selected && selected.id === store.selectedEndpointId ? selected : null;
69
+ return /*#__PURE__*/ _jsxs("div", {
70
+ className: "grid grid-cols-1 gap-4 xl:grid-cols-[minmax(0,18rem)_minmax(0,1fr)] xl:gap-5",
71
+ children: [
72
+ /*#__PURE__*/ _jsx(EndpointList, {
73
+ actions: actions,
74
+ onNewEndpoint: handleNew,
75
+ onSelect: handleSelect,
76
+ reloadToken: reloadToken,
77
+ sourceId: sourceId
78
+ }, sourceId),
79
+ /*#__PURE__*/ _jsxs("div", {
80
+ className: theme.layout.main,
81
+ children: [
82
+ editing || creating ? /*#__PURE__*/ _jsx(EndpointForm, {
83
+ actions: actions,
84
+ endpoint: editing,
85
+ onCancel: handleCancel,
86
+ onDeleted: handleDeleted,
87
+ onSaved: handleSaved,
88
+ sourceId: sourceId
89
+ }, editing?.id ?? 'new') : /*#__PURE__*/ _jsx("p", {
90
+ className: theme.list.empty,
91
+ children: "Select an endpoint to edit it, or add one. An endpoint is a single call — a method, a path, and where in the answer the records sit."
92
+ }),
93
+ editing ? /*#__PURE__*/ _jsx(EndpointSample, {
94
+ actions: actions,
95
+ endpoint: editing
96
+ }, editing.id) : null
97
+ ]
98
+ })
99
+ ]
100
+ });
101
+ }
@@ -0,0 +1,17 @@
1
+ import type { FieldMappingValue } from '../types';
2
+ export type FieldMappingRowProps = {
3
+ row: FieldMappingValue;
4
+ /** Position in the list, from zero. Also what the labels count from. */
5
+ index: number;
6
+ /** Id of the datalist holding the sampled source field names. */
7
+ sourceListId: string;
8
+ /** Columns of the chosen target entity. Empty until an entity is chosen. */
9
+ targetFields: string[];
10
+ isFirst: boolean;
11
+ isLast: boolean;
12
+ disabled?: boolean;
13
+ onPatch: (patch: Partial<FieldMappingValue>) => void;
14
+ onMove: (delta: number) => void;
15
+ onRemove: () => void;
16
+ };
17
+ export declare function FieldMappingRow({ row, index, sourceListId, targetFields, isFirst, isLast, disabled, onPatch, onMove, onRemove, }: FieldMappingRowProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,179 @@
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
+ import { FIELD_MAPPING_GRID, PARENT_PREFIX, TRANSFORM_LABEL, TRANSFORMS, toTransform } from './fieldMappingOptions';
6
+ /**
7
+ * One line of a field mapping: where the value comes from, what it becomes, and
8
+ * which column it lands in.
9
+ *
10
+ * The row owns no state. It reports a patch and the editor above decides what
11
+ * the list of rows now is, so ordering and validation live in one place instead
12
+ * of being spread across however many rows are on screen.
13
+ */ const theme = integrationsPageTheme;
14
+ /** Label above each control on a phone; the header row replaces it from lg up. */ function Cell({ id, label, children }) {
15
+ return /*#__PURE__*/ _jsxs("div", {
16
+ className: theme.field.wrapper,
17
+ children: [
18
+ /*#__PURE__*/ _jsx("label", {
19
+ className: cn(theme.field.label, 'lg:sr-only'),
20
+ htmlFor: id,
21
+ children: label
22
+ }),
23
+ children
24
+ ]
25
+ });
26
+ }
27
+ export function FieldMappingRow({ row, index, sourceListId, targetFields, isFirst, isLast, disabled, onPatch, onMove, onRemove }) {
28
+ const base = `${sourceListId}-${index}`;
29
+ return /*#__PURE__*/ _jsxs("li", {
30
+ className: cn(theme.card.wrapper, 'p-3'),
31
+ children: [
32
+ /*#__PURE__*/ _jsxs("div", {
33
+ className: FIELD_MAPPING_GRID,
34
+ children: [
35
+ /*#__PURE__*/ _jsx(Cell, {
36
+ id: `${base}-source`,
37
+ label: "Source",
38
+ children: /*#__PURE__*/ _jsx("input", {
39
+ className: theme.field.input,
40
+ disabled: disabled,
41
+ id: `${base}-source`,
42
+ list: sourceListId,
43
+ onChange: (event)=>onPatch({
44
+ source: event.target.value
45
+ }),
46
+ placeholder: "employeeNo",
47
+ value: row.source
48
+ })
49
+ }),
50
+ /*#__PURE__*/ _jsx(Cell, {
51
+ id: `${base}-target`,
52
+ label: "Target",
53
+ children: targetFields.length > 0 ? /*#__PURE__*/ _jsxs("select", {
54
+ className: theme.field.input,
55
+ disabled: disabled,
56
+ id: `${base}-target`,
57
+ onChange: (event)=>onPatch({
58
+ target: event.target.value
59
+ }),
60
+ value: row.target,
61
+ children: [
62
+ /*#__PURE__*/ _jsx("option", {
63
+ value: "",
64
+ children: "Not set"
65
+ }),
66
+ targetFields.map((field)=>/*#__PURE__*/ _jsx("option", {
67
+ value: field,
68
+ children: field
69
+ }, field))
70
+ ]
71
+ }) : /*#__PURE__*/ _jsx("input", {
72
+ className: theme.field.input,
73
+ disabled: disabled,
74
+ id: `${base}-target`,
75
+ onChange: (event)=>onPatch({
76
+ target: event.target.value
77
+ }),
78
+ placeholder: "employee_no",
79
+ value: row.target
80
+ })
81
+ }),
82
+ /*#__PURE__*/ _jsx(Cell, {
83
+ id: `${base}-transform`,
84
+ label: "Transform",
85
+ children: /*#__PURE__*/ _jsx("select", {
86
+ className: theme.field.input,
87
+ disabled: disabled,
88
+ id: `${base}-transform`,
89
+ onChange: (event)=>onPatch({
90
+ transform: toTransform(event.target.value)
91
+ }),
92
+ value: row.transform ?? 'none',
93
+ children: TRANSFORMS.map((option)=>/*#__PURE__*/ _jsx("option", {
94
+ value: option,
95
+ children: TRANSFORM_LABEL[option]
96
+ }, option))
97
+ })
98
+ }),
99
+ /*#__PURE__*/ _jsx(Cell, {
100
+ id: `${base}-constant`,
101
+ label: "Constant",
102
+ children: /*#__PURE__*/ _jsx("input", {
103
+ className: theme.field.input,
104
+ disabled: disabled,
105
+ id: `${base}-constant`,
106
+ onChange: (event)=>onPatch({
107
+ constant: event.target.value
108
+ }),
109
+ placeholder: "Same value on every record",
110
+ value: row.constant ?? ''
111
+ })
112
+ }),
113
+ /*#__PURE__*/ _jsx(Cell, {
114
+ id: `${base}-fallback`,
115
+ label: "Fallback",
116
+ children: /*#__PURE__*/ _jsx("input", {
117
+ className: theme.field.input,
118
+ disabled: disabled,
119
+ id: `${base}-fallback`,
120
+ onChange: (event)=>onPatch({
121
+ fallback: event.target.value
122
+ }),
123
+ placeholder: "Used when the source is empty",
124
+ value: row.fallback ?? ''
125
+ })
126
+ }),
127
+ /*#__PURE__*/ _jsxs("div", {
128
+ className: "flex items-end gap-1",
129
+ children: [
130
+ /*#__PURE__*/ _jsx("button", {
131
+ "aria-label": `Move field ${index + 1} earlier`,
132
+ className: theme.button.ghost,
133
+ disabled: disabled || isFirst,
134
+ onClick: ()=>onMove(-1),
135
+ type: "button",
136
+ children: /*#__PURE__*/ _jsx("span", {
137
+ "aria-hidden": "true",
138
+ children: "↑"
139
+ })
140
+ }),
141
+ /*#__PURE__*/ _jsx("button", {
142
+ "aria-label": `Move field ${index + 1} later`,
143
+ className: theme.button.ghost,
144
+ disabled: disabled || isLast,
145
+ onClick: ()=>onMove(1),
146
+ type: "button",
147
+ children: /*#__PURE__*/ _jsx("span", {
148
+ "aria-hidden": "true",
149
+ children: "↓"
150
+ })
151
+ }),
152
+ /*#__PURE__*/ _jsx("button", {
153
+ "aria-label": `Remove field ${index + 1}`,
154
+ className: theme.button.ghost,
155
+ disabled: disabled,
156
+ onClick: onRemove,
157
+ type: "button",
158
+ children: /*#__PURE__*/ _jsx("span", {
159
+ "aria-hidden": "true",
160
+ children: "✕"
161
+ })
162
+ })
163
+ ]
164
+ })
165
+ ]
166
+ }),
167
+ row.source.startsWith(PARENT_PREFIX) ? /*#__PURE__*/ _jsxs("p", {
168
+ className: cn(theme.field.hint, 'mt-2'),
169
+ children: [
170
+ "Reads ",
171
+ /*#__PURE__*/ _jsx("strong", {
172
+ children: row.source.slice(PARENT_PREFIX.length) || 'a field'
173
+ }),
174
+ " from the record the parent endpoint returned — the one this request was built for — not from this response."
175
+ ]
176
+ }) : null
177
+ ]
178
+ });
179
+ }
@@ -0,0 +1,11 @@
1
+ import type { FieldMappingValue } from '../types';
2
+ export type FieldMappingRowsProps = {
3
+ rows: FieldMappingValue[];
4
+ /** Field names the endpoint sample reported. Empty until the endpoint is sampled. */
5
+ sourceFields: string[];
6
+ /** Columns of the chosen target entity. Empty until an entity is chosen. */
7
+ targetFields: string[];
8
+ disabled?: boolean;
9
+ onChange: (rows: FieldMappingValue[]) => void;
10
+ };
11
+ export declare function FieldMappingRows({ rows, sourceFields, targetFields, disabled, onChange, }: FieldMappingRowsProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,115 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import { useId } from 'react';
4
+ import { cn } from '../../../utils/cn';
5
+ import { integrationsPageTheme } from '../theme';
6
+ import { FieldMappingRow } from './FieldMappingRow';
7
+ import { EMPTY_FIELD_MAPPING, FIELD_MAPPING_COLUMNS, FIELD_MAPPING_GRID, PARENT_PREFIX } from './fieldMappingOptions';
8
+ import { Notice } from './Primitives';
9
+ /**
10
+ * The rows that say which incoming value becomes which column.
11
+ *
12
+ * The order is kept because the writer applies the rows in it: two rows aimed at
13
+ * the same column mean the later one wins, and that is only predictable if the
14
+ * operator can see the order and change it.
15
+ */ const theme = integrationsPageTheme;
16
+ export function FieldMappingRows({ rows, sourceFields, targetFields, disabled, onChange }) {
17
+ const uid = useId();
18
+ const listId = `${uid}-source-fields`;
19
+ const patchRow = (index, patch)=>{
20
+ const current = rows[index];
21
+ if (!current) return;
22
+ onChange(rows.with(index, {
23
+ ...current,
24
+ ...patch
25
+ }));
26
+ };
27
+ const moveRow = (index, delta)=>{
28
+ const target = index + delta;
29
+ const moving = rows[index];
30
+ const displaced = rows[target];
31
+ if (!moving || !displaced) return;
32
+ onChange(rows.with(index, displaced).with(target, moving));
33
+ };
34
+ return /*#__PURE__*/ _jsxs("section", {
35
+ className: "flex flex-col gap-3",
36
+ children: [
37
+ /*#__PURE__*/ _jsxs("div", {
38
+ className: "flex flex-wrap items-center justify-between gap-2",
39
+ children: [
40
+ /*#__PURE__*/ _jsx("h3", {
41
+ className: theme.card.title,
42
+ children: "Field mappings"
43
+ }),
44
+ /*#__PURE__*/ _jsx("button", {
45
+ className: theme.button.secondary,
46
+ disabled: disabled,
47
+ onClick: ()=>onChange([
48
+ ...rows,
49
+ EMPTY_FIELD_MAPPING
50
+ ]),
51
+ type: "button",
52
+ children: "Add field"
53
+ })
54
+ ]
55
+ }),
56
+ sourceFields.length === 0 ? /*#__PURE__*/ _jsx(Notice, {
57
+ title: "Sample the endpoint first",
58
+ tone: "warning",
59
+ children: "No field names are known yet. Sampling the selected endpoint lists what the response really returns; until then a source has to be typed from memory, and a typo shows up only as an empty column once the import has already run."
60
+ }) : null,
61
+ /*#__PURE__*/ _jsx("datalist", {
62
+ id: listId,
63
+ children: sourceFields.map((field)=>/*#__PURE__*/ _jsx("option", {
64
+ value: field
65
+ }, field))
66
+ }),
67
+ rows.length === 0 ? /*#__PURE__*/ _jsx("p", {
68
+ className: theme.list.empty,
69
+ children: "Nothing is mapped yet, so a run would write empty records. Add a field to begin."
70
+ }) : /*#__PURE__*/ _jsxs(_Fragment, {
71
+ children: [
72
+ /*#__PURE__*/ _jsxs("div", {
73
+ "aria-hidden": "true",
74
+ className: cn(FIELD_MAPPING_GRID, 'hidden px-3 lg:grid'),
75
+ children: [
76
+ FIELD_MAPPING_COLUMNS.map((column)=>/*#__PURE__*/ _jsx("span", {
77
+ className: theme.field.label,
78
+ children: column
79
+ }, column)),
80
+ /*#__PURE__*/ _jsx("span", {
81
+ className: cn(theme.field.label, 'w-28'),
82
+ children: "Order"
83
+ })
84
+ ]
85
+ }),
86
+ /*#__PURE__*/ _jsx("ol", {
87
+ className: "flex flex-col gap-2",
88
+ children: rows.map((row, index)=>/*#__PURE__*/ _jsx(FieldMappingRow, {
89
+ disabled: disabled,
90
+ index: index,
91
+ isFirst: index === 0,
92
+ isLast: index === rows.length - 1,
93
+ onMove: (delta)=>moveRow(index, delta),
94
+ onPatch: (patch)=>patchRow(index, patch),
95
+ onRemove: ()=>onChange(rows.toSpliced(index, 1)),
96
+ row: row,
97
+ sourceListId: listId,
98
+ targetFields: targetFields
99
+ }, `field-mapping-${index}`))
100
+ }),
101
+ /*#__PURE__*/ _jsxs("p", {
102
+ className: theme.field.hint,
103
+ children: [
104
+ "Prefix a source with ",
105
+ /*#__PURE__*/ _jsx("strong", {
106
+ children: PARENT_PREFIX
107
+ }),
108
+ " to take the value from the parent endpoint's record instead of this one."
109
+ ]
110
+ })
111
+ ]
112
+ })
113
+ ]
114
+ });
115
+ }
@@ -0,0 +1,2 @@
1
+ import type { IntegrationsPageProps } from '../types';
2
+ export declare function IntegrationsPage({ title, subtitle, className, actions, onSubscribeProgress, }: IntegrationsPageProps): import("react/jsx-runtime").JSX.Element;