Skip to content

Commit c45a394

Browse files
committed
feat: [PROD-14255] add datasets renaming in dataset manager
1 parent a2d875d commit c45a394

File tree

8 files changed

+163
-6
lines changed

8 files changed

+163
-6
lines changed

public/locales/en/translation.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,8 @@
183183
"deleteButtonTooltip": "Delete",
184184
"shareButtonTooltip": "Share",
185185
"refreshButtonTooltip": "Refresh",
186+
"renameButtonTooltip": "Rename",
187+
"emptyDatasetNameError": "Dataset name cannot be empty",
186188
"createSubdatasetButtonTooltip": "Create sub-dataset",
187189
"editParametersButtonTooltip": "Edit parameters of the dataset"
188190
},

public/locales/fr/translation.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,8 @@
183183
"deleteButtonTooltip": "Supprimer",
184184
"shareButtonTooltip": "Partager",
185185
"refreshButtonTooltip": "Mettre à jour",
186+
"renameButtonTooltip": "Renommer",
187+
"emptyDatasetNameError": "Le nom du dataset ne doit pas être vide",
186188
"createSubdatasetButtonTooltip": "Créer un sous-dataset",
187189
"editParametersButtonTooltip": "Modifier les paramètres du dataset"
188190
},

src/views/DatasetManager/components/DatasetOverview/DatasetOverview.js

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,11 @@ import React, { useMemo } from 'react';
44
import { Card, CardContent, CardHeader, Grid } from '@mui/material';
55
import { INGESTION_STATUS } from '../../../../services/config/ApiConstants';
66
import { useDatasetOverview } from './DatasetOverviewHook';
7-
import { CategoryAccordion, DatasetOverviewPlaceholder, GraphIndicator } from './components';
7+
import { CategoryAccordion, DatasetOverviewPlaceholder, EditableDatasetName, GraphIndicator } from './components';
88
import DatasetActions from './components/DatasetActions/DatasetActions';
99

1010
export const DatasetOverview = () => {
11-
const { categories, graphIndicators, queriesResults, datasetIngestionStatus, dataset, datasetName } =
12-
useDatasetOverview();
11+
const { categories, graphIndicators, queriesResults, datasetIngestionStatus, dataset } = useDatasetOverview();
1312

1413
const showPlaceholder = useMemo(
1514
() =>
@@ -24,15 +23,15 @@ export const DatasetOverview = () => {
2423
});
2524
}, [graphIndicators, queriesResults]);
2625

26+
const editableDatasetName = <EditableDatasetName />;
2727
return (
2828
<Card
2929
elevation={0}
3030
sx={{ p: 1, width: '100%', height: '100%', overflow: 'auto', backgroundColor: 'transparent' }}
3131
data-cy="dataset-overview-card"
3232
>
3333
<CardHeader
34-
data-cy="dataset-name"
35-
title={datasetName}
34+
title={editableDatasetName}
3635
sx={{ height: '65px' }}
3736
action={<DatasetActions dataset={dataset}></DatasetActions>}
3837
></CardHeader>

src/views/DatasetManager/components/DatasetOverview/DatasetOverviewHook.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,5 @@ export const useDatasetOverview = () => {
4646
queriesResults,
4747
datasetIngestionStatus,
4848
dataset: currentDataset,
49-
datasetName: currentDataset?.name,
5049
};
5150
};
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
// Copyright (c) Cosmo Tech.
2+
// Licensed under the MIT license.
3+
import React, { useEffect, useMemo, useState } from 'react';
4+
import { useTranslation } from 'react-i18next';
5+
import { Edit as EditIcon } from '@mui/icons-material';
6+
import { FormControl, FormHelperText, IconButton, OutlinedInput, Stack, Typography } from '@mui/material';
7+
import { FadingTooltip, PermissionsGate } from '@cosmotech/ui';
8+
import { ACL_PERMISSIONS } from '../../../../../../services/config/accessControl';
9+
import { useEditableDatasetName } from './EditableDatasetNameHook';
10+
11+
const sanitizeValue = (value) => value.trim();
12+
13+
export const EditableDatasetName = () => {
14+
const { t } = useTranslation();
15+
const { dataset, datasetName, renameDataset } = useEditableDatasetName();
16+
17+
const [error, setError] = useState(null);
18+
const [isEditing, setEditing] = useState(false);
19+
const [textFieldValue, setTextFieldValue] = useState(datasetName ?? '');
20+
21+
useEffect(() => {
22+
setTextFieldValue(datasetName);
23+
}, [datasetName]);
24+
25+
const startEdition = (event) => {
26+
event.stopPropagation();
27+
event.preventDefault();
28+
setEditing(true);
29+
};
30+
31+
const editableTextField = useMemo(() => {
32+
const stopEdition = (event) => {
33+
event && event.stopPropagation();
34+
setEditing(false);
35+
setError(null);
36+
};
37+
38+
const cancelEdition = (event) => {
39+
setTextFieldValue(datasetName);
40+
stopEdition(event);
41+
};
42+
43+
const confirmChanges = (event) => {
44+
const sanitizedValue = sanitizeValue(event.target.value);
45+
if (error == null && sanitizedValue.length !== 0 && sanitizedValue !== datasetName) {
46+
renameDataset(sanitizedValue);
47+
setTextFieldValue(sanitizedValue);
48+
} else setTextFieldValue(datasetName);
49+
50+
stopEdition(event);
51+
};
52+
53+
const processNewValue = (event) => {
54+
const newValue = event.target.value;
55+
setTextFieldValue(newValue);
56+
57+
const sanitizedValue = sanitizeValue(newValue);
58+
if (sanitizedValue.length !== 0) setError(null);
59+
else
60+
setError(
61+
t('commoncomponents.datasetmanager.overview.actions.emptyDatasetNameError', 'Dataset name cannot be empty')
62+
);
63+
};
64+
65+
return (
66+
<FormControl data-cy="dataset-name-editable-text-field">
67+
<OutlinedInput
68+
autoFocus
69+
value={textFieldValue}
70+
error={error != null}
71+
onChange={processNewValue}
72+
onBlur={confirmChanges}
73+
onClick={(event) => event.stopPropagation()}
74+
onKeyDown={(event) => {
75+
if (event.key === 'Escape') cancelEdition(event);
76+
else if (event.key === 'Enter') confirmChanges(event);
77+
}}
78+
onFocus={(event) => event.stopPropagation()}
79+
size="small"
80+
sx={{ minWidth: '400px', marginLeft: 0.5, padding: 0.5 }}
81+
/>
82+
<FormHelperText error>{error}</FormHelperText>
83+
</FormControl>
84+
);
85+
}, [datasetName, error, renameDataset, setTextFieldValue, t, textFieldValue]);
86+
87+
const datasetNameElement = useMemo(
88+
() => (
89+
<Typography data-cy="dataset-name" variant="h6">
90+
{datasetName}
91+
</Typography>
92+
),
93+
[datasetName]
94+
);
95+
96+
const datasetNameWithEditButton = useMemo(() => {
97+
return (
98+
<Stack direction="row" spacing={1} alignItems="stretch" justifyContent="flex-start">
99+
{datasetNameElement}
100+
<FadingTooltip
101+
title={t('commoncomponents.datasetmanager.overview.actions.renameButtonTooltip', 'Rename')}
102+
disableInteractive={true}
103+
>
104+
<IconButton onClick={startEdition} data-cy="rename-dataset-button">
105+
<EditIcon color="primary" />
106+
</IconButton>
107+
</FadingTooltip>
108+
</Stack>
109+
);
110+
}, [datasetNameElement, t]);
111+
112+
const userPermissions = dataset?.security?.currentUserPermissions ?? [];
113+
return (
114+
<PermissionsGate
115+
userPermissions={userPermissions}
116+
necessaryPermissions={[ACL_PERMISSIONS.DATASET.WRITE]}
117+
RenderNoPermissionComponent={() => datasetNameElement}
118+
>
119+
{isEditing ? editableTextField : datasetNameWithEditButton}
120+
</PermissionsGate>
121+
);
122+
};
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Copyright (c) Cosmo Tech.
2+
// Licensed under the MIT license.
3+
import { useCallback } from 'react';
4+
import {
5+
useCurrentDataset,
6+
useSelectedDatasetIndex,
7+
useUpdateDataset,
8+
} from '../../../../../../state/hooks/DatasetHooks';
9+
10+
export const useEditableDatasetName = () => {
11+
const currentDataset = useCurrentDataset();
12+
const selectedDatasetIndex = useSelectedDatasetIndex();
13+
const updateDataset = useUpdateDataset();
14+
15+
const renameDataset = useCallback(
16+
(newDatasetName) => {
17+
if (!currentDataset) return;
18+
updateDataset(currentDataset.id, { name: newDatasetName }, selectedDatasetIndex);
19+
},
20+
[currentDataset, selectedDatasetIndex, updateDataset]
21+
);
22+
23+
return {
24+
dataset: currentDataset,
25+
datasetName: currentDataset?.name,
26+
renameDataset,
27+
};
28+
};
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// Copyright (c) Cosmo Tech.
2+
// Licensed under the MIT license.
3+
4+
export { EditableDatasetName } from './EditableDatasetName';

src/views/DatasetManager/components/DatasetOverview/components/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@
44
export { default as GraphIndicator } from './GraphIndicator';
55
export { default as CategoryAccordion } from './CategoryAccordion';
66
export { DatasetOverviewPlaceholder } from './DatasetOverviewPlaceholder';
7+
export { EditableDatasetName } from './EditableDatasetName';

0 commit comments

Comments
 (0)