';
const customCommands: CustomCommand[] = [
diff --git a/src/components/Projects/ProjectsList.tsx b/src/components/Projects/ProjectsList.tsx
index bbaf8c69..be22fdb0 100644
--- a/src/components/Projects/ProjectsList.tsx
+++ b/src/components/Projects/ProjectsList.tsx
@@ -1,8 +1,5 @@
-import {
- AnalyticalTable,
- AnalyticalTableColumnDefinition,
-} from '@ui5/webcomponents-react';
-import { ThemingParameters } from '@ui5/webcomponents-react-base';
+import { AnalyticalTable, AnalyticalTableColumnDefinition, Link } from '@ui5/webcomponents-react';
+
import { CopyButton } from '../Shared/CopyButton.tsx';
import useLuigiNavigate from '../Shared/useLuigiNavigate.tsx';
import IllustratedError from '../Shared/IllustratedError.tsx';
@@ -14,6 +11,7 @@ import { ListProjectNames } from '../../lib/api/types/crate/listProjectNames';
import { t } from 'i18next';
import { YamlViewButtonWithLoader } from '../Yaml/YamlViewButtonWithLoader.tsx';
import { useMemo } from 'react';
+import { ProjectsListItemMenu } from './ProjectsListItemMenu.tsx';
export default function ProjectsList() {
const navigate = useLuigiNavigate();
@@ -37,24 +35,26 @@ export default function ProjectsList() {
accessor: 'projectName',
// eslint-disable-next-line @typescript-eslint/no-explicit-any
Cell: (instance: any) => (
- {
+ navigate(`/mcp/projects/${instance.cell.row.original?.projectName}`);
}}
>
{instance.cell.value}
-
+
),
},
{
Header: 'Namespace',
accessor: 'nameSpace',
+ width: 340,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
Cell: (instance: any) => (
@@ -94,6 +95,26 @@ export default function ProjectsList() {
),
},
+ {
+ Header: '',
+ accessor: 'options',
+ width: 60,
+ disableFilters: true,
+ hAlign: 'Center',
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ Cell: (instance: any) => (
+
+ ),
+ },
],
[],
);
@@ -103,17 +124,7 @@ export default function ProjectsList() {
return (
<>
- {
- navigate(
- `/mcp/projects/${data ? [e.detail.row.values.projectName] : ''}`,
- );
- }}
- />
+
>
);
}
diff --git a/src/components/Projects/ProjectsListItemMenu.tsx b/src/components/Projects/ProjectsListItemMenu.tsx
new file mode 100644
index 00000000..7a02fae0
--- /dev/null
+++ b/src/components/Projects/ProjectsListItemMenu.tsx
@@ -0,0 +1,70 @@
+import { Button, ButtonDomRef, Menu, MenuItem, Ui5CustomEvent, MenuDomRef } from '@ui5/webcomponents-react';
+import type { ButtonClickEventDetail } from '@ui5/webcomponents/dist/Button.js';
+import { FC, useRef, useState } from 'react';
+import '@ui5/webcomponents-icons/dist/copy';
+import '@ui5/webcomponents-icons/dist/accept';
+
+import { useTranslation } from 'react-i18next';
+import { DeleteConfirmationDialog } from '../Dialogs/DeleteConfirmationDialog.tsx';
+
+import { useToast } from '../../context/ToastContext.tsx';
+import { useApiResourceMutation } from '../../lib/api/useApiResource.ts';
+import { DeleteWorkspaceType } from '../../lib/api/types/crate/deleteWorkspace.ts';
+import { DeleteProjectResource } from '../../lib/api/types/crate/deleteProject.ts';
+import { KubectlDeleteProject } from '../Dialogs/KubectlCommandInfo/Controllers/KubectlDeleteProject.tsx';
+
+type ProjectsListItemMenuProps = {
+ projectName: string;
+};
+
+export const ProjectsListItemMenu: FC = ({ projectName }) => {
+ const popoverRef = useRef(null);
+ const [open, setOpen] = useState(false);
+ const [dialogDeleteProjectIsOpen, setDialogDeleteProjectIsOpen] = useState(false);
+ const { t } = useTranslation();
+ const toast = useToast();
+ const { trigger } = useApiResourceMutation(DeleteProjectResource(projectName));
+ const handleOpenerClick = (e: Ui5CustomEvent) => {
+ e.stopImmediatePropagation();
+ e.stopPropagation();
+ if (popoverRef.current && e.currentTarget) {
+ popoverRef.current.opener = e.currentTarget as HTMLElement;
+ setOpen((prev) => !prev);
+ }
+ };
+
+ return (
+
+
+
+
+ {dialogDeleteProjectIsOpen && (
+ }
+ isOpen={dialogDeleteProjectIsOpen}
+ setIsOpen={setDialogDeleteProjectIsOpen}
+ onDeletionConfirmed={async () => {
+ await trigger();
+ toast.show(t('ProjectsListView.deleteConfirmationDialog'));
+ }}
+ />
+ )}
+
+ );
+};
diff --git a/src/components/Yaml/YamlViewButtonWithLoader.tsx b/src/components/Yaml/YamlViewButtonWithLoader.tsx
index 30e55a2b..9e66a4e2 100644
--- a/src/components/Yaml/YamlViewButtonWithLoader.tsx
+++ b/src/components/Yaml/YamlViewButtonWithLoader.tsx
@@ -12,11 +12,7 @@ export type YamlViewButtonProps = {
resourceName: string;
};
-export const YamlViewButtonWithLoader: FC = ({
- workspaceName,
- resourceType,
- resourceName,
-}) => {
+export const YamlViewButtonWithLoader: FC = ({ workspaceName, resourceType, resourceName }) => {
const [isOpen, setIsOpen] = useState(false);
const { t } = useTranslation();
return (
@@ -25,11 +21,7 @@ export const YamlViewButtonWithLoader: FC = ({
isOpen={isOpen}
setIsOpen={setIsOpen}
dialogContent={
-
+
}
/>
diff --git a/src/lib/api/types/crate/deleteProject.ts b/src/lib/api/types/crate/deleteProject.ts
new file mode 100644
index 00000000..4b27abcf
--- /dev/null
+++ b/src/lib/api/types/crate/deleteProject.ts
@@ -0,0 +1,10 @@
+import { Resource } from '../resource';
+
+export const DeleteProjectResource = (projectName: string): Resource => {
+ return {
+ path: `/apis/core.openmcp.cloud/v1alpha1/projects/${projectName}`,
+ method: 'DELETE',
+ jq: undefined,
+ body: undefined,
+ };
+};