Skip to content

Commit 95d0eb6

Browse files
authored
Merge pull request #3839 from headlamp-k8s/misc-project-improvements
frontend: Sanitize Projects' names as we type
2 parents 49d307d + 6c6baa0 commit 95d0eb6

File tree

14 files changed

+62
-23
lines changed

14 files changed

+62
-23
lines changed

frontend/src/components/project/NewProjectPopup.tsx

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ function ProjectFromExistingNamespace({ onBack }: { onBack: () => void }) {
105105
const { t } = useTranslation();
106106
const history = useHistory();
107107

108-
const [name, setName] = useState('');
108+
const [projectName, setProjectName] = useState('');
109109
const [selectedClusters, setSelectedClusters] = useState<string[]>([]);
110110
const [selectedNamespace, setSelectedNamespace] = useState<string>();
111111
const [typedNamespace, setTypedNamespace] = useState('');
@@ -118,7 +118,8 @@ function ProjectFromExistingNamespace({ onBack }: { onBack: () => void }) {
118118
clusters: selectedClusters,
119119
});
120120

121-
const isReadyToCreate = selectedClusters.length && (selectedNamespace || typedNamespace) && name;
121+
const isReadyToCreate =
122+
selectedClusters.length && (selectedNamespace || typedNamespace) && projectName;
122123

123124
/**
124125
* Creates or updates namespaces for the proejct
@@ -133,7 +134,7 @@ function ProjectFromExistingNamespace({ onBack }: { onBack: () => void }) {
133134
await maybeExistingNamespace.patch({
134135
metadata: {
135136
labels: {
136-
[PROJECT_ID_LABEL]: toKubernetesName(name),
137+
[PROJECT_ID_LABEL]: projectName,
137138
},
138139
},
139140
});
@@ -145,15 +146,15 @@ function ProjectFromExistingNamespace({ onBack }: { onBack: () => void }) {
145146
metadata: {
146147
name: toKubernetesName(typedNamespace),
147148
labels: {
148-
[PROJECT_ID_LABEL]: toKubernetesName(name),
149+
[PROJECT_ID_LABEL]: projectName,
149150
},
150151
} as any,
151152
} as KubeObjectInterface;
152153
await apply(namespace, cluster);
153154
}
154155
}
155156

156-
history.push(createRouteURL('projectDetails', { name: toKubernetesName(name) }));
157+
history.push(createRouteURL('projectDetails', { name: projectName }));
157158
} catch (e: any) {
158159
setError(e);
159160
} finally {
@@ -184,11 +185,36 @@ function ProjectFromExistingNamespace({ onBack }: { onBack: () => void }) {
184185
</Trans>
185186
</Typography>
186187
<TextField
187-
label={t('Name')}
188-
variant="outlined"
189-
size="small"
190-
value={name}
191-
onChange={e => setName(e.target.value)}
188+
label={t('translation|Project Name')}
189+
value={projectName}
190+
onChange={event => {
191+
const inputValue = event.target.value.toLowerCase();
192+
setProjectName(inputValue);
193+
}}
194+
onBlur={event => {
195+
// Convert to Kubernetes name when user finishes typing (loses focus)
196+
const converted = toKubernetesName(event.target.value);
197+
setProjectName(converted);
198+
}}
199+
onKeyDown={event => {
200+
// Convert spaces to dashes immediately when space is pressed
201+
if (event.key === ' ') {
202+
event.preventDefault();
203+
const target = event.target as HTMLInputElement;
204+
const start = target.selectionStart || 0;
205+
const end = target.selectionEnd || 0;
206+
const currentValue = projectName;
207+
const newValue = currentValue.substring(0, start) + '-' + currentValue.substring(end);
208+
setProjectName(newValue);
209+
// Set cursor position after the inserted dash
210+
setTimeout(() => {
211+
target.setSelectionRange(start + 1, start + 1);
212+
}, 0);
213+
}
214+
}}
215+
helperText={t('translation|Enter a name for your new project.')}
216+
autoComplete="off"
217+
fullWidth
192218
/>
193219
<Autocomplete
194220
fullWidth

frontend/src/components/project/projectUtils.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,8 @@ export const defaultApiResources = (() => {
204204
export const toKubernetesName = (name: string): string => {
205205
const converted = name
206206
.toLowerCase()
207-
.replace(/[^a-z0-9-]/g, '-') // Replace non-alphanumeric chars with dashes
207+
.replace(/\s+/g, '-') // Replace spaces with dashes
208+
.replace(/[^a-z0-9-]/g, '-') // Replace other non-alphanumeric chars with dashes
208209
.replace(/-+/g, '-') // Replace multiple dashes with single dash
209210
.replace(/^-+|-+$/g, '') // Remove leading/trailing dashes
210211
.substring(0, 63); // Ensure max 63 characters for DNS-1123 compliance

frontend/src/i18n/locales/de/translation.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,8 @@
493493
"Preemption Policy": "Preemtions-Policy",
494494
"Create new project": "",
495495
"To create a new project pick which clusters you want to include and then select existing or create a new namespace": "",
496+
"Project Name": "",
497+
"Enter a name for your new project.": "",
496498
"Clusters": "",
497499
"Select one or more clusters for this project": "",
498500
"No available clusters": "",
@@ -515,7 +517,6 @@
515517
"Create new Project from YAML": "",
516518
"Project name": "",
517519
"Give your project a descriptive name": "",
518-
"Project Name": "",
519520
"Enter a name": "",
520521
"Select cluster for this project": "",
521522
"Load resources": "",

frontend/src/i18n/locales/en/translation.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,8 @@
493493
"Preemption Policy": "Preemption Policy",
494494
"Create new project": "Create new project",
495495
"To create a new project pick which clusters you want to include and then select existing or create a new namespace": "To create a new project pick which clusters you want to include and then select existing or create a new namespace",
496+
"Project Name": "Project Name",
497+
"Enter a name for your new project.": "Enter a name for your new project.",
496498
"Clusters": "Clusters",
497499
"Select one or more clusters for this project": "Select one or more clusters for this project",
498500
"No available clusters": "No available clusters",
@@ -515,7 +517,6 @@
515517
"Create new Project from YAML": "Create new Project from YAML",
516518
"Project name": "Project name",
517519
"Give your project a descriptive name": "Give your project a descriptive name",
518-
"Project Name": "Project Name",
519520
"Enter a name": "Enter a name",
520521
"Select cluster for this project": "Select cluster for this project",
521522
"Load resources": "Load resources",

frontend/src/i18n/locales/es/translation.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -496,6 +496,8 @@
496496
"Preemption Policy": "Política de \"Preemption\"",
497497
"Create new project": "",
498498
"To create a new project pick which clusters you want to include and then select existing or create a new namespace": "",
499+
"Project Name": "",
500+
"Enter a name for your new project.": "",
499501
"Clusters": "",
500502
"Select one or more clusters for this project": "",
501503
"No available clusters": "",
@@ -518,7 +520,6 @@
518520
"Create new Project from YAML": "",
519521
"Project name": "",
520522
"Give your project a descriptive name": "",
521-
"Project Name": "",
522523
"Enter a name": "",
523524
"Select cluster for this project": "",
524525
"Load resources": "",

frontend/src/i18n/locales/fr/translation.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -496,6 +496,8 @@
496496
"Preemption Policy": "Politique de préemption",
497497
"Create new project": "",
498498
"To create a new project pick which clusters you want to include and then select existing or create a new namespace": "",
499+
"Project Name": "",
500+
"Enter a name for your new project.": "",
499501
"Clusters": "",
500502
"Select one or more clusters for this project": "",
501503
"No available clusters": "",
@@ -518,7 +520,6 @@
518520
"Create new Project from YAML": "",
519521
"Project name": "",
520522
"Give your project a descriptive name": "",
521-
"Project Name": "",
522523
"Enter a name": "",
523524
"Select cluster for this project": "",
524525
"Load resources": "",

frontend/src/i18n/locales/hi/translation.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,8 @@
493493
"Preemption Policy": "",
494494
"Create new project": "",
495495
"To create a new project pick which clusters you want to include and then select existing or create a new namespace": "",
496+
"Project Name": "",
497+
"Enter a name for your new project.": "",
496498
"Clusters": "",
497499
"Select one or more clusters for this project": "",
498500
"No available clusters": "",
@@ -515,7 +517,6 @@
515517
"Create new Project from YAML": "",
516518
"Project name": "",
517519
"Give your project a descriptive name": "",
518-
"Project Name": "",
519520
"Enter a name": "",
520521
"Select cluster for this project": "",
521522
"Load resources": "",

frontend/src/i18n/locales/it/translation.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -496,6 +496,8 @@
496496
"Preemption Policy": "Politica di Preemption",
497497
"Create new project": "",
498498
"To create a new project pick which clusters you want to include and then select existing or create a new namespace": "",
499+
"Project Name": "",
500+
"Enter a name for your new project.": "",
499501
"Clusters": "",
500502
"Select one or more clusters for this project": "",
501503
"No available clusters": "",
@@ -518,7 +520,6 @@
518520
"Create new Project from YAML": "",
519521
"Project name": "",
520522
"Give your project a descriptive name": "",
521-
"Project Name": "",
522523
"Enter a name": "",
523524
"Select cluster for this project": "",
524525
"Load resources": "",

frontend/src/i18n/locales/ja/translation.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -490,6 +490,8 @@
490490
"Preemption Policy": "プリエンプションポリシー",
491491
"Create new project": "",
492492
"To create a new project pick which clusters you want to include and then select existing or create a new namespace": "",
493+
"Project Name": "",
494+
"Enter a name for your new project.": "",
493495
"Clusters": "",
494496
"Select one or more clusters for this project": "",
495497
"No available clusters": "",
@@ -512,7 +514,6 @@
512514
"Create new Project from YAML": "",
513515
"Project name": "",
514516
"Give your project a descriptive name": "",
515-
"Project Name": "",
516517
"Enter a name": "",
517518
"Select cluster for this project": "",
518519
"Load resources": "",

frontend/src/i18n/locales/ko/translation.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -490,6 +490,8 @@
490490
"Preemption Policy": "선점 정책",
491491
"Create new project": "",
492492
"To create a new project pick which clusters you want to include and then select existing or create a new namespace": "",
493+
"Project Name": "",
494+
"Enter a name for your new project.": "",
493495
"Clusters": "",
494496
"Select one or more clusters for this project": "",
495497
"No available clusters": "",
@@ -512,7 +514,6 @@
512514
"Create new Project from YAML": "",
513515
"Project name": "",
514516
"Give your project a descriptive name": "",
515-
"Project Name": "",
516517
"Enter a name": "",
517518
"Select cluster for this project": "",
518519
"Load resources": "",

0 commit comments

Comments
 (0)