Skip to content

Commit

Permalink
frontend: Add create namespace ui
Browse files Browse the repository at this point in the history
Signed-off-by: Vincent T <[email protected]>
  • Loading branch information
vyncent-t committed May 21, 2024
1 parent 17f6e7b commit 58bbf86
Show file tree
Hide file tree
Showing 7 changed files with 217 additions and 7 deletions.
161 changes: 161 additions & 0 deletions frontend/src/components/namespace/CreateNamespaceButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
import {
Box,
Button,
Dialog,
DialogActions,
DialogContent,
DialogTitle,
TextField,
} from '@mui/material';
import React, { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useDispatch } from 'react-redux';
import { getCluster } from '../../lib/cluster';
import { post } from '../../lib/k8s/apiProxy';
import Namespace from '../../lib/k8s/namespace';
import { clusterAction } from '../../redux/clusterActionSlice';
import { EventStatus, HeadlampEventType, useEventCallback } from '../../redux/headlampEventSlice';
import { ActionButton, AuthVisible } from '../common';

export function CreateNamespaceButton() {
const { t } = useTranslation(['glossary', 'translation']);
const [namespaceName, setNamespaceName] = useState('');
const [namespaceDialogOpen, setNamespaceDialogOpen] = useState(false);
const dispatchCreateEvent = useEventCallback(HeadlampEventType.CREATE_RESOURCE);
const dispatch = useDispatch();

function createNewNamespace() {
function validateNamespaceName(namespaceName: string) {
const namespaceRegex = /^[a-z]([-a-z0-9]*[a-z0-9])?$/;

// Check if the namespace name is too long
if (namespaceName.length > 63) {
alert(t('translation|Invalid namespace name: name must be 63 characters or shorter'));
return false;
}

// Check if the namespace name starts with a lowercase letter
const startsLowercase = /^[a-z]/.test(namespaceName);
if (!startsLowercase) {
alert(t('translation|Invalid namespace name: name must start with a lowercase letter'));
return false;
}

// Check if the namespace name ends with an alphanumeric character
const endsAlphanumeric = /[a-z0-9]$/.test(namespaceName);
if (!endsAlphanumeric) {
alert(
t('translation|Invalid namespace name: name must end with an alphanumeric character')
);
return false;
}

// Check if the namespace name contains only lowercase letters, numbers, or hyphens
const validChars = namespaceRegex.test(namespaceName);
if (!validChars) {
alert(
t(
'translation|Invalid namespace name: name must consist of lower case alphanumeric characters or -'
)
);
return false;
}

return true;
}

if (!validateNamespaceName(namespaceName)) {
return;
}

const cluster = getCluster();
const newNamespaceData = {
apiVersion: 'v1',
kind: 'Namespace',
metadata: {
name: namespaceName,
},
};
const newNamespaceName = newNamespaceData.metadata.name;

async function namespaceRequest() {
try {
const response = await post('/api/v1/namespaces', newNamespaceData, true, {
cluster: `${cluster}`,
});
return response;
} catch (error) {
console.error('Error creating namespace', error);
throw error;
}
}

setNamespaceDialogOpen(false);
dispatch(
clusterAction(() => namespaceRequest(), {
startMessage: t('translation|Creating namespace {{ name }}…', { name: newNamespaceName }),
cancelledMessage: t('translation|Cancelled creation of {{ name }}.', {
name: newNamespaceName,
}),
successMessage: t('translation|Created namespace {{ name }}.', {
name: newNamespaceName,
}),
errorMessage: t('translation|Error creating namespace {{ name }}.', {
name: newNamespaceName,
}),
cancelCallback: () => {
setNamespaceDialogOpen(true);
},
})
);
}

return (
<AuthVisible item={Namespace} authVerb="create">
<ActionButton
color="primary"
description={t('translation|Create')}
icon={'mdi:plus-circle'}
onClick={() => {
setNamespaceDialogOpen(true);
}}
/>

<Dialog open={namespaceDialogOpen} onClose={() => setNamespaceDialogOpen(false)}>
<DialogTitle>{t('translation|Create Namespace')}</DialogTitle>
<DialogContent>
<Box component="form" style={{ width: '20vw', maxWidth: '20vw' }}>
<TextField
margin="dense"
id="name"
label={t('translation|Name')}
type="text"
fullWidth
value={namespaceName}
onChange={event => setNamespaceName(event.target.value)}
/>
</Box>
</DialogContent>
<DialogActions>
<Button
onClick={() => {
setNamespaceDialogOpen(false);
}}
>
{t('translation|Cancel')}
</Button>
<Button
onClick={() => {
createNewNamespace();
dispatchCreateEvent({
status: EventStatus.CONFIRMED,
});
}}
>
{t('translation|Create')}
</Button>
</DialogActions>
</Dialog>
</AuthVisible>
);
}
18 changes: 11 additions & 7 deletions frontend/src/components/namespace/List.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
ResourceTableFromResourceClassProps,
ResourceTableProps,
} from '../common/Resource/ResourceTable';
import { CreateNamespaceButton } from './CreateNamespaceButton';

export default function NamespacesList() {
const { t } = useTranslation(['glossary', 'translation']);
Expand Down Expand Up @@ -88,12 +89,15 @@ export default function NamespacesList() {
}, [allowedNamespaces]);

return (
<ResourceListView
title={t('Namespaces')}
headerProps={{
noNamespaceFilter: true,
}}
{...resourceTableProps}
/>
<>
<ResourceListView
title={t('Namespaces')}
headerProps={{
titleSideActions: [<CreateNamespaceButton />],
noNamespaceFilter: true,
}}
{...resourceTableProps}
/>
</>
);
}
9 changes: 9 additions & 0 deletions frontend/src/i18n/locales/de/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,15 @@
"Default Request": "Standardanforderung",
"Max": "Max",
"Min": "Min",
"Invalid namespace name: name must be 63 characters or shorter": "",
"Invalid namespace name: name must start with a lowercase letter": "",
"Invalid namespace name: name must end with an alphanumeric character": "",
"Invalid namespace name: name must consist of lower case alphanumeric characters or -": "",
"Creating namespace {{ name }}…": "",
"Cancelled creation of {{ name }}.": "",
"Created namespace {{ name }}.": "",
"Error creating namespace {{ name }}.": "",
"Create Namespace": "",
"To": "An",
"used": "benutzt",
"Scheduling Disabled": "Planung deaktiviert",
Expand Down
9 changes: 9 additions & 0 deletions frontend/src/i18n/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,15 @@
"Default Request": "Default Request",
"Max": "Max",
"Min": "Min",
"Invalid namespace name: name must be 63 characters or shorter": "Invalid namespace name: name must be 63 characters or shorter",
"Invalid namespace name: name must start with a lowercase letter": "Invalid namespace name: name must start with a lowercase letter",
"Invalid namespace name: name must end with an alphanumeric character": "Invalid namespace name: name must end with an alphanumeric character",
"Invalid namespace name: name must consist of lower case alphanumeric characters or -": "Invalid namespace name: name must consist of lower case alphanumeric characters or -",
"Creating namespace {{ name }}…": "Creating namespace {{ name }}…",
"Cancelled creation of {{ name }}.": "Cancelled creation of {{ name }}.",
"Created namespace {{ name }}.": "Created namespace {{ name }}.",
"Error creating namespace {{ name }}.": "Error creating namespace {{ name }}.",
"Create Namespace": "Create Namespace",
"To": "To",
"used": "used",
"Scheduling Disabled": "Scheduling Disabled",
Expand Down
9 changes: 9 additions & 0 deletions frontend/src/i18n/locales/es/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,15 @@
"Default Request": "Solicitud por defecto",
"Max": "Máx.",
"Min": "Mín.",
"Invalid namespace name: name must be 63 characters or shorter": "",
"Invalid namespace name: name must start with a lowercase letter": "",
"Invalid namespace name: name must end with an alphanumeric character": "",
"Invalid namespace name: name must consist of lower case alphanumeric characters or -": "",
"Creating namespace {{ name }}…": "",
"Cancelled creation of {{ name }}.": "",
"Created namespace {{ name }}.": "",
"Error creating namespace {{ name }}.": "",
"Create Namespace": "",
"To": "A",
"used": "usado",
"Scheduling Disabled": "Agendamiento deshabilitado",
Expand Down
9 changes: 9 additions & 0 deletions frontend/src/i18n/locales/fr/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,15 @@
"Default Request": "Demande par défaut",
"Max": "Max",
"Min": "Min",
"Invalid namespace name: name must be 63 characters or shorter": "",
"Invalid namespace name: name must start with a lowercase letter": "",
"Invalid namespace name: name must end with an alphanumeric character": "",
"Invalid namespace name: name must consist of lower case alphanumeric characters or -": "",
"Creating namespace {{ name }}…": "",
"Cancelled creation of {{ name }}.": "",
"Created namespace {{ name }}.": "",
"Error creating namespace {{ name }}.": "",
"Create Namespace": "",
"To": "À",
"used": "utilisé",
"Scheduling Disabled": "Planification désactivée",
Expand Down
9 changes: 9 additions & 0 deletions frontend/src/i18n/locales/pt/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,15 @@
"Default Request": "Pedido por defeito",
"Max": "Máx.",
"Min": "Mín.",
"Invalid namespace name: name must be 63 characters or shorter": "",
"Invalid namespace name: name must start with a lowercase letter": "",
"Invalid namespace name: name must end with an alphanumeric character": "",
"Invalid namespace name: name must consist of lower case alphanumeric characters or -": "",
"Creating namespace {{ name }}…": "",
"Cancelled creation of {{ name }}.": "",
"Created namespace {{ name }}.": "",
"Error creating namespace {{ name }}.": "",
"Create Namespace": "",
"To": "Para",
"used": "usado",
"Scheduling Disabled": "Agendamento Desactivado",
Expand Down

0 comments on commit 58bbf86

Please sign in to comment.