Skip to content

Commit 06196ac

Browse files
committed
show type always
1 parent b3e40fa commit 06196ac

File tree

4 files changed

+241
-172
lines changed

4 files changed

+241
-172
lines changed

src/components/dagshub/data-engine/metadataKeyValue/MetadataKeyValueList.tsx

+158-121
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1-
import React, { useEffect, useRef, useState } from 'react';
1+
import React, {useEffect, useMemo, useRef, useState} from 'react';
22
import Box from '@mui/material/Box';
3-
import { MetadataKeyValuePair } from './MetadataKeyValuePair';
3+
import {MetadataKeyValuePair} from './MetadataKeyValuePair';
44
import StyledTextField from './StyledTextField';
55
import IconButton from '@mui/material/IconButton';
66
import AddIcon from '@mui/icons-material/Add';
7-
import { Button, ButtonStretch, ButtonVariant } from '../../../elements';
7+
import {Button, ButtonStretch, ButtonVariant} from '../../../elements';
8+
import theme from "../../../../theme";
9+
import {ThemeProvider} from "@mui/material";
810

911
export type MetadataType = 'BOOLEAN' | 'INTEGER' | 'FLOAT' | 'STRING' | 'BLOB';
1012

@@ -16,6 +18,7 @@ export interface NewMetadataField {
1618
multiple?: boolean;
1719
isAutoGenerated?: boolean;
1820
isNewlyCreated?: boolean;
21+
editInProgress?: boolean;
1922
}
2023

2124
//The format the component expects to receive the metadata list
@@ -46,12 +49,12 @@ export interface MetadataKeyValueListProps {
4649
}
4750

4851
export function MetadataKeyValueList({
49-
maxHeight,
50-
metadataList,
51-
onDeleteHandler,
52-
onSaveHandler,
53-
validateValueByType,
54-
}: MetadataKeyValueListProps) {
52+
maxHeight,
53+
metadataList,
54+
onDeleteHandler,
55+
onSaveHandler,
56+
validateValueByType,
57+
}: MetadataKeyValueListProps) {
5558
//Todo:
5659
// - Not sure what to do with the multiple field. (If I need to use it as part of the validations in the future, and also what value should I set for newly created fields).
5760
// - Validations that are missing:
@@ -73,7 +76,7 @@ export function MetadataKeyValueList({
7376

7477
const checkIfTemporaryMetadataListIsEqualToOriginalMetadataList = () => {
7578
//Compare the fields - if isNewlyCreated is undefined and all the rest are the same, it means its equal, if there is metadat with isNewlyCreated true, its not equal
76-
if(temporaryMetadataList.length !== metadataList.length) return false;
79+
if (temporaryMetadataList.length !== metadataList.length) return false;
7780
return temporaryMetadataList.every((tempField, index) => {
7881
const originalField = metadataList[index];
7982
return (
@@ -86,9 +89,45 @@ export function MetadataKeyValueList({
8689
});
8790
}
8891

89-
useEffect(()=>{
90-
setShowButtonsSection(!checkIfTemporaryMetadataListIsEqualToOriginalMetadataList());
91-
},[temporaryMetadataList, metadataList])
92+
const checkIfThereAreEmptyFields = () => {
93+
return temporaryMetadataList.some((field) => {
94+
return (
95+
field.key === undefined ||
96+
field.key == '' ||
97+
field.valueType === undefined ||
98+
((field.value === undefined || field.value === '') && field.valueType !== "STRING")
99+
);
100+
});
101+
}
102+
103+
const checkIfThereAreInvalidFields = () => {
104+
return temporaryMetadataList.some((field) => {
105+
if (!!validateValueByType) {
106+
return (
107+
field.valueType !== undefined &&
108+
field.value !== undefined &&
109+
!validateValueByType(field.valueType, field.value)
110+
);
111+
}
112+
return false;
113+
});
114+
}
115+
116+
const checkIfThereAreFieldsThatAreStillBeingEdited = () => {
117+
return temporaryMetadataList.some((field) => {
118+
return field.editInProgress;
119+
});
120+
}
121+
122+
const disableSaveButton = useMemo(() => {
123+
if (checkIfThereAreEmptyFields() || checkIfThereAreInvalidFields() || checkIfThereAreFieldsThatAreStillBeingEdited()) {
124+
return true;
125+
}
126+
}, [temporaryMetadataList, validateValueByType]);
127+
128+
useEffect(() => {
129+
setShowButtonsSection(!checkIfTemporaryMetadataListIsEqualToOriginalMetadataList() || checkIfThereAreFieldsThatAreStillBeingEdited());
130+
}, [temporaryMetadataList, metadataList])
92131

93132
useEffect(() => {
94133
setTemporaryMetadataList([...metadataList]);
@@ -129,25 +168,12 @@ export function MetadataKeyValueList({
129168
}
130169
}, [shouldHighlightEmptyFields]);
131170

132-
const CheckIfEmptyFieldsAndHighlightThem = () => {
133-
const hasEmptyFields = temporaryMetadataList.some((field) => {
134-
return (
135-
field.key === undefined ||
136-
field.key == '' ||
137-
field.value === undefined ||
138-
field.value === '' ||
139-
field.valueType === undefined
140-
);
141-
});
142-
143-
setShouldHighlightEmptyFields(hasEmptyFields);
144-
return hasEmptyFields;
145-
};
146-
147171
const handleAddNew = () => {
148172
setShouldScrollToBottom(true); //scroll to button when clicking on the + button
149-
const hasEmptyFields = CheckIfEmptyFieldsAndHighlightThem();
150-
if (!hasEmptyFields) {
173+
const hasEmptyFields = checkIfThereAreEmptyFields();
174+
setShouldHighlightEmptyFields(hasEmptyFields);
175+
176+
if (!hasEmptyFields && !checkIfThereAreInvalidFields()) {
151177
//if there are no empty fields, add new field
152178
const newField: NewMetadataField = {
153179
key: undefined,
@@ -167,23 +193,31 @@ export function MetadataKeyValueList({
167193
}
168194
setTemporaryMetadataList((prevList) => {
169195
const newList = [...prevList];
170-
newList[index] = { ...newList[index], key: newKey };
196+
newList[index] = {...newList[index], key: newKey, editInProgress: false};
171197
return newList;
172198
});
173199
};
174200

175201
const locallyEditValueAtIndex = (index: number, newValue: string | undefined) => {
176202
setTemporaryMetadataList((prevList) => {
177203
const newList = [...prevList];
178-
newList[index] = { ...newList[index], value: newValue };
204+
newList[index] = {...newList[index], value: newValue, editInProgress: false};
205+
return newList;
206+
});
207+
};
208+
209+
const setMetadataFieldStatusAsEditInProgress = (index: number) => {
210+
setTemporaryMetadataList((prevList) => {
211+
const newList = [...prevList];
212+
newList[index] = {...newList[index], editInProgress: true};
179213
return newList;
180214
});
181215
};
182216

183217
const locallyEditValueTypeAtIndex = (index: number, newType: MetadataType | undefined) => {
184218
setTemporaryMetadataList((prevList) => {
185219
const newList = [...prevList];
186-
newList[index] = { ...newList[index], valueType: newType };
220+
newList[index] = {...newList[index], valueType: newType};
187221
return newList;
188222
});
189223
};
@@ -206,7 +240,8 @@ export function MetadataKeyValueList({
206240
const newList = prevList.filter((_, index) => index !== indexToRemove);
207241
return newList;
208242
});
209-
} catch (e) {}
243+
} catch (e) {
244+
}
210245
}
211246
};
212247

@@ -230,103 +265,105 @@ export function MetadataKeyValueList({
230265
};
231266

232267
return (
233-
<Box
234-
sx={{
235-
display: 'flex',
236-
flexDirection: 'column',
237-
height: '100%',
238-
maxHeight: maxHeight ?? '100%',
239-
overflowX: 'hidden',
240-
}}
241-
>
268+
<ThemeProvider theme={theme}>
242269
<Box
243-
ref={metadataFieldsSection}
244270
sx={{
245271
display: 'flex',
246272
flexDirection: 'column',
247273
height: '100%',
248-
maxHeight: '100%',
249-
overflowY: 'auto',
274+
maxHeight: maxHeight ?? '100%',
250275
overflowX: 'hidden',
251276
}}
252277
>
253-
{temporaryMetadataList.map((metadataField, index) => (
254-
<MetadataKeyValuePair
255-
{...metadataField}
256-
index={index}
257-
keyName={metadataField.key}
258-
value={String(metadataField.value)}
259-
isEditable={!!onSaveHandler && !metadataField.isAutoGenerated}
260-
description={metadataField.isAutoGenerated ? 'Auto-generated' : undefined}
261-
isRemovable={checkIfPairIsRemovable(metadataField)}
262-
saveKeyNameLocally={locallyEditKeyAtIndex}
263-
saveValueTypeLocally={locallyEditValueTypeAtIndex}
264-
saveValueLocally={locallyEditValueAtIndex}
265-
shouldHighlightEmptyFields={shouldHighlightEmptyFields}
266-
deleteFieldPermanently={
267-
metadataField.isNewlyCreated
268-
? locallyRemoveMetadataFieldByIndex
269-
: permanentlyDeleteMetadataFieldByIndex
270-
}
271-
autoFocusKey={metadataField.isNewlyCreated && autoFocusNewlyCreatedFieldKey}
272-
validateValueByType={validateValueByType}
273-
/>
274-
))}
275-
</Box>
276-
{!!onSaveHandler && (
277-
<>
278-
<StyledTextField
279-
onClick={handleAddNew}
280-
sx={{
281-
borderBottom: '1px solid #E2E8F0',
282-
borderRadius: 0,
283-
}}
284-
focusModeDisabled
285-
changeColorOnHover
286-
InputProps={{
287-
sx: { input: { cursor: 'pointer!important' } },
288-
readOnly: true,
289-
endAdornment: (
290-
<IconButton>
291-
<AddIcon />
292-
</IconButton>
293-
),
294-
}}
295-
value={'Add new'}
296-
/>
297-
{showButtonsSection && <Box
298-
sx={{
299-
padding: '16px',
300-
display: 'flex',
301-
width: '100%',
302-
gap: '8px',
303-
justifyContent: 'flex-end',
304-
}}
305-
>
306-
<Button
307-
variant={ButtonVariant.Secondary}
308-
style={{ borderRadius: '8px' }}
309-
label={'Cancel'}
310-
stretch={ButtonStretch.Slim}
311-
onClick={() => {
312-
// onResetChanges();
313-
//Todo: implement
314-
}}
278+
<Box
279+
ref={metadataFieldsSection}
280+
sx={{
281+
display: 'flex',
282+
flexDirection: 'column',
283+
height: '100%',
284+
maxHeight: '100%',
285+
overflowY: 'auto',
286+
overflowX: 'hidden',
287+
}}
288+
>
289+
{temporaryMetadataList.map((metadataField, index) => (
290+
<MetadataKeyValuePair
291+
{...metadataField}
292+
index={index}
293+
keyName={metadataField.key}
294+
value={String(metadataField.value)}
295+
isEditable={!!onSaveHandler && !metadataField.isAutoGenerated}
296+
description={metadataField.isAutoGenerated ? `Auto-generated` : undefined}
297+
isRemovable={checkIfPairIsRemovable(metadataField)}
298+
saveKeyNameLocally={locallyEditKeyAtIndex}
299+
saveValueTypeLocally={locallyEditValueTypeAtIndex}
300+
saveValueLocally={locallyEditValueAtIndex}
301+
markFieldStatusAsEditInProgress={setMetadataFieldStatusAsEditInProgress}
302+
shouldHighlightEmptyFields={shouldHighlightEmptyFields}
303+
deleteFieldPermanently={
304+
metadataField.isNewlyCreated
305+
? locallyRemoveMetadataFieldByIndex
306+
: permanentlyDeleteMetadataFieldByIndex
307+
}
308+
autoFocusKey={metadataField.isNewlyCreated && autoFocusNewlyCreatedFieldKey}
309+
validateValueByType={validateValueByType}
315310
/>
316-
<Button
317-
style={{ borderRadius: '8px' }}
318-
label={'Save'}
319-
stretch={ButtonStretch.Slim}
320-
disabled={false} //Todo
321-
onClick={() => {
322-
onSaveHandler(
323-
convertNewMetadataFieldToDatapointMetadataInput(temporaryMetadataList)
324-
);
311+
))}
312+
</Box>
313+
{!!onSaveHandler && (
314+
<>
315+
<StyledTextField
316+
onClick={handleAddNew}
317+
sx={{
318+
borderBottom: '1px solid #E2E8F0',
319+
borderRadius: 0,
320+
}}
321+
focusModeDisabled
322+
changeColorOnHover
323+
InputProps={{
324+
sx: {input: {cursor: 'pointer!important'}},
325+
readOnly: true,
326+
endAdornment: (
327+
<IconButton>
328+
<AddIcon/>
329+
</IconButton>
330+
),
325331
}}
332+
value={'Add new'}
326333
/>
327-
</Box>}
328-
</>
329-
)}
330-
</Box>
334+
{showButtonsSection && <Box
335+
sx={{
336+
padding: '16px',
337+
display: 'flex',
338+
width: '100%',
339+
gap: '8px',
340+
justifyContent: 'flex-end',
341+
}}
342+
>
343+
<Button
344+
variant={ButtonVariant.Secondary}
345+
style={{borderRadius: '8px'}}
346+
label={'Cancel'}
347+
stretch={ButtonStretch.Slim}
348+
onClick={() => {
349+
setTemporaryMetadataList([...metadataList]);
350+
}}
351+
/>
352+
<Button
353+
style={{borderRadius: '8px'}}
354+
label={'Save'}
355+
stretch={ButtonStretch.Slim}
356+
disabled={disableSaveButton}
357+
onClick={() => {
358+
onSaveHandler(
359+
convertNewMetadataFieldToDatapointMetadataInput(temporaryMetadataList)
360+
);
361+
}}
362+
/>
363+
</Box>}
364+
</>
365+
)}
366+
</Box>
367+
</ThemeProvider>
331368
);
332369
}

0 commit comments

Comments
 (0)