nucleus-core-ts 0.9.805 → 0.9.807
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.
- package/dist/fe/components/IntegrationsPage/components/ConnectionAuthFields.js +10 -8
- package/dist/fe/components/IntegrationsPage/components/ConnectionOauthFields.js +15 -13
- package/dist/fe/components/IntegrationsPage/components/ConnectionTest.js +7 -5
- package/dist/fe/components/IntegrationsPage/components/CredentialFields.js +7 -5
- package/dist/fe/components/IntegrationsPage/components/EndpointForm.js +6 -4
- package/dist/fe/components/IntegrationsPage/components/EndpointFormFields.js +32 -23
- package/dist/fe/components/IntegrationsPage/components/EndpointList.js +3 -3
- package/dist/fe/components/IntegrationsPage/components/EndpointsTab.js +38 -32
- package/dist/fe/components/IntegrationsPage/components/FieldMappingRow.js +11 -9
- package/dist/fe/components/IntegrationsPage/components/FieldMappingRows.js +4 -2
- package/dist/fe/components/IntegrationsPage/components/MappingEditor.js +14 -12
- package/dist/fe/components/IntegrationsPage/components/MappingList.js +6 -4
- package/dist/fe/components/IntegrationsPage/components/MappingWriteModeFields.js +14 -12
- package/dist/fe/components/IntegrationsPage/components/MappingsTab.js +15 -19
- package/dist/fe/components/IntegrationsPage/text/index.d.ts +113 -0
- package/dist/fe/components/IntegrationsPage/text/index.js +110 -0
- package/package.json +1 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useLabels } from '../text/context';
|
|
3
4
|
import { integrationsPageTheme } from '../theme';
|
|
4
5
|
import { AUTH_TYPE_OPTIONS, authTypeHint, toAuthType } from './authOptions';
|
|
5
6
|
import { ConnectionOauthFields } from './ConnectionOauthFields';
|
|
@@ -16,15 +17,16 @@ import { Field } from './Primitives';
|
|
|
16
17
|
* because they are written and never read back.
|
|
17
18
|
*/ const theme = integrationsPageTheme;
|
|
18
19
|
export function ConnectionAuthFields(props) {
|
|
20
|
+
const labels = useLabels();
|
|
19
21
|
const { draft, disabled, onChange } = props;
|
|
20
22
|
return /*#__PURE__*/ _jsxs("section", {
|
|
21
|
-
"aria-label":
|
|
23
|
+
"aria-label": labels.auth.sectionLabel,
|
|
22
24
|
className: "flex flex-col gap-3",
|
|
23
25
|
children: [
|
|
24
26
|
/*#__PURE__*/ _jsx(Field, {
|
|
25
27
|
hint: authTypeHint(draft.authType),
|
|
26
28
|
htmlFor: "connection-auth-type",
|
|
27
|
-
label:
|
|
29
|
+
label: labels.auth.type,
|
|
28
30
|
children: /*#__PURE__*/ _jsx("select", {
|
|
29
31
|
"aria-describedby": describedBy('connection-auth-type', true, false),
|
|
30
32
|
className: theme.field.input,
|
|
@@ -44,9 +46,9 @@ export function ConnectionAuthFields(props) {
|
|
|
44
46
|
})
|
|
45
47
|
}),
|
|
46
48
|
usesHeaderName(draft.authType) ? /*#__PURE__*/ _jsx(Field, {
|
|
47
|
-
hint:
|
|
49
|
+
hint: labels.auth.headerNameHint,
|
|
48
50
|
htmlFor: "connection-auth-header",
|
|
49
|
-
label:
|
|
51
|
+
label: labels.auth.headerName,
|
|
50
52
|
children: /*#__PURE__*/ _jsx("input", {
|
|
51
53
|
"aria-describedby": describedBy('connection-auth-header', true, false),
|
|
52
54
|
className: theme.field.input,
|
|
@@ -55,15 +57,15 @@ export function ConnectionAuthFields(props) {
|
|
|
55
57
|
onChange: (event)=>onChange({
|
|
56
58
|
authHeaderName: event.target.value
|
|
57
59
|
}),
|
|
58
|
-
placeholder:
|
|
60
|
+
placeholder: labels.auth.headerNamePlaceholder,
|
|
59
61
|
type: "text",
|
|
60
62
|
value: draft.authHeaderName
|
|
61
63
|
})
|
|
62
64
|
}) : null,
|
|
63
65
|
usesQueryParam(draft.authType) ? /*#__PURE__*/ _jsx(Field, {
|
|
64
|
-
hint:
|
|
66
|
+
hint: labels.auth.queryParamHint,
|
|
65
67
|
htmlFor: "connection-auth-query",
|
|
66
|
-
label:
|
|
68
|
+
label: labels.auth.queryParam,
|
|
67
69
|
children: /*#__PURE__*/ _jsx("input", {
|
|
68
70
|
"aria-describedby": describedBy('connection-auth-query', true, false),
|
|
69
71
|
className: theme.field.input,
|
|
@@ -72,7 +74,7 @@ export function ConnectionAuthFields(props) {
|
|
|
72
74
|
onChange: (event)=>onChange({
|
|
73
75
|
authQueryParam: event.target.value
|
|
74
76
|
}),
|
|
75
|
-
placeholder:
|
|
77
|
+
placeholder: labels.auth.queryParamPlaceholder,
|
|
76
78
|
type: "text",
|
|
77
79
|
value: draft.authQueryParam
|
|
78
80
|
})
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import { useLabels } from '../text/context';
|
|
3
4
|
import { integrationsPageTheme } from '../theme';
|
|
4
5
|
import { CLIENT_AUTH_OPTIONS, GRANT_TYPE_OPTIONS, toClientAuth, toGrantType } from './authOptions';
|
|
5
6
|
import { usesOauth } from './connectionDraft';
|
|
@@ -13,14 +14,15 @@ import { Field } from './Primitives';
|
|
|
13
14
|
* place instead of at every field.
|
|
14
15
|
*/ const theme = integrationsPageTheme;
|
|
15
16
|
export function ConnectionOauthFields({ draft, errors, disabled, onChange }) {
|
|
17
|
+
const labels = useLabels();
|
|
16
18
|
if (!usesOauth(draft.authType)) return null;
|
|
17
19
|
return /*#__PURE__*/ _jsxs(_Fragment, {
|
|
18
20
|
children: [
|
|
19
21
|
/*#__PURE__*/ _jsx(Field, {
|
|
20
22
|
error: errors.tokenUrl,
|
|
21
|
-
hint:
|
|
23
|
+
hint: labels.auth.tokenUrlHint,
|
|
22
24
|
htmlFor: "connection-token-url",
|
|
23
|
-
label:
|
|
25
|
+
label: labels.auth.tokenUrl,
|
|
24
26
|
children: /*#__PURE__*/ _jsx("input", {
|
|
25
27
|
"aria-describedby": describedBy('connection-token-url', true, Boolean(errors.tokenUrl)),
|
|
26
28
|
className: theme.field.input,
|
|
@@ -29,15 +31,15 @@ export function ConnectionOauthFields({ draft, errors, disabled, onChange }) {
|
|
|
29
31
|
onChange: (event)=>onChange({
|
|
30
32
|
tokenUrl: event.target.value
|
|
31
33
|
}),
|
|
32
|
-
placeholder:
|
|
34
|
+
placeholder: labels.auth.tokenUrlPlaceholder,
|
|
33
35
|
type: "text",
|
|
34
36
|
value: draft.tokenUrl
|
|
35
37
|
})
|
|
36
38
|
}),
|
|
37
39
|
/*#__PURE__*/ _jsx(Field, {
|
|
38
|
-
hint:
|
|
40
|
+
hint: labels.auth.grantTypeHint,
|
|
39
41
|
htmlFor: "connection-grant-type",
|
|
40
|
-
label:
|
|
42
|
+
label: labels.auth.grantType,
|
|
41
43
|
children: /*#__PURE__*/ _jsx("select", {
|
|
42
44
|
"aria-describedby": describedBy('connection-grant-type', true, false),
|
|
43
45
|
className: theme.field.input,
|
|
@@ -58,7 +60,7 @@ export function ConnectionOauthFields({ draft, errors, disabled, onChange }) {
|
|
|
58
60
|
}),
|
|
59
61
|
/*#__PURE__*/ _jsx(Field, {
|
|
60
62
|
htmlFor: "connection-client-id",
|
|
61
|
-
label:
|
|
63
|
+
label: labels.auth.clientId,
|
|
62
64
|
children: /*#__PURE__*/ _jsx("input", {
|
|
63
65
|
className: theme.field.input,
|
|
64
66
|
disabled: disabled,
|
|
@@ -66,14 +68,14 @@ export function ConnectionOauthFields({ draft, errors, disabled, onChange }) {
|
|
|
66
68
|
onChange: (event)=>onChange({
|
|
67
69
|
oauthClientId: event.target.value
|
|
68
70
|
}),
|
|
69
|
-
placeholder:
|
|
71
|
+
placeholder: labels.auth.clientIdPlaceholder,
|
|
70
72
|
type: "text",
|
|
71
73
|
value: draft.oauthClientId
|
|
72
74
|
})
|
|
73
75
|
}),
|
|
74
76
|
draft.oauthGrantType === 'password' ? /*#__PURE__*/ _jsx(Field, {
|
|
75
77
|
htmlFor: "connection-oauth-username",
|
|
76
|
-
label:
|
|
78
|
+
label: labels.auth.username,
|
|
77
79
|
children: /*#__PURE__*/ _jsx("input", {
|
|
78
80
|
autoComplete: "off",
|
|
79
81
|
className: theme.field.input,
|
|
@@ -82,15 +84,15 @@ export function ConnectionOauthFields({ draft, errors, disabled, onChange }) {
|
|
|
82
84
|
onChange: (event)=>onChange({
|
|
83
85
|
oauthUsername: event.target.value
|
|
84
86
|
}),
|
|
85
|
-
placeholder:
|
|
87
|
+
placeholder: labels.auth.usernamePlaceholder,
|
|
86
88
|
type: "text",
|
|
87
89
|
value: draft.oauthUsername
|
|
88
90
|
})
|
|
89
91
|
}) : null,
|
|
90
92
|
/*#__PURE__*/ _jsx(Field, {
|
|
91
|
-
hint:
|
|
93
|
+
hint: labels.auth.scopeHint,
|
|
92
94
|
htmlFor: "connection-scope",
|
|
93
|
-
label:
|
|
95
|
+
label: labels.auth.scope,
|
|
94
96
|
children: /*#__PURE__*/ _jsx("input", {
|
|
95
97
|
"aria-describedby": describedBy('connection-scope', true, false),
|
|
96
98
|
className: theme.field.input,
|
|
@@ -99,7 +101,7 @@ export function ConnectionOauthFields({ draft, errors, disabled, onChange }) {
|
|
|
99
101
|
onChange: (event)=>onChange({
|
|
100
102
|
oauthScope: event.target.value
|
|
101
103
|
}),
|
|
102
|
-
placeholder:
|
|
104
|
+
placeholder: labels.auth.scopePlaceholder,
|
|
103
105
|
type: "text",
|
|
104
106
|
value: draft.oauthScope
|
|
105
107
|
})
|
|
@@ -107,7 +109,7 @@ export function ConnectionOauthFields({ draft, errors, disabled, onChange }) {
|
|
|
107
109
|
/*#__PURE__*/ _jsx(Field, {
|
|
108
110
|
hint: "Where the client ID and secret go on the token request. A server accepts one or the other; if the token call comes back with an invalid-client error, try the other.",
|
|
109
111
|
htmlFor: "connection-client-auth",
|
|
110
|
-
label:
|
|
112
|
+
label: labels.auth.clientAuth,
|
|
111
113
|
children: /*#__PURE__*/ _jsx("select", {
|
|
112
114
|
"aria-describedby": describedBy('connection-client-auth', true, false),
|
|
113
115
|
className: theme.field.input,
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useEffect, useEffectEvent, useState } from 'react';
|
|
4
4
|
import { cn } from '../../../utils/cn';
|
|
5
|
+
import { useLabels } from '../text/context';
|
|
5
6
|
import { integrationsPageTheme } from '../theme';
|
|
6
7
|
import { errorText } from './formSupport';
|
|
7
8
|
import { Badge, Notice } from './Primitives';
|
|
@@ -15,6 +16,7 @@ import { CardSkeleton } from './Skeletons';
|
|
|
15
16
|
* sends the operator back to guessing.
|
|
16
17
|
*/ const theme = integrationsPageTheme;
|
|
17
18
|
export function ConnectionTest({ actions, source, loading = false }) {
|
|
19
|
+
const labels = useLabels();
|
|
18
20
|
const [testing, setTesting] = useState(false);
|
|
19
21
|
const [result, setResult] = useState(null);
|
|
20
22
|
// A result describes the connection it was run against. Leaving it up under
|
|
@@ -45,7 +47,7 @@ export function ConnectionTest({ actions, source, loading = false }) {
|
|
|
45
47
|
};
|
|
46
48
|
if (loading) return /*#__PURE__*/ _jsx(CardSkeleton, {});
|
|
47
49
|
return /*#__PURE__*/ _jsxs("section", {
|
|
48
|
-
"aria-label":
|
|
50
|
+
"aria-label": labels.auth.testHeading,
|
|
49
51
|
className: theme.card.wrapper,
|
|
50
52
|
children: [
|
|
51
53
|
/*#__PURE__*/ _jsxs("div", {
|
|
@@ -53,7 +55,7 @@ export function ConnectionTest({ actions, source, loading = false }) {
|
|
|
53
55
|
children: [
|
|
54
56
|
/*#__PURE__*/ _jsx("h2", {
|
|
55
57
|
className: theme.card.title,
|
|
56
|
-
children:
|
|
58
|
+
children: labels.auth.testHeading
|
|
57
59
|
}),
|
|
58
60
|
result ? /*#__PURE__*/ _jsx(Badge, {
|
|
59
61
|
tone: result.ok ? 'success' : 'danger',
|
|
@@ -76,13 +78,13 @@ export function ConnectionTest({ actions, source, loading = false }) {
|
|
|
76
78
|
children: "Save the connection first — there is nothing to call yet."
|
|
77
79
|
}),
|
|
78
80
|
result?.ok ? /*#__PURE__*/ _jsxs(Notice, {
|
|
79
|
-
title:
|
|
81
|
+
title: labels.auth.testOkTitle,
|
|
80
82
|
tone: "info",
|
|
81
83
|
children: [
|
|
82
84
|
/*#__PURE__*/ _jsx("p", {
|
|
83
85
|
children: /*#__PURE__*/ _jsx(Badge, {
|
|
84
86
|
tone: "success",
|
|
85
|
-
children:
|
|
87
|
+
children: labels.auth.testOkBadge
|
|
86
88
|
})
|
|
87
89
|
}),
|
|
88
90
|
result.detail ? /*#__PURE__*/ _jsx("p", {
|
|
@@ -92,7 +94,7 @@ export function ConnectionTest({ actions, source, loading = false }) {
|
|
|
92
94
|
]
|
|
93
95
|
}) : null,
|
|
94
96
|
result && !result.ok ? /*#__PURE__*/ _jsx(Notice, {
|
|
95
|
-
title:
|
|
97
|
+
title: labels.auth.testFailedTitle,
|
|
96
98
|
tone: "danger",
|
|
97
99
|
children: /*#__PURE__*/ _jsx("p", {
|
|
98
100
|
className: cn(theme.notice.body, 'whitespace-pre-wrap break-words font-mono'),
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useEffect, useEffectEvent, useState } from 'react';
|
|
4
4
|
import { useIntegrationsStore } from '../store';
|
|
5
|
+
import { useLabels } from '../text/context';
|
|
5
6
|
import { integrationsPageTheme } from '../theme';
|
|
6
7
|
import { CredentialSlotRow } from './CredentialSlotRow';
|
|
7
8
|
import { hintFromResult, patchFor, slotsForSource, storedHint } from './credentialSlots';
|
|
@@ -18,6 +19,7 @@ import { CardSkeleton } from './Skeletons';
|
|
|
18
19
|
* button per field.
|
|
19
20
|
*/ const theme = integrationsPageTheme;
|
|
20
21
|
export function CredentialFields({ actions, source, loading = false }) {
|
|
22
|
+
const labels = useLabels();
|
|
21
23
|
const store = useIntegrationsStore();
|
|
22
24
|
const [values, setValues] = useState({});
|
|
23
25
|
const [hints, setHints] = useState({});
|
|
@@ -39,10 +41,10 @@ export function CredentialFields({ actions, source, loading = false }) {
|
|
|
39
41
|
if (loading) return /*#__PURE__*/ _jsx(CardSkeleton, {});
|
|
40
42
|
if (!source) {
|
|
41
43
|
return /*#__PURE__*/ _jsx(Notice, {
|
|
42
|
-
title:
|
|
44
|
+
title: labels.auth.saveFirstTitle,
|
|
43
45
|
tone: "info",
|
|
44
46
|
children: /*#__PURE__*/ _jsx("p", {
|
|
45
|
-
children:
|
|
47
|
+
children: labels.auth.saveFirstBody
|
|
46
48
|
})
|
|
47
49
|
});
|
|
48
50
|
}
|
|
@@ -114,21 +116,21 @@ export function CredentialFields({ actions, source, loading = false }) {
|
|
|
114
116
|
});
|
|
115
117
|
};
|
|
116
118
|
return /*#__PURE__*/ _jsxs("section", {
|
|
117
|
-
"aria-label":
|
|
119
|
+
"aria-label": labels.auth.credentialsHeading,
|
|
118
120
|
className: theme.card.wrapper,
|
|
119
121
|
children: [
|
|
120
122
|
/*#__PURE__*/ _jsx("div", {
|
|
121
123
|
className: theme.card.header,
|
|
122
124
|
children: /*#__PURE__*/ _jsx("h2", {
|
|
123
125
|
className: theme.card.title,
|
|
124
|
-
children:
|
|
126
|
+
children: labels.auth.credentialsHeading
|
|
125
127
|
})
|
|
126
128
|
}),
|
|
127
129
|
/*#__PURE__*/ _jsxs("div", {
|
|
128
130
|
className: theme.card.body,
|
|
129
131
|
children: [
|
|
130
132
|
/*#__PURE__*/ _jsx(Notice, {
|
|
131
|
-
title:
|
|
133
|
+
title: labels.auth.writeOnlyTitle,
|
|
132
134
|
tone: "info",
|
|
133
135
|
children: /*#__PURE__*/ _jsx("p", {
|
|
134
136
|
children: "A value typed here is stored and from then on only ever sent to the service. It is not returned to this screen, or to any other, no matter who asks — all that comes back is a masked hint. Leave a box empty to keep whatever is already stored."
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useEffect, useEffectEvent, useState } from 'react';
|
|
4
4
|
import { useIntegrationsStore } from '../store';
|
|
5
|
+
import { useLabels } from '../text/context';
|
|
5
6
|
import { integrationsPageTheme } from '../theme';
|
|
6
7
|
import { EndpointFormFields } from './EndpointFormFields';
|
|
7
8
|
import { formatJsonObject, parseJsonObject } from './jsonObjectField';
|
|
@@ -17,6 +18,7 @@ import { pathParamNames } from './pathParams';
|
|
|
17
18
|
* a list page arriving in the background.
|
|
18
19
|
*/ const theme = integrationsPageTheme;
|
|
19
20
|
export function EndpointForm({ sourceId, endpoint, actions, onSaved, onDeleted, onCancel }) {
|
|
21
|
+
const labels = useLabels();
|
|
20
22
|
const store = useIntegrationsStore();
|
|
21
23
|
const [saving, setSaving] = useState(false);
|
|
22
24
|
const [deleting, setDeleting] = useState(false);
|
|
@@ -123,7 +125,7 @@ export function EndpointForm({ sourceId, endpoint, actions, onSaved, onDeleted,
|
|
|
123
125
|
className: theme.card.header,
|
|
124
126
|
children: /*#__PURE__*/ _jsx("h3", {
|
|
125
127
|
className: theme.card.title,
|
|
126
|
-
children: endpoint ?
|
|
128
|
+
children: endpoint ? labels.endpoints.editTitle : labels.endpoints.newTitle
|
|
127
129
|
})
|
|
128
130
|
}),
|
|
129
131
|
/*#__PURE__*/ _jsxs("div", {
|
|
@@ -163,20 +165,20 @@ export function EndpointForm({ sourceId, endpoint, actions, onSaved, onDeleted,
|
|
|
163
165
|
disabled: busy,
|
|
164
166
|
onClick: remove,
|
|
165
167
|
type: "button",
|
|
166
|
-
children: deleting ?
|
|
168
|
+
children: deleting ? labels.common.deleting : labels.common.delete
|
|
167
169
|
}) : null,
|
|
168
170
|
/*#__PURE__*/ _jsx("button", {
|
|
169
171
|
className: theme.button.secondary,
|
|
170
172
|
disabled: busy,
|
|
171
173
|
onClick: onCancel,
|
|
172
174
|
type: "button",
|
|
173
|
-
children:
|
|
175
|
+
children: labels.common.cancel
|
|
174
176
|
}),
|
|
175
177
|
/*#__PURE__*/ _jsx("button", {
|
|
176
178
|
className: theme.button.primary,
|
|
177
179
|
disabled: busy || !canSave,
|
|
178
180
|
type: "submit",
|
|
179
|
-
children: saving ?
|
|
181
|
+
children: saving ? labels.common.saving : labels.endpoints.save
|
|
180
182
|
})
|
|
181
183
|
]
|
|
182
184
|
})
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import { useId } from 'react';
|
|
3
4
|
import { cn } from '../../../utils/cn';
|
|
4
5
|
import { useLabels } from '../text/context';
|
|
5
6
|
import { integrationsPageTheme } from '../theme';
|
|
@@ -20,6 +21,14 @@ const METHODS = [
|
|
|
20
21
|
];
|
|
21
22
|
export function EndpointFormFields({ draft, disabled, errors, onChange }) {
|
|
22
23
|
const labels = useLabels();
|
|
24
|
+
/**
|
|
25
|
+
* Unique per instance.
|
|
26
|
+
*
|
|
27
|
+
* These ids were literals — `endpoint-tag`, `endpoint-name` — which is fine
|
|
28
|
+
* for one form on a page and wrong the moment there are two: every `<label
|
|
29
|
+
* htmlFor>` binds to whichever rendered first, so clicking a label focuses the
|
|
30
|
+
* OTHER record's field. `useId` makes that structurally impossible.
|
|
31
|
+
*/ const uid = useId();
|
|
23
32
|
return /*#__PURE__*/ _jsxs(_Fragment, {
|
|
24
33
|
children: [
|
|
25
34
|
/*#__PURE__*/ _jsxs("div", {
|
|
@@ -27,13 +36,13 @@ export function EndpointFormFields({ draft, disabled, errors, onChange }) {
|
|
|
27
36
|
children: [
|
|
28
37
|
/*#__PURE__*/ _jsx(Field, {
|
|
29
38
|
hint: labels.endpoints.tagHint,
|
|
30
|
-
htmlFor:
|
|
39
|
+
htmlFor: `${uid}-tag`,
|
|
31
40
|
label: labels.endpoints.tag,
|
|
32
41
|
children: /*#__PURE__*/ _jsx("input", {
|
|
33
|
-
"aria-describedby":
|
|
42
|
+
"aria-describedby": `${uid}-tag-hint`,
|
|
34
43
|
className: theme.field.input,
|
|
35
44
|
disabled: disabled,
|
|
36
|
-
id:
|
|
45
|
+
id: `${uid}-tag`,
|
|
37
46
|
onChange: (event)=>onChange({
|
|
38
47
|
tag: event.target.value
|
|
39
48
|
}),
|
|
@@ -43,12 +52,12 @@ export function EndpointFormFields({ draft, disabled, errors, onChange }) {
|
|
|
43
52
|
})
|
|
44
53
|
}),
|
|
45
54
|
/*#__PURE__*/ _jsx(Field, {
|
|
46
|
-
htmlFor:
|
|
55
|
+
htmlFor: `${uid}-name`,
|
|
47
56
|
label: labels.endpoints.name,
|
|
48
57
|
children: /*#__PURE__*/ _jsx("input", {
|
|
49
58
|
className: theme.field.input,
|
|
50
59
|
disabled: disabled,
|
|
51
|
-
id:
|
|
60
|
+
id: `${uid}-name`,
|
|
52
61
|
onChange: (event)=>onChange({
|
|
53
62
|
name: event.target.value
|
|
54
63
|
}),
|
|
@@ -65,12 +74,12 @@ export function EndpointFormFields({ draft, disabled, errors, onChange }) {
|
|
|
65
74
|
/*#__PURE__*/ _jsx("div", {
|
|
66
75
|
className: "sm:w-32",
|
|
67
76
|
children: /*#__PURE__*/ _jsx(Field, {
|
|
68
|
-
htmlFor:
|
|
77
|
+
htmlFor: `${uid}-method`,
|
|
69
78
|
label: labels.endpoints.method,
|
|
70
79
|
children: /*#__PURE__*/ _jsx("select", {
|
|
71
80
|
className: theme.field.input,
|
|
72
81
|
disabled: disabled,
|
|
73
|
-
id:
|
|
82
|
+
id: `${uid}-method`,
|
|
74
83
|
onChange: (event)=>{
|
|
75
84
|
for (const method of METHODS){
|
|
76
85
|
if (method === event.target.value) onChange({
|
|
@@ -90,13 +99,13 @@ export function EndpointFormFields({ draft, disabled, errors, onChange }) {
|
|
|
90
99
|
className: "min-w-0 flex-1",
|
|
91
100
|
children: /*#__PURE__*/ _jsx(Field, {
|
|
92
101
|
hint: labels.endpoints.pathHint,
|
|
93
|
-
htmlFor:
|
|
102
|
+
htmlFor: `${uid}-path`,
|
|
94
103
|
label: labels.endpoints.path,
|
|
95
104
|
children: /*#__PURE__*/ _jsx("input", {
|
|
96
|
-
"aria-describedby":
|
|
105
|
+
"aria-describedby": `${uid}-path-hint`,
|
|
97
106
|
className: theme.field.input,
|
|
98
107
|
disabled: disabled,
|
|
99
|
-
id:
|
|
108
|
+
id: `${uid}-path`,
|
|
100
109
|
onChange: (event)=>onChange({
|
|
101
110
|
path: event.target.value
|
|
102
111
|
}),
|
|
@@ -110,13 +119,13 @@ export function EndpointFormFields({ draft, disabled, errors, onChange }) {
|
|
|
110
119
|
}),
|
|
111
120
|
/*#__PURE__*/ _jsx(Field, {
|
|
112
121
|
hint: labels.endpoints.rootPathHint,
|
|
113
|
-
htmlFor:
|
|
122
|
+
htmlFor: `${uid}-root`,
|
|
114
123
|
label: labels.endpoints.rootPath,
|
|
115
124
|
children: /*#__PURE__*/ _jsx("input", {
|
|
116
|
-
"aria-describedby":
|
|
125
|
+
"aria-describedby": `${uid}-root-hint`,
|
|
117
126
|
className: theme.field.input,
|
|
118
127
|
disabled: disabled,
|
|
119
|
-
id:
|
|
128
|
+
id: `${uid}-root`,
|
|
120
129
|
onChange: (event)=>onChange({
|
|
121
130
|
responseRootPath: event.target.value
|
|
122
131
|
}),
|
|
@@ -128,13 +137,13 @@ export function EndpointFormFields({ draft, disabled, errors, onChange }) {
|
|
|
128
137
|
/*#__PURE__*/ _jsx(Field, {
|
|
129
138
|
error: errors?.queryParams,
|
|
130
139
|
hint: labels.endpoints.queryParamsHint,
|
|
131
|
-
htmlFor:
|
|
140
|
+
htmlFor: `${uid}-query`,
|
|
132
141
|
label: labels.endpoints.queryParams,
|
|
133
142
|
children: /*#__PURE__*/ _jsx("textarea", {
|
|
134
|
-
"aria-describedby": describedBy(
|
|
143
|
+
"aria-describedby": describedBy(`${uid}-query`, true, Boolean(errors?.queryParams)),
|
|
135
144
|
className: cn(theme.field.input, 'h-auto min-h-16 py-2 font-mono text-xs'),
|
|
136
145
|
disabled: disabled,
|
|
137
|
-
id:
|
|
146
|
+
id: `${uid}-query`,
|
|
138
147
|
onChange: (event)=>onChange({
|
|
139
148
|
queryParams: event.target.value
|
|
140
149
|
}),
|
|
@@ -146,13 +155,13 @@ export function EndpointFormFields({ draft, disabled, errors, onChange }) {
|
|
|
146
155
|
draft.method === 'GET' ? null : /*#__PURE__*/ _jsx(Field, {
|
|
147
156
|
error: errors?.requestBody,
|
|
148
157
|
hint: labels.endpoints.requestBodyHint,
|
|
149
|
-
htmlFor:
|
|
158
|
+
htmlFor: `${uid}-body`,
|
|
150
159
|
label: labels.endpoints.requestBody,
|
|
151
160
|
children: /*#__PURE__*/ _jsx("textarea", {
|
|
152
|
-
"aria-describedby": describedBy(
|
|
161
|
+
"aria-describedby": describedBy(`${uid}-body`, true, Boolean(errors?.requestBody)),
|
|
153
162
|
className: cn(theme.field.input, 'h-auto min-h-20 py-2 font-mono text-xs'),
|
|
154
163
|
disabled: disabled,
|
|
155
|
-
id:
|
|
164
|
+
id: `${uid}-body`,
|
|
156
165
|
onChange: (event)=>onChange({
|
|
157
166
|
requestBody: event.target.value
|
|
158
167
|
}),
|
|
@@ -162,12 +171,12 @@ export function EndpointFormFields({ draft, disabled, errors, onChange }) {
|
|
|
162
171
|
})
|
|
163
172
|
}),
|
|
164
173
|
/*#__PURE__*/ _jsx(Field, {
|
|
165
|
-
htmlFor:
|
|
174
|
+
htmlFor: `${uid}-description`,
|
|
166
175
|
label: labels.endpoints.description,
|
|
167
176
|
children: /*#__PURE__*/ _jsx("textarea", {
|
|
168
177
|
className: cn(theme.field.input, 'h-auto min-h-20 py-2'),
|
|
169
178
|
disabled: disabled,
|
|
170
|
-
id:
|
|
179
|
+
id: `${uid}-description`,
|
|
171
180
|
onChange: (event)=>onChange({
|
|
172
181
|
description: event.target.value
|
|
173
182
|
}),
|
|
@@ -178,13 +187,13 @@ export function EndpointFormFields({ draft, disabled, errors, onChange }) {
|
|
|
178
187
|
}),
|
|
179
188
|
/*#__PURE__*/ _jsxs("label", {
|
|
180
189
|
className: "flex items-center gap-2",
|
|
181
|
-
htmlFor:
|
|
190
|
+
htmlFor: `${uid}-enabled`,
|
|
182
191
|
children: [
|
|
183
192
|
/*#__PURE__*/ _jsx("input", {
|
|
184
193
|
checked: draft.enabled,
|
|
185
194
|
className: "size-4 shrink-0 accent-sky-600 dark:accent-sky-500",
|
|
186
195
|
disabled: disabled,
|
|
187
|
-
id:
|
|
196
|
+
id: `${uid}-enabled`,
|
|
188
197
|
onChange: (event)=>onChange({
|
|
189
198
|
enabled: event.target.checked
|
|
190
199
|
}),
|
|
@@ -107,7 +107,7 @@ export function EndpointList({ sourceId, actions, onNewEndpoint, onSelect, reloa
|
|
|
107
107
|
}),
|
|
108
108
|
/*#__PURE__*/ _jsx("p", {
|
|
109
109
|
className: theme.header.subtitle,
|
|
110
|
-
children: list.total === 1 ?
|
|
110
|
+
children: list.total === 1 ? labels.endpoints.countOne : labels.endpoints.countMany(list.total)
|
|
111
111
|
})
|
|
112
112
|
]
|
|
113
113
|
}),
|
|
@@ -117,7 +117,7 @@ export function EndpointList({ sourceId, actions, onNewEndpoint, onSelect, reloa
|
|
|
117
117
|
className: theme.button.primary,
|
|
118
118
|
onClick: handleNew,
|
|
119
119
|
type: "button",
|
|
120
|
-
children:
|
|
120
|
+
children: labels.endpoints.create
|
|
121
121
|
})
|
|
122
122
|
})
|
|
123
123
|
]
|
|
@@ -153,7 +153,7 @@ export function EndpointList({ sourceId, actions, onNewEndpoint, onSelect, reloa
|
|
|
153
153
|
}) : null,
|
|
154
154
|
!firstLoad && list.items.length === 0 && !list.error ? /*#__PURE__*/ _jsx("p", {
|
|
155
155
|
className: theme.list.empty,
|
|
156
|
-
children: search.length > 0 ?
|
|
156
|
+
children: search.length > 0 ? labels.endpoints.emptySearch(search) : labels.endpoints.empty
|
|
157
157
|
}) : null,
|
|
158
158
|
list.items.length > 0 ? /*#__PURE__*/ _jsx("ul", {
|
|
159
159
|
className: theme.list.wrapper,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
3
|
import { useEffect, useEffectEvent, useState } from 'react';
|
|
4
4
|
import { useIntegrationsStore } from '../store';
|
|
5
5
|
import { useLabels } from '../text/context';
|
|
@@ -18,14 +18,24 @@ export function EndpointsTab({ actions }) {
|
|
|
18
18
|
const labels = useLabels();
|
|
19
19
|
const store = useIntegrationsStore();
|
|
20
20
|
const sourceId = store.selectedSourceId;
|
|
21
|
-
const [selected, setSelected] = useState(null);
|
|
22
21
|
const [creating, setCreating] = useState(false);
|
|
23
22
|
const [reloadToken, setReloadToken] = useState(0);
|
|
24
|
-
|
|
23
|
+
/**
|
|
24
|
+
* The selection is the STORE's, and only the store's.
|
|
25
|
+
*
|
|
26
|
+
* It used to be kept here as well, and the two were reconciled by comparing
|
|
27
|
+
* them on every render. Clicking a second call then left the first form on
|
|
28
|
+
* screen and added the new one under it — two live editors of two different
|
|
29
|
+
* records, both writing to the same hard-coded field ids, growing by one card
|
|
30
|
+
* per click. One source of truth, and one keyed container below, is what makes
|
|
31
|
+
* that impossible rather than unlikely.
|
|
32
|
+
*/ const selectedId = store.selectedEndpointId;
|
|
33
|
+
const editing = selectedId ? store.endpoints.find((e)=>e.id === selectedId) ?? null : null;
|
|
34
|
+
// Another connection is another set of calls. A form left open across the
|
|
25
35
|
// change would be editing a record this connection does not own.
|
|
26
36
|
const reset = useEffectEvent(()=>{
|
|
27
|
-
setSelected(null);
|
|
28
37
|
setCreating(false);
|
|
38
|
+
store.selectEndpoint(null);
|
|
29
39
|
});
|
|
30
40
|
useEffect(()=>{
|
|
31
41
|
reset();
|
|
@@ -33,29 +43,26 @@ export function EndpointsTab({ actions }) {
|
|
|
33
43
|
sourceId
|
|
34
44
|
]);
|
|
35
45
|
const handleNew = ()=>{
|
|
36
|
-
|
|
46
|
+
store.selectEndpoint(null);
|
|
37
47
|
setCreating(true);
|
|
38
48
|
};
|
|
39
49
|
const handleSelect = (endpoint)=>{
|
|
40
|
-
setSelected(endpoint);
|
|
41
50
|
setCreating(false);
|
|
51
|
+
store.selectEndpoint(endpoint.id);
|
|
42
52
|
};
|
|
43
53
|
const handleSaved = (saved)=>{
|
|
44
|
-
setSelected(saved);
|
|
45
54
|
setCreating(false);
|
|
46
|
-
// Re-selecting drops the old sample: it described the
|
|
55
|
+
// Re-selecting drops the old sample: it described the call as it was
|
|
47
56
|
// configured a moment ago, and the mapping would be built from it.
|
|
48
57
|
store.selectEndpoint(saved.id);
|
|
49
58
|
setReloadToken((token)=>token + 1);
|
|
50
59
|
};
|
|
51
60
|
const handleDeleted = ()=>{
|
|
52
|
-
setSelected(null);
|
|
53
61
|
setCreating(false);
|
|
54
62
|
store.selectEndpoint(null);
|
|
55
63
|
setReloadToken((token)=>token + 1);
|
|
56
64
|
};
|
|
57
65
|
const handleCancel = ()=>{
|
|
58
|
-
setSelected(null);
|
|
59
66
|
setCreating(false);
|
|
60
67
|
store.selectEndpoint(null);
|
|
61
68
|
};
|
|
@@ -65,9 +72,6 @@ export function EndpointsTab({ actions }) {
|
|
|
65
72
|
children: labels.endpoints.selectConnection
|
|
66
73
|
});
|
|
67
74
|
}
|
|
68
|
-
// Guarded against the store: the selection is the store's, and a record left
|
|
69
|
-
// over from the previous one must not be what the form shows.
|
|
70
|
-
const editing = selected && selected.id === store.selectedEndpointId ? selected : null;
|
|
71
75
|
return /*#__PURE__*/ _jsxs("div", {
|
|
72
76
|
className: "grid grid-cols-1 gap-4 xl:grid-cols-[minmax(0,18rem)_minmax(0,1fr)] xl:gap-5",
|
|
73
77
|
children: [
|
|
@@ -78,26 +82,28 @@ export function EndpointsTab({ actions }) {
|
|
|
78
82
|
reloadToken: reloadToken,
|
|
79
83
|
sourceId: sourceId
|
|
80
84
|
}, sourceId),
|
|
81
|
-
/*#__PURE__*/
|
|
85
|
+
/*#__PURE__*/ _jsx("div", {
|
|
82
86
|
className: theme.layout.main,
|
|
83
|
-
children:
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
87
|
+
children: editing || creating ? /*#__PURE__*/ _jsxs(_Fragment, {
|
|
88
|
+
children: [
|
|
89
|
+
/*#__PURE__*/ _jsx(EndpointForm, {
|
|
90
|
+
actions: actions,
|
|
91
|
+
endpoint: editing,
|
|
92
|
+
onCancel: handleCancel,
|
|
93
|
+
onDeleted: handleDeleted,
|
|
94
|
+
onSaved: handleSaved,
|
|
95
|
+
sourceId: sourceId
|
|
96
|
+
}),
|
|
97
|
+
editing ? /*#__PURE__*/ _jsx(EndpointSample, {
|
|
98
|
+
actions: actions,
|
|
99
|
+
endpoint: editing
|
|
100
|
+
}) : null
|
|
101
|
+
]
|
|
102
|
+
}) : /*#__PURE__*/ _jsx("p", {
|
|
103
|
+
className: theme.list.empty,
|
|
104
|
+
children: labels.endpoints.pickOne
|
|
105
|
+
})
|
|
106
|
+
}, editing?.id ?? (creating ? 'new' : 'none'))
|
|
101
107
|
]
|
|
102
108
|
});
|
|
103
109
|
}
|