nucleus-core-ts 0.9.799 → 0.9.801

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 (27) hide show
  1. package/dist/fe/components/IntegrationsPage/components/ConnectionBasicFields.js +18 -17
  2. package/dist/fe/components/IntegrationsPage/components/ConnectionList.js +11 -9
  3. package/dist/fe/components/IntegrationsPage/components/ConnectionTabs.d.ts +11 -3
  4. package/dist/fe/components/IntegrationsPage/components/ConnectionTabs.js +93 -59
  5. package/dist/fe/components/IntegrationsPage/components/IntegrationsPage.d.ts +1 -1
  6. package/dist/fe/components/IntegrationsPage/components/IntegrationsPage.js +172 -109
  7. package/dist/fe/components/IntegrationsPage/components/RunHistory.js +3 -1
  8. package/dist/fe/components/IntegrationsPage/components/RunPanel.js +4 -2
  9. package/dist/fe/components/IntegrationsPage/components/RunPlanIssues.js +6 -4
  10. package/dist/fe/components/IntegrationsPage/components/RunPlanSummary.js +8 -6
  11. package/dist/fe/components/IntegrationsPage/components/RunsTab.js +3 -1
  12. package/dist/fe/components/IntegrationsPage/index.d.ts +2 -0
  13. package/dist/fe/components/IntegrationsPage/index.js +1 -0
  14. package/dist/fe/components/IntegrationsPage/store/index.js +9 -0
  15. package/dist/fe/components/IntegrationsPage/store/state.d.ts +9 -0
  16. package/dist/fe/components/IntegrationsPage/text/context.d.ts +7 -0
  17. package/dist/fe/components/IntegrationsPage/text/context.js +20 -0
  18. package/dist/fe/components/IntegrationsPage/text/index.d.ts +137 -0
  19. package/dist/fe/components/IntegrationsPage/text/index.js +146 -0
  20. package/dist/fe/components/IntegrationsPage/text/text.test.d.ts +1 -0
  21. package/dist/fe/components/IntegrationsPage/text/text.test.js +67 -0
  22. package/dist/fe/components/IntegrationsPage/theme/index.d.ts +16 -0
  23. package/dist/fe/components/IntegrationsPage/theme/index.js +18 -0
  24. package/dist/fe/components/IntegrationsPage/types/actions.d.ts +9 -0
  25. package/dist/fe/index.d.ts +2 -1
  26. package/dist/fe/index.js +1 -1
  27. package/package.json +1 -1
@@ -1,6 +1,7 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { cn } from '../../../utils/cn';
4
+ import { useLabels } from '../text/context';
4
5
  import { integrationsPageTheme } from '../theme';
5
6
  import { describedBy } from './formSupport';
6
7
  import { Field } from './Primitives';
@@ -9,16 +10,16 @@ import { Field } from './Primitives';
9
10
  * decide whether it is used and how carefully.
10
11
  */ const theme = integrationsPageTheme;
11
12
  const CHECKBOX = 'h-4 w-4 shrink-0 accent-sky-600 dark:accent-sky-500';
12
- const BASE_URL_HINT = 'The scheme is free. https:// and plain http:// are both accepted and neither is rewritten — calling a service inside the same cluster over http, for example http://hr-service:8080, is a legitimate setup.';
13
13
  export function ConnectionBasicFields({ draft, errors, disabled, onChange }) {
14
+ const labels = useLabels();
14
15
  return /*#__PURE__*/ _jsxs("section", {
15
- "aria-label": "Connection details",
16
+ "aria-label": labels.connectionForm.sectionLabel,
16
17
  className: "flex flex-col gap-3",
17
18
  children: [
18
19
  /*#__PURE__*/ _jsx(Field, {
19
20
  error: errors.name,
20
21
  htmlFor: "connection-name",
21
- label: "Name",
22
+ label: labels.connectionForm.name,
22
23
  children: /*#__PURE__*/ _jsx("input", {
23
24
  "aria-describedby": describedBy('connection-name', false, Boolean(errors.name)),
24
25
  className: theme.field.input,
@@ -27,16 +28,16 @@ export function ConnectionBasicFields({ draft, errors, disabled, onChange }) {
27
28
  onChange: (event)=>onChange({
28
29
  name: event.target.value
29
30
  }),
30
- placeholder: "Directory service",
31
+ placeholder: labels.connectionForm.namePlaceholder,
31
32
  type: "text",
32
33
  value: draft.name
33
34
  })
34
35
  }),
35
36
  /*#__PURE__*/ _jsx(Field, {
36
37
  error: errors.slug,
37
- hint: "Used to refer to this connection elsewhere. It does not change once things point at it.",
38
+ hint: labels.connectionForm.slugHint,
38
39
  htmlFor: "connection-slug",
39
- label: "Slug",
40
+ label: labels.connectionForm.slug,
40
41
  children: /*#__PURE__*/ _jsx("input", {
41
42
  "aria-describedby": describedBy('connection-slug', true, Boolean(errors.slug)),
42
43
  className: theme.field.input,
@@ -52,9 +53,9 @@ export function ConnectionBasicFields({ draft, errors, disabled, onChange }) {
52
53
  }),
53
54
  /*#__PURE__*/ _jsx(Field, {
54
55
  error: errors.baseUrl,
55
- hint: BASE_URL_HINT,
56
+ hint: labels.connectionForm.baseUrlHint,
56
57
  htmlFor: "connection-base-url",
57
- label: "Base URL",
58
+ label: labels.connectionForm.baseUrl,
58
59
  children: /*#__PURE__*/ _jsx("input", {
59
60
  "aria-describedby": describedBy('connection-base-url', true, Boolean(errors.baseUrl)),
60
61
  className: theme.field.input,
@@ -69,9 +70,9 @@ export function ConnectionBasicFields({ draft, errors, disabled, onChange }) {
69
70
  })
70
71
  }),
71
72
  /*#__PURE__*/ _jsx(Field, {
72
- hint: "For whoever has to work out what this connection is, months from now.",
73
+ hint: labels.connectionForm.descriptionHint,
73
74
  htmlFor: "connection-description",
74
- label: "Description",
75
+ label: labels.connectionForm.description,
75
76
  children: /*#__PURE__*/ _jsx("textarea", {
76
77
  "aria-describedby": describedBy('connection-description', true, false),
77
78
  className: cn(theme.field.input, 'h-20 py-2 sm:h-20'),
@@ -80,7 +81,7 @@ export function ConnectionBasicFields({ draft, errors, disabled, onChange }) {
80
81
  onChange: (event)=>onChange({
81
82
  description: event.target.value
82
83
  }),
83
- placeholder: "Read-only employee directory used by the nightly import.",
84
+ placeholder: labels.connectionForm.descriptionPlaceholder,
84
85
  value: draft.description
85
86
  })
86
87
  }),
@@ -102,13 +103,13 @@ export function ConnectionBasicFields({ draft, errors, disabled, onChange }) {
102
103
  }),
103
104
  type: "checkbox"
104
105
  }),
105
- "Enabled"
106
+ labels.connectionForm.enabled
106
107
  ]
107
108
  }),
108
109
  /*#__PURE__*/ _jsx("span", {
109
110
  className: theme.field.hint,
110
111
  id: "connection-enabled-hint",
111
- children: "Turning this off stops every endpoint and import that goes through this connection. The settings are kept."
112
+ children: labels.connectionForm.enabledHint
112
113
  })
113
114
  ]
114
115
  }),
@@ -130,21 +131,21 @@ export function ConnectionBasicFields({ draft, errors, disabled, onChange }) {
130
131
  }),
131
132
  type: "checkbox"
132
133
  }),
133
- "Verify TLS certificate"
134
+ labels.connectionForm.tlsVerify
134
135
  ]
135
136
  }),
136
137
  /*#__PURE__*/ _jsx("span", {
137
138
  className: theme.field.hint,
138
139
  id: "connection-tls-verify-hint",
139
- children: draft.tlsVerify ? 'On. Unchecking it applies to requests made through THIS connection only — no other connection and nothing else in the app is affected.' : 'Off. Certificates are not checked for requests made through THIS connection only. Every other connection still verifies. Use it for an internal service with its own certificate authority.'
140
+ children: draft.tlsVerify ? labels.connectionForm.tlsVerifyOnHint : labels.connectionForm.tlsVerifyOffHint
140
141
  })
141
142
  ]
142
143
  }),
143
144
  /*#__PURE__*/ _jsx(Field, {
144
145
  error: errors.timeoutMs,
145
- hint: "How long one request may take before it is given up on. Empty means the server default.",
146
+ hint: labels.connectionForm.timeoutHint,
146
147
  htmlFor: "connection-timeout",
147
- label: "Timeout (ms)",
148
+ label: labels.connectionForm.timeout,
148
149
  children: /*#__PURE__*/ _jsx("input", {
149
150
  "aria-describedby": describedBy('connection-timeout', true, Boolean(errors.timeoutMs)),
150
151
  className: theme.field.input,
@@ -3,6 +3,7 @@ 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
5
  import { useIntegrationsStore } from '../store';
6
+ import { useLabels } from '../text/context';
6
7
  import { integrationsPageTheme } from '../theme';
7
8
  import { Badge, Field, Notice } from './Primitives';
8
9
  import { ListSkeleton } from './Skeletons';
@@ -19,6 +20,7 @@ const PAGE_SIZE = 20;
19
20
  const SEARCH_DEBOUNCE_MS = 300;
20
21
  export function ConnectionList({ actions, onNewConnection, reloadToken = 0 }) {
21
22
  const store = useIntegrationsStore();
23
+ const labels = useLabels();
22
24
  const search = store.sourcesSearch;
23
25
  const selectedId = store.selectedSourceId;
24
26
  const [term, setTerm] = useState(search);
@@ -84,11 +86,11 @@ export function ConnectionList({ actions, onNewConnection, reloadToken = 0 }) {
84
86
  children: [
85
87
  /*#__PURE__*/ _jsx("h2", {
86
88
  className: theme.header.title,
87
- children: "Connections"
89
+ children: labels.connections.heading
88
90
  }),
89
91
  /*#__PURE__*/ _jsx("p", {
90
92
  className: theme.header.subtitle,
91
- children: list.total === 1 ? '1 connection' : `${list.total} connections`
93
+ children: list.total === 1 ? labels.connections.countOne : labels.connections.countMany(list.total)
92
94
  })
93
95
  ]
94
96
  }),
@@ -98,19 +100,19 @@ export function ConnectionList({ actions, onNewConnection, reloadToken = 0 }) {
98
100
  className: theme.button.primary,
99
101
  onClick: handleNew,
100
102
  type: "button",
101
- children: "New connection"
103
+ children: labels.connections.create
102
104
  })
103
105
  })
104
106
  ]
105
107
  }),
106
108
  /*#__PURE__*/ _jsx(Field, {
107
109
  htmlFor: "connection-search",
108
- label: "Search",
110
+ label: labels.connections.searchLabel,
109
111
  children: /*#__PURE__*/ _jsx("input", {
110
112
  className: theme.field.input,
111
113
  id: "connection-search",
112
114
  onChange: (event)=>setTerm(event.target.value),
113
- placeholder: "Name or slug",
115
+ placeholder: labels.connections.searchPlaceholder,
114
116
  type: "search",
115
117
  value: term
116
118
  })
@@ -119,7 +121,7 @@ export function ConnectionList({ actions, onNewConnection, reloadToken = 0 }) {
119
121
  rows: 6
120
122
  }) : null,
121
123
  list.error ? /*#__PURE__*/ _jsxs(Notice, {
122
- title: "This list could not be loaded",
124
+ title: labels.connections.loadFailed,
123
125
  tone: "danger",
124
126
  children: [
125
127
  list.error,
@@ -128,13 +130,13 @@ export function ConnectionList({ actions, onNewConnection, reloadToken = 0 }) {
128
130
  className: theme.button.ghost,
129
131
  onClick: list.reload,
130
132
  type: "button",
131
- children: "Try again"
133
+ children: labels.connections.retry
132
134
  })
133
135
  ]
134
136
  }) : null,
135
137
  !firstLoad && list.items.length === 0 && !list.error ? /*#__PURE__*/ _jsx("p", {
136
138
  className: theme.list.empty,
137
- children: search.length > 0 ? `No connection matches “${search}”. Clear the search to see them all.` : 'No connections yet. A connection is one service this app calls — its base URL, how it authenticates and how long it may take. Start with New connection.'
139
+ children: search.length > 0 ? labels.connections.emptySearch(search) : labels.connections.empty
138
140
  }) : null,
139
141
  list.items.length > 0 ? /*#__PURE__*/ _jsx("ul", {
140
142
  className: theme.list.wrapper,
@@ -154,7 +156,7 @@ export function ConnectionList({ actions, onNewConnection, reloadToken = 0 }) {
154
156
  }),
155
157
  source.enabled === false ? /*#__PURE__*/ _jsx(Badge, {
156
158
  tone: "neutral",
157
- children: "Off"
159
+ children: labels.connections.off
158
160
  }) : null
159
161
  ]
160
162
  }),
@@ -2,11 +2,19 @@ import type { ConnectionTab } from '../store/state';
2
2
  /** Shared with the panel so `aria-controls` and `aria-labelledby` line up. */
3
3
  export declare function connectionTabId(tab: ConnectionTab): string;
4
4
  export declare function connectionTabPanelId(tab: ConnectionTab): string;
5
+ /** What a step has to show about itself beyond its name. */
6
+ export type ConnectionStepState = {
7
+ /** Shown in place of the number, and in the step's own words. */
8
+ done?: boolean;
9
+ /** The step before it is unfinished; still reachable, but said so. */
10
+ locked?: boolean;
11
+ /** One short phrase proving the step is done — "3 calls, all sampled". */
12
+ evidence?: string;
13
+ };
5
14
  export type ConnectionTabsProps = {
6
15
  value: ConnectionTab;
7
16
  onChange: (tab: ConnectionTab) => void;
8
- /** Server-reported totals. A zero is left off rather than shown as "0". */
9
- counts?: Partial<Record<ConnectionTab, number>>;
17
+ steps?: Partial<Record<ConnectionTab, ConnectionStepState>>;
10
18
  label?: string;
11
19
  };
12
- export declare function ConnectionTabs({ value, onChange, counts, label, }: ConnectionTabsProps): import("react/jsx-runtime").JSX.Element;
20
+ export declare function ConnectionTabs({ value, onChange, steps, label, }: ConnectionTabsProps): import("react/jsx-runtime").JSX.Element;
@@ -2,32 +2,29 @@
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useRef } from 'react';
4
4
  import { cn } from '../../../utils/cn';
5
+ import { useLabels } from '../text/context';
5
6
  import { integrationsPageTheme } from '../theme';
6
7
  /**
7
- * The strip that switches between a connection's own settings, its endpoints,
8
- * its mappings and its runs.
8
+ * The four phases of an import, in the order they happen.
9
9
  *
10
- * It is a real ARIA tablist: one tab is in the tab order and the arrow keys move
11
- * between the rest. A row of separately tabbable buttons would make a keyboard
12
- * user press Tab three times to leave a control they were never inside.
10
+ * These were four flat tabs Connection, Endpoints, Mappings, Runs sitting
11
+ * side by side with nothing to say that they are a SEQUENCE, that a mapping is
12
+ * meaningless before a call has been tried, or which of them the operator had
13
+ * already finished. People opened the middle one first and met a dead end.
14
+ *
15
+ * So each is a step: a number, its name, one sentence saying what it is for, and
16
+ * a line of evidence once it is done. What is on screen now answers "where am I,
17
+ * what is this for, and what have I already got".
18
+ *
19
+ * It remains a real ARIA tablist — one stop in the tab order, arrow keys between
20
+ * the steps. A row of separately tabbable cards would make a keyboard user press
21
+ * Tab four times to leave a strip they were never inside.
13
22
  */ const theme = integrationsPageTheme;
14
- const TABS = [
15
- {
16
- value: 'connection',
17
- label: 'Connection'
18
- },
19
- {
20
- value: 'endpoints',
21
- label: 'Endpoints'
22
- },
23
- {
24
- value: 'mappings',
25
- label: 'Mappings'
26
- },
27
- {
28
- value: 'runs',
29
- label: 'Runs'
30
- }
23
+ const ORDER = [
24
+ 'connection',
25
+ 'endpoints',
26
+ 'mappings',
27
+ 'runs'
31
28
  ];
32
29
  /** Shared with the panel so `aria-controls` and `aria-labelledby` line up. */ export function connectionTabId(tab) {
33
30
  return `integrations-tab-${tab}`;
@@ -35,18 +32,25 @@ const TABS = [
35
32
  export function connectionTabPanelId(tab) {
36
33
  return `integrations-panel-${tab}`;
37
34
  }
38
- export function ConnectionTabs({ value, onChange, counts, label = 'Connection sections' }) {
35
+ export function ConnectionTabs({ value, onChange, steps, label = 'Import steps' }) {
36
+ const labels = useLabels();
39
37
  const buttonsRef = useRef({});
38
+ const copy = {
39
+ connection: labels.journey.connection,
40
+ endpoints: labels.journey.endpoints,
41
+ mappings: labels.journey.mappings,
42
+ runs: labels.journey.runs
43
+ };
40
44
  const select = (index)=>{
41
- const next = TABS[(index % TABS.length + TABS.length) % TABS.length];
45
+ const next = ORDER[(index % ORDER.length + ORDER.length) % ORDER.length];
42
46
  if (!next) return;
43
- onChange(next.value);
47
+ onChange(next);
44
48
  // Selection follows focus, so the focus has to follow the selection too —
45
- // otherwise the next arrow press starts from the tab the user just left.
46
- buttonsRef.current[next.value]?.focus();
49
+ // otherwise the next arrow press starts from the step the user just left.
50
+ buttonsRef.current[next]?.focus();
47
51
  };
48
52
  const handleKeyDown = (event, tab)=>{
49
- const index = TABS.findIndex((entry)=>entry.value === tab);
53
+ const index = ORDER.indexOf(tab);
50
54
  if (event.key === 'ArrowRight' || event.key === 'ArrowDown') {
51
55
  event.preventDefault();
52
56
  select(index + 1);
@@ -58,38 +62,68 @@ export function ConnectionTabs({ value, onChange, counts, label = 'Connection se
58
62
  select(0);
59
63
  } else if (event.key === 'End') {
60
64
  event.preventDefault();
61
- select(TABS.length - 1);
65
+ select(ORDER.length - 1);
62
66
  }
63
67
  };
64
- return /*#__PURE__*/ _jsx("div", {
65
- "aria-label": label,
66
- className: theme.tabs.wrapper,
67
- role: "tablist",
68
- children: TABS.map((tab)=>{
69
- const selected = tab.value === value;
70
- const count = counts?.[tab.value];
71
- return /*#__PURE__*/ _jsxs("button", {
72
- "aria-controls": connectionTabPanelId(tab.value),
73
- "aria-selected": selected,
74
- className: cn(theme.tabs.button, selected ? theme.tabs.active : theme.tabs.inactive),
75
- id: connectionTabId(tab.value),
76
- onClick: ()=>onChange(tab.value),
77
- onKeyDown: (event)=>handleKeyDown(event, tab.value),
78
- ref: (node)=>{
79
- buttonsRef.current[tab.value] = node;
80
- },
81
- role: "tab",
82
- // Roving tabindex: the tablist is ONE stop in the tab order.
83
- tabIndex: selected ? 0 : -1,
84
- type: "button",
85
- children: [
86
- tab.label,
87
- typeof count === 'number' && count > 0 ? /*#__PURE__*/ _jsx("span", {
88
- className: cn(theme.progress.label, 'ml-1.5'),
89
- children: count
90
- }) : null
91
- ]
92
- }, tab.value);
93
- })
68
+ return /*#__PURE__*/ _jsxs("div", {
69
+ className: "flex flex-col gap-2.5",
70
+ children: [
71
+ /*#__PURE__*/ _jsx("p", {
72
+ className: theme.steps.intro,
73
+ children: labels.journey.intro
74
+ }),
75
+ /*#__PURE__*/ _jsx("div", {
76
+ "aria-label": label,
77
+ className: theme.steps.wrapper,
78
+ role: "tablist",
79
+ children: ORDER.map((tab, index)=>{
80
+ const selected = tab === value;
81
+ const state = steps?.[tab] ?? {};
82
+ const { name, purpose } = copy[tab];
83
+ return /*#__PURE__*/ _jsxs("button", {
84
+ "aria-controls": connectionTabPanelId(tab),
85
+ "aria-selected": selected,
86
+ className: cn(theme.steps.item, state.done && !selected && theme.steps.itemDone, state.locked && !selected && theme.steps.itemLocked, selected && theme.steps.itemActive),
87
+ id: connectionTabId(tab),
88
+ onClick: ()=>onChange(tab),
89
+ onKeyDown: (event)=>handleKeyDown(event, tab),
90
+ ref: (node)=>{
91
+ buttonsRef.current[tab] = node;
92
+ },
93
+ role: "tab",
94
+ // Roving tabindex: the whole strip is ONE stop in the tab order.
95
+ tabIndex: selected ? 0 : -1,
96
+ type: "button",
97
+ children: [
98
+ /*#__PURE__*/ _jsx("span", {
99
+ "aria-hidden": "true",
100
+ className: cn(theme.steps.marker, selected ? theme.steps.markerActive : state.done ? theme.steps.markerDone : state.locked ? theme.steps.markerLocked : theme.steps.markerLocked),
101
+ children: state.done && !selected ? '✓' : index + 1
102
+ }),
103
+ /*#__PURE__*/ _jsxs("span", {
104
+ className: "min-w-0 flex-1",
105
+ children: [
106
+ /*#__PURE__*/ _jsx("span", {
107
+ className: cn(theme.steps.name, 'block'),
108
+ children: name
109
+ }),
110
+ /*#__PURE__*/ _jsx("span", {
111
+ className: cn(theme.steps.purpose, 'block'),
112
+ children: purpose
113
+ }),
114
+ state.evidence ? /*#__PURE__*/ _jsx("span", {
115
+ className: cn(theme.steps.evidence, 'block'),
116
+ children: state.evidence
117
+ }) : state.locked ? /*#__PURE__*/ _jsx("span", {
118
+ className: cn(theme.field.hint, 'mt-1 block'),
119
+ children: labels.journey.lockedHint
120
+ }) : null
121
+ ]
122
+ })
123
+ ]
124
+ }, tab);
125
+ })
126
+ })
127
+ ]
94
128
  });
95
129
  }
@@ -1,2 +1,2 @@
1
1
  import type { IntegrationsPageProps } from '../types';
2
- export declare function IntegrationsPage({ title, subtitle, className, actions, onSubscribeProgress, }: IntegrationsPageProps): import("react/jsx-runtime").JSX.Element;
2
+ export declare function IntegrationsPage({ title, subtitle, className, actions, labels: labelsOverride, onSubscribeProgress, }: IntegrationsPageProps): import("react/jsx-runtime").JSX.Element;