Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
35bb5b3
initialize
lucasgoral Jun 3, 2025
2009834
fix
lucasgoral Jun 3, 2025
eca41fb
refactor
lucasgoral Jun 4, 2025
b0d1067
fixes
lucasgoral Jun 5, 2025
98f87e6
fix
lucasgoral Jun 5, 2025
7d00e69
Update CreateManagedControlPlaneWizardContainer.tsx
lucasgoral Jun 6, 2025
b3f1927
Merge branch 'main' into feat/create-MCP-mvp
lucasgoral Jun 9, 2025
efb07fb
init
lucasgoral Jun 9, 2025
c036777
fixes
lucasgoral Jun 9, 2025
1c71d7f
fixes
lucasgoral Jun 10, 2025
80970fa
fixes
lucasgoral Jun 10, 2025
64d8785
Update CreateManagedControlPlaneWizardContainer.tsx
lucasgoral Jun 10, 2025
f94c772
Update CreateManagedControlPlaneWizardContainer.tsx
lucasgoral Jun 10, 2025
a5a04bf
refactor
lucasgoral Jun 11, 2025
d2e5698
refactor
lucasgoral Jun 11, 2025
4447695
Update CreateManagedControlPlaneWizardContainer.tsx
lucasgoral Jun 11, 2025
ae5bd0e
Update CreateManagedControlPlaneWizardContainer.tsx
lucasgoral Jun 11, 2025
11a4344
Update CreateManagedControlPlaneWizardContainer.tsx
lucasgoral Jun 11, 2025
e3a2f4e
fixes
lucasgoral Jun 11, 2025
a4e1bbe
Update CreateManagedControlPlaneWizardContainer.tsx
lucasgoral Jun 11, 2025
fbb44aa
fixes
lucasgoral Jun 12, 2025
529f458
fix
lucasgoral Jun 12, 2025
d3a30f6
refactor
lucasgoral Jun 12, 2025
f3561d1
fixes
lucasgoral Jun 12, 2025
2be12b2
Merge branch 'main' into feat/create-MCP-mvp
lucasgoral Jun 13, 2025
2016aa1
fixes
lucasgoral Jun 13, 2025
24da70c
Update CreateManagedControlPlaneWizardContainer.tsx
lucasgoral Jun 13, 2025
290c411
Update ControlPlanesListMenu.tsx
lucasgoral Jun 13, 2025
e3443ed
Update createManagedControlPlane.ts
lucasgoral Jun 13, 2025
4245794
Update schemas.ts
lucasgoral Jun 13, 2025
8d7b806
fixes
lucasgoral Jun 13, 2025
dfbe5fc
Update regex.ts
lucasgoral Jun 13, 2025
368a951
Update WorkspacesList.module.css
lucasgoral Jun 16, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 25 additions & 5 deletions public/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,9 @@
"tableHeaderUsage": "Usage"
},
"ControlPlaneListToolbar": {
"buttonText": "Workspace"
"buttonText": "Workspace",
"deleteWorkspace": "Delete workspace",
"createNewManagedControlPlane": "Create new Managed Control Plane"
},
"ControlPlaneListWorkspaceGridTile": {
"deleteConfirmationDialog": "Workspace deletion triggered. The list will refresh automatically once completed.",
Expand Down Expand Up @@ -79,8 +81,8 @@
"menuCopy": "Copy to clipboard"
},
"IllustratedBanner": {
"titleMessage": "No ManagedControlPlane",
"subtitleMessage": "Create a ManagedControlPlane to get started",
"titleMessage": "No Managed Control Planes found",
"subtitleMessage": "Get started by creating your first Managed Control Plane.",
"helpButton": "Help"
},
"IntelligentBreadcrumbs": {
Expand Down Expand Up @@ -256,21 +258,39 @@
"validationErrors": {
"required": "This field is required!",
"properFormatting": "Use A-Z, a-z, 0-9, hyphen (-), and period (.), but note that whitespace (spaces, tabs, etc.) is not allowed for proper compatibility.",
"properFormattingLowercase": "Use lowercase a-z, 0-9, hyphen (-), and period (.), but note that whitespace (spaces, tabs, etc.) is not allowed for proper compatibility.",
"max25chars": "Max length is 25 characters.",
"userExists": "User with this email already exists!",
"atLeastOneUser": "You need to have at least one member assigned."
},
"common": {
"close": "Close",
"cannotLoadData": "Cannot load data"
"cannotLoadData": "Cannot load data",
"metadata": "Metadata",
"members": "Members",
"summarize": "Summarize",
"namespace": "Namespace",
"region": "Region",
"success": "Success",
"displayName": "Display Name",
"name": "Name"
},
"buttons": {
"viewResource": "View resource",
"download": "Download",
"copy": "Copy"
"copy": "Copy",
"next": "Next",
"create": "Create",
"close": "Close",
"back": "Back"
},
"yaml": {
"copiedToClipboard": "YAML copied to clipboard!",
"YAML": "YAML"
},
"createMCP": {
"dialogTitle": "Create Managed Control Plane",
"titleText": "Managed Control Plane Created Successfully!",
"subtitleText": "Your Managed Control Plane is being set up. It will be ready to use in just a few minutes. You can safely close this window."
}
}
72 changes: 72 additions & 0 deletions src/components/ControlPlanes/ControlPlanesListMenu.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import {
Button,
ButtonDomRef,
Menu,
MenuItem,
Ui5CustomEvent,
MenuDomRef,
} from '@ui5/webcomponents-react';
import type { ButtonClickEventDetail } from '@ui5/webcomponents/dist/Button.js';
import { Dispatch, FC, SetStateAction, useRef, useState } from 'react';
import '@ui5/webcomponents-icons/dist/copy';
import '@ui5/webcomponents-icons/dist/accept';

import { useTranslation } from 'react-i18next';

type ControlPlanesListMenuProps = {
setDialogDeleteWsIsOpen: Dispatch<SetStateAction<boolean>>;
setIsCreateManagedControlPlaneWizardOpen: Dispatch<SetStateAction<boolean>>;
};

export const ControlPlanesListMenu: FC<ControlPlanesListMenuProps> = ({
setDialogDeleteWsIsOpen,
setIsCreateManagedControlPlaneWizardOpen,
}) => {
const popoverRef = useRef<MenuDomRef>(null);
const [open, setOpen] = useState(false);

const { t } = useTranslation();

const handleOpenerClick = (
e: Ui5CustomEvent<ButtonDomRef, ButtonClickEventDetail>,
) => {
if (popoverRef.current && e.currentTarget) {
popoverRef.current.opener = e.currentTarget as HTMLElement;
setOpen((prev) => !prev);
}
};

return (
<>
<Button icon="overflow" icon-end onClick={handleOpenerClick} />
<Menu
ref={popoverRef}
open={open}
onItemClick={(event) => {
const action = (event.detail.item as HTMLElement).dataset.action;
if (action === 'newManagedControlPlane') {
setIsCreateManagedControlPlaneWizardOpen(true);
}
if (action === 'deleteWorkspace') {
setDialogDeleteWsIsOpen(true);
}

setOpen(false);
}}
>
<MenuItem
key={'add'}
text={t('ControlPlaneListToolbar.createNewManagedControlPlane')}
data-action="newManagedControlPlane"
icon="add"
/>
<MenuItem
key={'delete'}
text={t('ControlPlaneListToolbar.deleteWorkspace')}
data-action="deleteWorkspace"
icon="delete"
/>
</Menu>
</>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ import { YamlViewButtonWithLoader } from '../../Yaml/YamlViewButtonWithLoader.ts
import { IllustratedBanner } from '../../Ui/IllustratedBanner/IllustratedBanner.tsx';
import { useLink } from '../../../lib/shared/useLink.ts';
import IllustrationMessageType from '@ui5/webcomponents-fiori/dist/types/IllustrationMessageType.js';
import styles from './WorkspacesList.module.css';
import { ControlPlanesListMenu } from '../ControlPlanesListMenu.tsx';
import { CreateManagedControlPlaneWizardContainer } from '../../Wizards/CreateManagedControlPlaneWizardContainer.tsx';

interface Props {
projectName: string;
Expand All @@ -47,6 +50,10 @@ export function ControlPlaneListWorkspaceGridTile({
projectName,
workspace,
}: Props) {
const [
isCreateManagedControlPlaneWizardOpen,
setIsCreateManagedControlPlaneWizardOpen,
] = useState(false);
const workspaceName = workspace.metadata.name;
const workspaceDisplayName =
workspace.metadata.annotations?.[DISPLAY_NAME_ANNOTATION] || '';
Expand Down Expand Up @@ -103,7 +110,6 @@ export function ControlPlaneListWorkspaceGridTile({
<Panel
headerLevel="H2"
style={{ margin: '12px 12px 12px 0' }}
collapsed={controlplanes?.length === 0}
header={
<div
style={{
Expand Down Expand Up @@ -131,18 +137,17 @@ export function ControlPlaneListWorkspaceGridTile({
workspace={workspaceName}
/>
<FlexBox justifyContent={'SpaceBetween'} gap={10}>
<Button
design={'Transparent'}
icon="delete"
onClick={async () => {
setDialogDeleteWsIsOpen(true);
}}
/>
<YamlViewButtonWithLoader
workspaceName={workspace.metadata.namespace}
resourceName={workspaceName}
resourceType={'workspaces'}
/>
<ControlPlanesListMenu
setDialogDeleteWsIsOpen={setDialogDeleteWsIsOpen}
setIsCreateManagedControlPlaneWizardOpen={
setIsCreateManagedControlPlaneWizardOpen
}
/>
</FlexBox>
</div>
}
Expand All @@ -159,6 +164,18 @@ export function ControlPlaneListWorkspaceGridTile({
link: mcpCreationGuide,
buttonText: t('IllustratedBanner.helpButton'),
}}
button={
<Button
className={styles.createButton}
icon={'add'}
design={'Emphasized'}
onClick={() => {
setIsCreateManagedControlPlaneWizardOpen(true);
}}
>
{t('ControlPlaneListToolbar.createNewManagedControlPlane')}
</Button>
}
/>
) : (
<Grid defaultSpan="XL4 L4 M7 S12">
Expand Down Expand Up @@ -191,6 +208,12 @@ export function ControlPlaneListWorkspaceGridTile({
);
}}
/>
<CreateManagedControlPlaneWizardContainer
isOpen={isCreateManagedControlPlaneWizardOpen}
setIsOpen={setIsCreateManagedControlPlaneWizardOpen}
projectName={projectNamespace}
workspaceName={workspaceName}
/>
</>
);
}
2 changes: 1 addition & 1 deletion src/components/ControlPlanes/List/MembersAvatarView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export function MembersAvatarView({ members, project, workspace }: Props) {
setPopoverIsOpen(false);
}}
>
<MemberTable members={members} />
<MemberTable members={members} requireAtLeastOneMember={false} />
</Popover>
</div>
);
Expand Down
3 changes: 3 additions & 0 deletions src/components/ControlPlanes/List/WorkspacesList.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.createButton {
margin-bottom: 2rem;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.input {
width: 100%;
margin-bottom: 2rem;
max-width: 40ch;
}
99 changes: 18 additions & 81 deletions src/components/Dialogs/CreateProjectWorkspaceDialog.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,4 @@
import {
Bar,
Button,
Dialog,
Form,
FormGroup,
FormItem,
Input,
Label,
} from '@ui5/webcomponents-react';
import { Bar, Button, Dialog, FormGroup } from '@ui5/webcomponents-react';

import { Member } from '../../lib/api/types/shared/members';
import { ErrorDialog, ErrorDialogHandle } from '../Shared/ErrorMessageBox.tsx';
Expand All @@ -18,11 +9,12 @@ import { KubectlCreateWorkspaceDialog } from './KubectlCommandInfo/KubectlCreate
import { KubectlCreateProjectDialog } from './KubectlCommandInfo/KubectlCreateProjectDialog.tsx';

import { EditMembers } from '../Members/EditMembers.tsx';
// import { useFrontendConfig } from '../../context/FrontendConfigContext.tsx';

import { useTranslation } from 'react-i18next';

import { CreateDialogProps } from './CreateWorkspaceDialogContainer.tsx';
import { FieldErrors, UseFormRegister, UseFormSetValue } from 'react-hook-form';
import { MetadataForm } from './MetadataForm.tsx';

export type OnCreatePayload = {
name: string;
Expand Down Expand Up @@ -56,12 +48,14 @@ export function CreateProjectWorkspaceDialog({
setValue,
projectName,
}: CreateProjectWorkspaceDialogProps) {
// const { links } = useFrontendConfig();
const { t } = useTranslation();
const [isKubectlDialogOpen, setIsKubectlDialogOpen] = useState(false);

const openKubectlDialog = () => setIsKubectlDialogOpen(true);
const closeKubectlDialog = () => setIsKubectlDialogOpen(false);
const setMembers = (members: Member[]) => {
setValue('members', members);
};

return (
<>
Expand All @@ -79,7 +73,6 @@ export function CreateProjectWorkspaceDialog({
>
<KubectlInfoButton onClick={openKubectlDialog} />
<Button onClick={() => setIsOpen(false)}>
{' '}
{t('CreateProjectWorkspaceDialog.cancelButton')}
</Button>
<Button design="Emphasized" onClick={() => onCreate()}>
Expand All @@ -91,11 +84,20 @@ export function CreateProjectWorkspaceDialog({
}
onClose={() => setIsOpen(false)}
>
<CreateProjectWorkspaceDialogContent
members={members}
<MetadataForm
register={register}
errors={errors}
setValue={setValue}
sideFormContent={
<FormGroup
headerText={t('CreateProjectWorkspaceDialog.membersHeader')}
>
<EditMembers
members={members}
isValidationError={!!errors.members}
onMemberChanged={setMembers}
/>
</FormGroup>
}
/>
</Dialog>
<KubectlCreateWorkspaceDialog
Expand All @@ -111,68 +113,3 @@ export function CreateProjectWorkspaceDialog({
</>
);
}

interface CreateProjectWorkspaceDialogContentProps {
members: Member[];
register: UseFormRegister<CreateDialogProps>;
errors: FieldErrors<CreateDialogProps>;
setValue: UseFormSetValue<CreateDialogProps>;
}

function CreateProjectWorkspaceDialogContent({
members,
register,
errors,
setValue,
}: CreateProjectWorkspaceDialogContentProps) {
const { t } = useTranslation();

const setMembers = (members: Member[]) => {
setValue('members', members);
};
return (
<Form>
<FormGroup headerText={t('CreateProjectWorkspaceDialog.metadataHeader')}>
<FormItem
labelContent={
<Label required>
{t('CreateProjectWorkspaceDialog.nameLabel')}
</Label>
}
>
<Input
id="name"
{...register('name')}
valueState={errors.name ? 'Negative' : 'None'}
valueStateMessage={<span>{errors.name?.message}</span>}
required
/>
</FormItem>

<FormItem
labelContent={
<Label>{t('CreateProjectWorkspaceDialog.displayNameLabel')}</Label>
}
>
<Input id="displayName" {...register('displayName')} />
</FormItem>
<FormItem
labelContent={
<Label>
{t('CreateProjectWorkspaceDialog.chargingTargetLabel')}
</Label>
}
>
<Input id="chargingTarget" {...register('chargingTarget')} />
</FormItem>
</FormGroup>
<FormGroup headerText={t('CreateProjectWorkspaceDialog.membersHeader')}>
<EditMembers
members={members}
isValidationError={!!errors.members}
onMemberChanged={setMembers}
/>
</FormGroup>
</Form>
);
}
Loading
Loading