@odigos/ui-kit 0.0.17 → 0.0.19
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/CHANGELOG.md +15 -0
- package/lib/components/index.d.ts +1 -0
- package/lib/components/scroll-x/index.d.ts +10 -0
- package/lib/components.js +13 -44
- package/lib/constants.js +5 -9
- package/lib/containers/data-flow/nodes/scroll-node.d.ts +3 -14
- package/lib/containers.js +42 -94
- package/lib/functions.js +9 -15
- package/lib/hooks.js +10 -10
- package/lib/icons.js +3 -4
- package/lib/{index-Hz7AAE0t.js → index-7-KCQK-x.js} +1 -1
- package/lib/{index-G4WmxXds.js → index-BFRz3l_w.js} +21 -4
- package/lib/index-BazfJyRh.js +687 -0
- package/lib/{index-C3nz3TIx.js → index-CD_BQJCD.js} +5 -3
- package/lib/{index-BiNX-Cge.js → index-CvuVOtkr.js} +154 -119
- package/lib/{index-CIXQeSHu.js → index-DGel4E-Z.js} +8 -1
- package/lib/{index-BQW5EUgp.js → index-DSzybApb.js} +6 -4
- package/lib/{index-BxQTUOME.js → index-WSle42rz.js} +5 -3
- package/lib/store.js +3 -6
- package/lib/theme.js +3 -86
- package/lib/types.js +215 -6
- package/lib/useSourceSelectionFormData-_2PggiXn.js +563 -0
- package/lib/{useTimeAgo-weEj7br6.js → useTransition-bXMKBfST.js} +113 -544
- package/package.json +1 -2
- package/lib/index-B72aw6tI.js +0 -23
- package/lib/index-BQs4sULy.js +0 -32
- package/lib/index-BVVVevuY.js +0 -100
- package/lib/index-BWqrekK4.js +0 -11
- package/lib/index-C1PCuZgw.js +0 -18
- package/lib/index-CIgHU72d.js +0 -52
- package/lib/index-DbfrGXPH.js +0 -8
- package/lib/index-RBS1MqCQ.js +0 -37
- package/lib/react-CjImwkhV.js +0 -44
- package/lib/useDarkMode-DxhIuVNi.js +0 -201
- package/lib/useSelectedStore-93bIo1kE.js +0 -97
- package/lib/useSetupStore-CoYx1UQw.js +0 -211
- package/lib/useTransition-D0wUpPGk.js +0 -128
|
@@ -1,11 +1,8 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import
|
|
6
|
-
import { A as AddNodeTypes } from './index-B72aw6tI.js';
|
|
7
|
-
import { g as getIdFromSseTarget } from './index-Hz7AAE0t.js';
|
|
8
|
-
import { useState, useEffect, useCallback } from 'react';
|
|
1
|
+
import React, { useState, useRef, useEffect, useCallback } from 'react';
|
|
2
|
+
import './index-BFRz3l_w.js';
|
|
3
|
+
import { f as useNotificationStore } from './index-BazfJyRh.js';
|
|
4
|
+
import { CodeAttributesKeyTypes, PayloadCollectionKeyTypes } from './types.js';
|
|
5
|
+
import styled from 'styled-components';
|
|
9
6
|
|
|
10
7
|
const useGenericForm = (initialFormData) => {
|
|
11
8
|
function copyInitial() {
|
|
@@ -64,341 +61,69 @@ const useGenericForm = (initialFormData) => {
|
|
|
64
61
|
};
|
|
65
62
|
};
|
|
66
63
|
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
piiCategories: null,
|
|
78
|
-
fallbackSamplingRatio: null,
|
|
79
|
-
samplingPercentage: null,
|
|
80
|
-
endpointsFilters: null,
|
|
81
|
-
};
|
|
82
|
-
const useActionFormData = () => {
|
|
83
|
-
const { addNotification } = useNotificationStore();
|
|
84
|
-
const { formData, formErrors, handleFormChange, handleErrorChange, resetFormData } = useGenericForm(INITIAL$3);
|
|
85
|
-
const validateForm = (params) => {
|
|
86
|
-
const errors = {};
|
|
87
|
-
let ok = true;
|
|
88
|
-
Object.entries(formData).forEach(([k, v]) => {
|
|
89
|
-
switch (k) {
|
|
90
|
-
case 'type':
|
|
91
|
-
case 'signals':
|
|
92
|
-
if (isEmpty(v))
|
|
93
|
-
errors[k] = FORM_ALERTS.FIELD_IS_REQUIRED;
|
|
94
|
-
break;
|
|
95
|
-
case 'clusterAttributes':
|
|
96
|
-
if (formData.type === ActionType.AddClusterInfo && isEmpty(v))
|
|
97
|
-
errors[k] = FORM_ALERTS.FIELD_IS_REQUIRED;
|
|
98
|
-
break;
|
|
99
|
-
case 'renames':
|
|
100
|
-
if (formData.type === ActionType.RenameAttributes && isEmpty(v))
|
|
101
|
-
errors[k] = FORM_ALERTS.FIELD_IS_REQUIRED;
|
|
102
|
-
break;
|
|
103
|
-
case 'attributeNamesToDelete':
|
|
104
|
-
if (formData.type === ActionType.DeleteAttributes && isEmpty(v))
|
|
105
|
-
errors[k] = FORM_ALERTS.FIELD_IS_REQUIRED;
|
|
106
|
-
break;
|
|
107
|
-
case 'piiCategories':
|
|
108
|
-
if (formData.type === ActionType.PiiMasking && isEmpty(v))
|
|
109
|
-
errors[k] = FORM_ALERTS.FIELD_IS_REQUIRED;
|
|
110
|
-
break;
|
|
111
|
-
case 'fallbackSamplingRatio':
|
|
112
|
-
if (formData.type === ActionType.ErrorSampler && isEmpty(v))
|
|
113
|
-
errors[k] = FORM_ALERTS.FIELD_IS_REQUIRED;
|
|
114
|
-
break;
|
|
115
|
-
case 'samplingPercentage':
|
|
116
|
-
if (formData.type === ActionType.ProbabilisticSampler && isEmpty(v))
|
|
117
|
-
errors[k] = FORM_ALERTS.FIELD_IS_REQUIRED;
|
|
118
|
-
break;
|
|
119
|
-
case 'endpointsFilters':
|
|
120
|
-
if (formData.type === ActionType.LatencySampler) {
|
|
121
|
-
if (isEmpty(v))
|
|
122
|
-
errors[k] = FORM_ALERTS.FIELD_IS_REQUIRED;
|
|
123
|
-
v?.forEach((endpoint) => {
|
|
124
|
-
if (endpoint.httpRoute.charAt(0) !== '/')
|
|
125
|
-
errors[k] = FORM_ALERTS.LATENCY_HTTP_ROUTE;
|
|
126
|
-
});
|
|
127
|
-
}
|
|
128
|
-
break;
|
|
64
|
+
const useContainerSize = () => {
|
|
65
|
+
const ref = useRef(null);
|
|
66
|
+
const [width, setWidth] = useState(0);
|
|
67
|
+
const [height, setHeight] = useState(0);
|
|
68
|
+
useEffect(() => {
|
|
69
|
+
const resize = () => {
|
|
70
|
+
if (ref.current) {
|
|
71
|
+
const { width, height } = ref.current.getBoundingClientRect();
|
|
72
|
+
setWidth(width);
|
|
73
|
+
setHeight(height);
|
|
129
74
|
}
|
|
130
|
-
});
|
|
131
|
-
ok = !Object.values(errors).length;
|
|
132
|
-
if (!ok && params?.withAlert) {
|
|
133
|
-
addNotification({
|
|
134
|
-
type: StatusType.Warning,
|
|
135
|
-
title: params.alertTitle,
|
|
136
|
-
message: FORM_ALERTS.REQUIRED_FIELDS,
|
|
137
|
-
hideFromHistory: true,
|
|
138
|
-
});
|
|
139
|
-
}
|
|
140
|
-
handleErrorChange(undefined, undefined, errors);
|
|
141
|
-
return ok;
|
|
142
|
-
};
|
|
143
|
-
const loadFormWithDrawerItem = ({ type, spec }) => {
|
|
144
|
-
const updatedData = {
|
|
145
|
-
...INITIAL$3,
|
|
146
|
-
type,
|
|
147
75
|
};
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
updatedData['name'] = v;
|
|
153
|
-
break;
|
|
154
|
-
}
|
|
155
|
-
case 'type':
|
|
156
|
-
case 'notes':
|
|
157
|
-
case 'signals':
|
|
158
|
-
case 'disabled':
|
|
159
|
-
case 'collectContainerAttributes':
|
|
160
|
-
case 'collectWorkloadId':
|
|
161
|
-
case 'collectClusterId':
|
|
162
|
-
case 'labelsAttributes':
|
|
163
|
-
case 'annotationsAttributes':
|
|
164
|
-
case 'clusterAttributes':
|
|
165
|
-
case 'attributeNamesToDelete':
|
|
166
|
-
case 'renames':
|
|
167
|
-
case 'piiCategories':
|
|
168
|
-
case 'fallbackSamplingRatio':
|
|
169
|
-
case 'samplingPercentage':
|
|
170
|
-
case 'endpointsFilters': {
|
|
171
|
-
// @ts-ignore
|
|
172
|
-
updatedData[k] = v;
|
|
173
|
-
break;
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
});
|
|
178
|
-
handleFormChange(undefined, undefined, updatedData);
|
|
179
|
-
};
|
|
76
|
+
resize();
|
|
77
|
+
window.addEventListener('resize', resize);
|
|
78
|
+
return () => window.removeEventListener('resize', resize);
|
|
79
|
+
}, []);
|
|
180
80
|
return {
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
resetFormData,
|
|
185
|
-
validateForm,
|
|
186
|
-
loadFormWithDrawerItem,
|
|
187
|
-
};
|
|
188
|
-
};
|
|
189
|
-
|
|
190
|
-
const useClickNode = () => {
|
|
191
|
-
const { setCurrentModal } = useModalStore();
|
|
192
|
-
const { setDrawerType, setDrawerEntityId } = useDrawerStore();
|
|
193
|
-
const onClickNode = (_, object) => {
|
|
194
|
-
const { data: { id, type }, } = object;
|
|
195
|
-
switch (type) {
|
|
196
|
-
case EntityTypes.Source:
|
|
197
|
-
case EntityTypes.Destination:
|
|
198
|
-
case EntityTypes.Action:
|
|
199
|
-
case EntityTypes.InstrumentationRule:
|
|
200
|
-
setDrawerType(type);
|
|
201
|
-
setDrawerEntityId(id);
|
|
202
|
-
break;
|
|
203
|
-
case AddNodeTypes.AddSource:
|
|
204
|
-
setCurrentModal(EntityTypes.Source);
|
|
205
|
-
break;
|
|
206
|
-
case AddNodeTypes.AddDestination:
|
|
207
|
-
setCurrentModal(EntityTypes.Destination);
|
|
208
|
-
break;
|
|
209
|
-
case AddNodeTypes.AddAction:
|
|
210
|
-
setCurrentModal(EntityTypes.Action);
|
|
211
|
-
break;
|
|
212
|
-
case AddNodeTypes.AddRule:
|
|
213
|
-
setCurrentModal(EntityTypes.InstrumentationRule);
|
|
214
|
-
break;
|
|
215
|
-
default:
|
|
216
|
-
console.warn('Unhandled node click', object);
|
|
217
|
-
break;
|
|
218
|
-
}
|
|
81
|
+
containerRef: ref,
|
|
82
|
+
containerWidth: width,
|
|
83
|
+
containerHeight: height,
|
|
219
84
|
};
|
|
220
|
-
return { onClickNode };
|
|
221
85
|
};
|
|
222
86
|
|
|
223
|
-
const
|
|
224
|
-
const
|
|
225
|
-
const
|
|
226
|
-
const
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
setDrawerType(EntityTypes.Source);
|
|
239
|
-
setDrawerEntityId(getIdFromSseTarget(target, EntityTypes.Source));
|
|
240
|
-
break;
|
|
241
|
-
case EntityTypes.Action:
|
|
242
|
-
setDrawerType(EntityTypes.Action);
|
|
243
|
-
setDrawerEntityId(getIdFromSseTarget(target, EntityTypes.Action));
|
|
244
|
-
break;
|
|
245
|
-
case EntityTypes.Destination:
|
|
246
|
-
case 'Destination':
|
|
247
|
-
setDrawerType(EntityTypes.Destination);
|
|
248
|
-
setDrawerEntityId(getIdFromSseTarget(target, EntityTypes.Destination));
|
|
249
|
-
break;
|
|
250
|
-
default:
|
|
251
|
-
console.warn('notif click not handled for:', { crdType, target });
|
|
252
|
-
break;
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
markAsSeen(id);
|
|
256
|
-
if (dismissToast)
|
|
257
|
-
markAsDismissed(id);
|
|
258
|
-
};
|
|
259
|
-
return { onClickNotification };
|
|
260
|
-
};
|
|
261
|
-
|
|
262
|
-
const INITIAL$2 = {
|
|
263
|
-
// @ts-ignore form should be initialized with empty values
|
|
264
|
-
type: '',
|
|
265
|
-
name: '',
|
|
266
|
-
exportedSignals: {
|
|
267
|
-
logs: false,
|
|
268
|
-
metrics: false,
|
|
269
|
-
traces: false,
|
|
270
|
-
},
|
|
271
|
-
fields: [],
|
|
272
|
-
};
|
|
273
|
-
const buildFormDynamicFields = (fields) => {
|
|
274
|
-
return fields
|
|
275
|
-
.filter((f) => !!f)
|
|
276
|
-
.map((f) => {
|
|
277
|
-
const { name, componentType, componentProperties, displayName, initialValue, renderCondition } = f;
|
|
278
|
-
switch (componentType) {
|
|
279
|
-
case FieldTypes.Dropdown: {
|
|
280
|
-
const componentPropertiesJson = safeJsonParse(componentProperties, {});
|
|
281
|
-
const options = Array.isArray(componentPropertiesJson.values)
|
|
282
|
-
? componentPropertiesJson.values.map((value) => ({
|
|
283
|
-
id: value,
|
|
284
|
-
value,
|
|
285
|
-
}))
|
|
286
|
-
: Object.entries(componentPropertiesJson.values).map(([key, value]) => ({
|
|
287
|
-
id: key,
|
|
288
|
-
value,
|
|
289
|
-
}));
|
|
290
|
-
return {
|
|
291
|
-
name,
|
|
292
|
-
componentType: componentType,
|
|
293
|
-
title: displayName,
|
|
294
|
-
value: initialValue,
|
|
295
|
-
placeholder: componentPropertiesJson.placeholder || 'Select an option',
|
|
296
|
-
options,
|
|
297
|
-
renderCondition,
|
|
298
|
-
...componentPropertiesJson,
|
|
299
|
-
};
|
|
300
|
-
}
|
|
301
|
-
default: {
|
|
302
|
-
const componentPropertiesJson = safeJsonParse(componentProperties, {});
|
|
303
|
-
return {
|
|
304
|
-
name,
|
|
305
|
-
componentType,
|
|
306
|
-
title: displayName,
|
|
307
|
-
value: initialValue,
|
|
308
|
-
renderCondition,
|
|
309
|
-
...componentPropertiesJson,
|
|
310
|
-
};
|
|
87
|
+
const useCopy = () => {
|
|
88
|
+
const [isCopied, setIsCopied] = useState(false);
|
|
89
|
+
const [copiedIndex, setCopiedIndex] = useState(-1);
|
|
90
|
+
const clickCopy = async (str, idx) => {
|
|
91
|
+
if (!isCopied) {
|
|
92
|
+
setIsCopied(true);
|
|
93
|
+
if (idx !== undefined)
|
|
94
|
+
setCopiedIndex(idx);
|
|
95
|
+
if (navigator?.clipboard && navigator.clipboard.writeText) {
|
|
96
|
+
try {
|
|
97
|
+
await navigator.clipboard.writeText(str);
|
|
98
|
+
}
|
|
99
|
+
catch (err) {
|
|
100
|
+
console.error('Clipboard write failed:', err);
|
|
101
|
+
}
|
|
311
102
|
}
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
const [dynamicFields, setDynamicFields] = useState([]);
|
|
321
|
-
useEffect(() => {
|
|
322
|
-
if (yamlFields) {
|
|
323
|
-
setDynamicFields(buildFormDynamicFields(yamlFields).map((field) => {
|
|
324
|
-
// if we have preloaded fields, we need to set the value of the field
|
|
325
|
-
// (this can be from an odigos-detected-destination during create, or from an existing destination during edit/update)
|
|
326
|
-
if (!!preLoadedFields) {
|
|
327
|
-
const parsedFields = typeof preLoadedFields === 'string' ? safeJsonParse(preLoadedFields, {}) : preLoadedFields;
|
|
328
|
-
if (field.name in parsedFields) {
|
|
329
|
-
return {
|
|
330
|
-
...field,
|
|
331
|
-
// @ts-ignore
|
|
332
|
-
value: parsedFields[field.name],
|
|
333
|
-
};
|
|
334
|
-
}
|
|
103
|
+
else {
|
|
104
|
+
// Fallback: Create a temporary textarea
|
|
105
|
+
const textArea = document.createElement('textarea');
|
|
106
|
+
textArea.value = str;
|
|
107
|
+
document.body.appendChild(textArea);
|
|
108
|
+
textArea.select();
|
|
109
|
+
try {
|
|
110
|
+
document.execCommand('copy');
|
|
335
111
|
}
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
setDynamicFields([]);
|
|
341
|
-
}
|
|
342
|
-
}, [yamlFields, preLoadedFields]);
|
|
343
|
-
useEffect(() => {
|
|
344
|
-
handleFormChange('fields', dynamicFields.map((field) => ({
|
|
345
|
-
key: field.name,
|
|
346
|
-
value: field.value,
|
|
347
|
-
})));
|
|
348
|
-
}, [dynamicFields]);
|
|
349
|
-
useEffect(() => {
|
|
350
|
-
const { logs, metrics, traces } = supportedSignals || {};
|
|
351
|
-
handleFormChange('exportedSignals', {
|
|
352
|
-
logs: logs?.supported || false,
|
|
353
|
-
metrics: metrics?.supported || false,
|
|
354
|
-
traces: traces?.supported || false,
|
|
355
|
-
});
|
|
356
|
-
}, [supportedSignals]);
|
|
357
|
-
const validateForm = (params) => {
|
|
358
|
-
const errors = {};
|
|
359
|
-
let ok = true;
|
|
360
|
-
dynamicFields.forEach(({ name, value, required }) => {
|
|
361
|
-
if (required && !value) {
|
|
362
|
-
ok = false;
|
|
363
|
-
errors[name] = FORM_ALERTS.FIELD_IS_REQUIRED;
|
|
112
|
+
catch (err) {
|
|
113
|
+
console.error('execCommand copy failed:', err);
|
|
114
|
+
}
|
|
115
|
+
document.body.removeChild(textArea);
|
|
364
116
|
}
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
title: params.alertTitle,
|
|
370
|
-
message: FORM_ALERTS.REQUIRED_FIELDS,
|
|
371
|
-
hideFromHistory: true,
|
|
372
|
-
});
|
|
117
|
+
setTimeout(() => {
|
|
118
|
+
setIsCopied(false);
|
|
119
|
+
setCopiedIndex(-1);
|
|
120
|
+
}, 1000);
|
|
373
121
|
}
|
|
374
|
-
handleErrorChange(undefined, undefined, errors);
|
|
375
|
-
return ok;
|
|
376
|
-
};
|
|
377
|
-
const loadFormWithDrawerItem = ({ destinationType: { type }, name, exportedSignals, fields }) => {
|
|
378
|
-
const updatedData = {
|
|
379
|
-
...INITIAL$2,
|
|
380
|
-
type,
|
|
381
|
-
name,
|
|
382
|
-
exportedSignals,
|
|
383
|
-
fields: Object.entries(safeJsonParse(fields, {})).map(([key, value]) => ({ key, value })),
|
|
384
|
-
};
|
|
385
|
-
handleFormChange(undefined, undefined, updatedData);
|
|
386
|
-
};
|
|
387
|
-
return {
|
|
388
|
-
formData,
|
|
389
|
-
formErrors,
|
|
390
|
-
handleFormChange,
|
|
391
|
-
resetFormData,
|
|
392
|
-
validateForm,
|
|
393
|
-
loadFormWithDrawerItem,
|
|
394
|
-
yamlFields,
|
|
395
|
-
setYamlFields,
|
|
396
|
-
dynamicFields,
|
|
397
|
-
setDynamicFields,
|
|
398
122
|
};
|
|
123
|
+
return { isCopied, copiedIndex, clickCopy };
|
|
399
124
|
};
|
|
400
125
|
|
|
401
|
-
const INITIAL
|
|
126
|
+
const INITIAL = {
|
|
402
127
|
ruleName: '',
|
|
403
128
|
notes: '',
|
|
404
129
|
disabled: false,
|
|
@@ -421,7 +146,7 @@ const INITIAL$1 = {
|
|
|
421
146
|
};
|
|
422
147
|
const useInstrumentationRuleFormData = () => {
|
|
423
148
|
const { addNotification } = useNotificationStore();
|
|
424
|
-
const { formData, formErrors, handleFormChange, handleErrorChange, resetFormData } = useGenericForm(INITIAL
|
|
149
|
+
const { formData, formErrors, handleFormChange, handleErrorChange, resetFormData } = useGenericForm(INITIAL);
|
|
425
150
|
const validateForm = (params) => {
|
|
426
151
|
const errors = {};
|
|
427
152
|
let ok = true;
|
|
@@ -430,7 +155,7 @@ const useInstrumentationRuleFormData = () => {
|
|
|
430
155
|
};
|
|
431
156
|
const loadFormWithDrawerItem = ({ ruleName, notes, disabled, payloadCollection, codeAttributes }) => {
|
|
432
157
|
const updatedData = {
|
|
433
|
-
...INITIAL
|
|
158
|
+
...INITIAL,
|
|
434
159
|
ruleName,
|
|
435
160
|
notes,
|
|
436
161
|
disabled,
|
|
@@ -465,222 +190,44 @@ const useInstrumentationRuleFormData = () => {
|
|
|
465
190
|
};
|
|
466
191
|
};
|
|
467
192
|
|
|
468
|
-
const
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
const updatedData = {
|
|
482
|
-
...INITIAL,
|
|
483
|
-
otelServiceName: otelServiceName || name || '',
|
|
193
|
+
const useKeyDown = ({ active, key, withAltKey, withCtrlKey, withShiftKey, withMetaKey }, callback) => {
|
|
194
|
+
useEffect(() => {
|
|
195
|
+
const handleKeyDown = (e) => {
|
|
196
|
+
if (active &&
|
|
197
|
+
key === e.key &&
|
|
198
|
+
(!withAltKey || (withAltKey && e.altKey)) &&
|
|
199
|
+
(!withCtrlKey || (withCtrlKey && e.ctrlKey)) &&
|
|
200
|
+
(!withShiftKey || (withShiftKey && e.shiftKey)) &&
|
|
201
|
+
(!withMetaKey || (withMetaKey && e.metaKey))) {
|
|
202
|
+
e.preventDefault();
|
|
203
|
+
e.stopPropagation();
|
|
204
|
+
callback(e);
|
|
205
|
+
}
|
|
484
206
|
};
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
resetFormData,
|
|
492
|
-
validateForm,
|
|
493
|
-
loadFormWithDrawerItem,
|
|
494
|
-
};
|
|
207
|
+
window.addEventListener('keydown', handleKeyDown);
|
|
208
|
+
return () => {
|
|
209
|
+
window.removeEventListener('keydown', handleKeyDown);
|
|
210
|
+
};
|
|
211
|
+
}, [key, active, withAltKey, withCtrlKey, withShiftKey, withMetaKey, callback]);
|
|
212
|
+
return null;
|
|
495
213
|
};
|
|
496
214
|
|
|
497
|
-
const
|
|
498
|
-
const { namespaces } = useEntityStore();
|
|
499
|
-
const { selectedNamespace, onSelectNamespace, namespace } = params || {};
|
|
500
|
-
// only for "onboarding" - get unsaved values and set to state
|
|
501
|
-
// (this is to persist the values when user navigates back to this page)
|
|
502
|
-
const { configuredSources, configuredFutureApps, availableSources } = useSetupStore();
|
|
503
|
-
// Keeps intial values fetched from API, so we can later filter the user-specific-selections, therebey minimizing the amount of data sent to the API on "persist sources".
|
|
504
|
-
const [recordedInitialSources, setRecordedInitialSources] = useState(availableSources);
|
|
505
|
-
const [selectAllForNamespace, setSelectAllForNamespace] = useState('');
|
|
506
|
-
const [selectedSources, setSelectedSources] = useState(configuredSources);
|
|
507
|
-
const [selectedFutureApps, setSelectedFutureApps] = useState(configuredFutureApps);
|
|
508
|
-
useEffect(() => {
|
|
509
|
-
if (!!namespaces?.length) {
|
|
510
|
-
// initialize all states (to avoid undefined errors)
|
|
511
|
-
setRecordedInitialSources((prev) => {
|
|
512
|
-
const payload = { ...prev };
|
|
513
|
-
namespaces.forEach(({ name }) => (payload[name] = payload[name] || []));
|
|
514
|
-
return payload;
|
|
515
|
-
});
|
|
516
|
-
setSelectedSources((prev) => {
|
|
517
|
-
const payload = { ...prev };
|
|
518
|
-
namespaces.forEach(({ name }) => (payload[name] = payload[name] || []));
|
|
519
|
-
return payload;
|
|
520
|
-
});
|
|
521
|
-
setSelectedFutureApps((prev) => {
|
|
522
|
-
const payload = { ...prev };
|
|
523
|
-
namespaces.forEach(({ name, selected }) => (payload[name] = payload[name] || selected || false));
|
|
524
|
-
return payload;
|
|
525
|
-
});
|
|
526
|
-
}
|
|
527
|
-
}, [namespaces]);
|
|
528
|
-
useEffect(() => {
|
|
529
|
-
if (!!namespace) {
|
|
530
|
-
// initialize sources for this namespace
|
|
531
|
-
const { name, sources = [] } = namespace;
|
|
532
|
-
setRecordedInitialSources((prev) => ({
|
|
533
|
-
...prev,
|
|
534
|
-
[name]: sources.map(({ name, kind, selected, numberOfInstances }) => ({
|
|
535
|
-
name,
|
|
536
|
-
kind,
|
|
537
|
-
selected,
|
|
538
|
-
numberOfInstances,
|
|
539
|
-
})),
|
|
540
|
-
}));
|
|
541
|
-
setSelectedSources((prev) => ({
|
|
542
|
-
...prev,
|
|
543
|
-
[name]: !!prev[name].length
|
|
544
|
-
? prev[name]
|
|
545
|
-
: sources.map(({ name, kind, selected, numberOfInstances }) => ({
|
|
546
|
-
name,
|
|
547
|
-
kind,
|
|
548
|
-
selected,
|
|
549
|
-
numberOfInstances,
|
|
550
|
-
})),
|
|
551
|
-
}));
|
|
552
|
-
}
|
|
553
|
-
}, [namespace]);
|
|
554
|
-
// form filters
|
|
555
|
-
const [searchText, setSearchText] = useState('');
|
|
556
|
-
const [showSelectedOnly, setShowSelectedOnly] = useState(false);
|
|
557
|
-
const onSelectAll = useCallback((selected, ns, selectionsByNamespace) => {
|
|
558
|
-
// When clicking "select all" on a single namespace
|
|
559
|
-
if (!!ns) {
|
|
560
|
-
if (!selectionsByNamespace) {
|
|
561
|
-
// If the sources are not loaded yet, call the onSelectNamespace to load the sources
|
|
562
|
-
onSelectNamespace?.(selected ? ns : '');
|
|
563
|
-
// Set the state, so the interval would be able to use the namespace
|
|
564
|
-
setSelectAllForNamespace(selected ? ns : '');
|
|
565
|
-
}
|
|
566
|
-
else if (!!selectionsByNamespace?.[ns]?.length) {
|
|
567
|
-
// Clear the state, so the interval would stop
|
|
568
|
-
setSelectAllForNamespace('');
|
|
569
|
-
}
|
|
570
|
-
// Set the selected sources
|
|
571
|
-
setSelectedSources((prev) => ({
|
|
572
|
-
...prev,
|
|
573
|
-
[ns]: selectionsByNamespace?.[ns]?.map((source) => ({
|
|
574
|
-
...source,
|
|
575
|
-
selected,
|
|
576
|
-
})) || [],
|
|
577
|
-
}));
|
|
578
|
-
// setSelectedFutureApps((prev) => ({
|
|
579
|
-
// ...prev,
|
|
580
|
-
// [ns]: !!selectionsByNamespace?.[ns]?.length ? selected : false,
|
|
581
|
-
// }))
|
|
582
|
-
}
|
|
583
|
-
// When clicking "select all" on all namespaces
|
|
584
|
-
else {
|
|
585
|
-
setSelectedSources((prev) => {
|
|
586
|
-
const payload = { ...prev };
|
|
587
|
-
Object.entries(payload).forEach(([key, sources]) => {
|
|
588
|
-
payload[key] = sources.map((source) => ({ ...source, selected }));
|
|
589
|
-
});
|
|
590
|
-
return payload;
|
|
591
|
-
});
|
|
592
|
-
}
|
|
593
|
-
}, [selectedSources]);
|
|
594
|
-
// This is to keep trying "select all" per namespace, until the sources are loaded (allows for 1-click, better UX).
|
|
215
|
+
const useOnClickOutside = (ref, handler) => {
|
|
595
216
|
useEffect(() => {
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
}, [selectAllForNamespace, onSelectAll]);
|
|
601
|
-
const onSelectSource = (source, namespace) => {
|
|
602
|
-
const id = namespace || selectedNamespace;
|
|
603
|
-
if (!id)
|
|
604
|
-
return;
|
|
605
|
-
const arr = [...(selectedSources[id] || [])];
|
|
606
|
-
const foundIdx = arr.findIndex(({ name, kind }) => name === source.name && kind === source.kind);
|
|
607
|
-
if (foundIdx !== -1) {
|
|
608
|
-
// Replace the item with a new object to avoid mutating a possibly read-only object
|
|
609
|
-
const updatedItem = { ...arr[foundIdx], selected: !arr[foundIdx].selected };
|
|
610
|
-
arr[foundIdx] = updatedItem;
|
|
611
|
-
}
|
|
612
|
-
else {
|
|
613
|
-
arr.push({ ...source, selected: true });
|
|
614
|
-
}
|
|
615
|
-
setSelectedSources((prev) => ({ ...prev, [id]: arr }));
|
|
616
|
-
};
|
|
617
|
-
const onSelectFutureApps = (bool, namespace) => {
|
|
618
|
-
const id = namespace || selectedNamespace;
|
|
619
|
-
if (!id)
|
|
620
|
-
return;
|
|
621
|
-
setSelectedFutureApps((prev) => ({ ...prev, [id]: bool }));
|
|
622
|
-
};
|
|
623
|
-
const filterNamespaces = (options) => {
|
|
624
|
-
const { cancelSearch } = options || {};
|
|
625
|
-
const namespaces = Object.entries(selectedSources);
|
|
626
|
-
const isSearchOk = (targetText) => cancelSearch || !searchText || targetText.toLowerCase().includes(searchText);
|
|
627
|
-
return namespaces.filter(([namespace]) => isSearchOk(namespace));
|
|
628
|
-
};
|
|
629
|
-
const filterSources = (namespace, options) => {
|
|
630
|
-
const { cancelSearch, cancelSelected } = options || {};
|
|
631
|
-
const id = namespace || selectedNamespace;
|
|
632
|
-
if (!id)
|
|
633
|
-
return [];
|
|
634
|
-
const isSearchOk = (targetText) => cancelSearch || !searchText || targetText.toLowerCase().includes(searchText);
|
|
635
|
-
const isOnlySelectedOk = (sources, compareKey, target) => cancelSelected || !showSelectedOnly || !!sources.find((item) => item[compareKey] === target && item.selected);
|
|
636
|
-
return selectedSources[id].filter((source) => isSearchOk(source.name) && isOnlySelectedOk(selectedSources[id], 'name', source.name));
|
|
637
|
-
};
|
|
638
|
-
// This is to filter the user-specific-selections, therebey minimizing the amount of data sent to the API on "persist sources".
|
|
639
|
-
const getApiSourcesPayload = () => {
|
|
640
|
-
const payload = {};
|
|
641
|
-
Object.entries(selectedSources).forEach(([namespace, sources]) => {
|
|
642
|
-
sources.forEach((source) => {
|
|
643
|
-
const foundInitial = recordedInitialSources[namespace]?.find((initialSource) => initialSource.name === source.name && initialSource.kind === source.kind);
|
|
644
|
-
if (foundInitial?.selected !== source.selected) {
|
|
645
|
-
if (!payload[namespace])
|
|
646
|
-
payload[namespace] = [];
|
|
647
|
-
payload[namespace].push({
|
|
648
|
-
name: source.name,
|
|
649
|
-
kind: source.kind,
|
|
650
|
-
selected: source.selected,
|
|
651
|
-
});
|
|
652
|
-
}
|
|
653
|
-
});
|
|
654
|
-
});
|
|
655
|
-
return payload;
|
|
656
|
-
};
|
|
657
|
-
// This is to filter the user-specific-selections, therebey minimizing the amount of data sent to the API on "persist namespaces".
|
|
658
|
-
const getApiFutureAppsPayload = () => {
|
|
659
|
-
const payload = {};
|
|
660
|
-
Object.entries(selectedFutureApps).forEach(([namespace, selected]) => {
|
|
661
|
-
const foundInitial = namespaces?.find((ns) => ns.name === namespace);
|
|
662
|
-
if (foundInitial?.selected !== selected) {
|
|
663
|
-
payload[namespace] = selected;
|
|
217
|
+
const listener = (event) => {
|
|
218
|
+
// Do nothing if clicking ref's element or descendent elements
|
|
219
|
+
if (!ref.current || ref.current.contains(event.target)) {
|
|
220
|
+
return;
|
|
664
221
|
}
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
selectedSources,
|
|
675
|
-
onSelectSource,
|
|
676
|
-
selectedFutureApps,
|
|
677
|
-
onSelectFutureApps,
|
|
678
|
-
onSelectAll,
|
|
679
|
-
searchText,
|
|
680
|
-
setSearchText,
|
|
681
|
-
showSelectedOnly,
|
|
682
|
-
setShowSelectedOnly,
|
|
683
|
-
};
|
|
222
|
+
handler();
|
|
223
|
+
};
|
|
224
|
+
document.addEventListener('mousedown', listener);
|
|
225
|
+
document.addEventListener('touchstart', listener);
|
|
226
|
+
return () => {
|
|
227
|
+
document.removeEventListener('mousedown', listener);
|
|
228
|
+
document.removeEventListener('touchstart', listener);
|
|
229
|
+
};
|
|
230
|
+
}, [ref, handler]);
|
|
684
231
|
};
|
|
685
232
|
|
|
686
233
|
// Fallback locale.
|
|
@@ -3921,4 +3468,26 @@ const useTimeAgo = () => {
|
|
|
3921
3468
|
return timeAgo;
|
|
3922
3469
|
};
|
|
3923
3470
|
|
|
3924
|
-
|
|
3471
|
+
const useTransition = ({ container, animateIn, animateOut, duration = 300 }) => {
|
|
3472
|
+
const Animated = styled(container) `
|
|
3473
|
+
animation-name: ${({ $isEntering, $isLeaving }) => ($isEntering ? animateIn : $isLeaving ? animateOut : 'none')};
|
|
3474
|
+
animation-duration: ${duration}ms;
|
|
3475
|
+
animation-fill-mode: forwards;
|
|
3476
|
+
`;
|
|
3477
|
+
// !! Do not deprecate this "useCallback" hook, it is necessary for the transition to work properly
|
|
3478
|
+
const Transition = useCallback(({ children, enter, ...props }) => {
|
|
3479
|
+
const [mounted, setMounted] = useState(false);
|
|
3480
|
+
useEffect(() => {
|
|
3481
|
+
const t = setTimeout(() => setMounted(enter), duration + 50); // +50ms to ensure the animation is finished
|
|
3482
|
+
return () => clearTimeout(t);
|
|
3483
|
+
}, [enter, duration]);
|
|
3484
|
+
if (!enter && !mounted)
|
|
3485
|
+
return null;
|
|
3486
|
+
return (React.createElement(Animated, { "$isEntering": enter, "$isLeaving": !enter && mounted, ...props }, children));
|
|
3487
|
+
},
|
|
3488
|
+
// !! Do not add dependencies here, it will cause re-renders which we want to avoid
|
|
3489
|
+
[]);
|
|
3490
|
+
return Transition;
|
|
3491
|
+
};
|
|
3492
|
+
|
|
3493
|
+
export { useCopy as a, useGenericForm as b, useInstrumentationRuleFormData as c, useKeyDown as d, useOnClickOutside as e, useTimeAgo as f, useTransition as g, useContainerSize as u };
|