From ac4318ec1b8ea3e6d400d8332033a3fab679be43 Mon Sep 17 00:00:00 2001 From: nicosammito Date: Thu, 9 Jul 2026 17:56:30 +0200 Subject: [PATCH 01/36] feat: enhance ApplicationBarView with namespace and organization services for improved navigation --- .../application/views/ApplicationBarView.tsx | 138 +++++++++++++++--- 1 file changed, 115 insertions(+), 23 deletions(-) diff --git a/src/packages/ce/src/application/views/ApplicationBarView.tsx b/src/packages/ce/src/application/views/ApplicationBarView.tsx index fc6f0a17..7b58ba1a 100644 --- a/src/packages/ce/src/application/views/ApplicationBarView.tsx +++ b/src/packages/ce/src/application/views/ApplicationBarView.tsx @@ -2,22 +2,44 @@ import {Button, Flex, MenuItem, MenuSeparator, Text, useService, useStore} from "@code0-tech/pictor"; import {UserService} from "@edition/user/services/User.service"; -import {useParams, useRouter} from "next/navigation"; +import {useParams, usePathname, useRouter} from "next/navigation"; import React from "react"; import Link from "next/link"; -import {IconBuilding, IconFolders, IconInbox, IconLogout, IconSearch, IconUser} from "@tabler/icons-react"; +import { + IconBox, + IconBuilding, + IconFolders, + IconHome, + IconInbox, + IconLogout, + IconRoute, + IconSearch, + IconServer, + IconSettings, + IconUser, + IconUserCog, + IconUsers +} from "@tabler/icons-react"; import {ApplicationBreadcrumbView} from "@edition/application/views/ApplicationBreadcrumbView"; import UserMenuComponent from "@edition/user/components/UserMenuComponent"; import {useUserSession} from "@edition/user/hooks/User.session.hook"; import {Island} from "@code0-tech/pictor/dist/components/island/Island"; import {ButtonGroup} from "@code0-tech/pictor/dist/components/button-group/ButtonGroup"; +import {NamespaceService} from "@edition/namespace/services/Namespace.service"; +import {OrganizationService} from "@edition/organization/services/Organization.service"; +import {Namespace} from "@code0-tech/sagittarius-graphql-types"; export const ApplicationBarView: React.FC = () => { const currentSession = useUserSession() const userService = useService(UserService) const userStore = useStore(UserService) + const namespaceService = useService(NamespaceService) + const namespaceStore = useStore(NamespaceService) + const organizationService = useService(OrganizationService) + const organizationStore = useStore(OrganizationService) const router = useRouter() + const pathname = usePathname() const [loading, startTransition] = React.useTransition() const params = useParams() @@ -28,6 +50,94 @@ export const ApplicationBarView: React.FC = () => { const userIndex = currentUser?.id?.match(/User\/(\d+)$/)?.[1] const currentStep = projectIndex ? "project" : namespaceIndex ? "namespace" : "home"; + const namespaceId: Namespace['id'] = `gid://sagittarius/Namespace/${namespaceIndex as any as number}` + const namespace = React.useMemo(() => namespaceService.getById(namespaceId), [namespaceStore, namespaceId]) + const parentOrganization = React.useMemo(() => namespace?.parent?.__typename === "Organization" ? organizationService.getById(namespace?.parent?.id) : null, [organizationStore, namespace]) + + const homeTabs = React.useMemo(() => { + return [ + , + ...(currentUser?.admin ? [ + , + , + + ] : []) + ] + }, [currentUser, pathname]) + + const namespaceTabs = React.useMemo(() => { + const baseLink = `/namespace/${namespaceIndex}` + const showSettings = (parentOrganization && (parentOrganization.userAbilities?.deleteOrganization + || parentOrganization?.userAbilities?.updateOrganization)) + || namespace?.userAbilities?.createLicense + //TODO add license check for enterprise features + + return [ + , + , + , + , + , + ...(showSettings ? [ + + ] : []) + ] + }, [namespace, parentOrganization, namespaceIndex, pathname]) + + const projectTabs = React.useMemo(() => { + const baseLink = `/namespace/${namespaceIndex}/project/${projectIndex}` + + return [ + , + , + , + + ] + }, [namespaceIndex, projectIndex, pathname]) + const userMenu = React.useMemo(() => { if (!currentUser || !currentSession) { @@ -52,7 +162,7 @@ export const ApplicationBarView: React.FC = () => { - + Organizations @@ -75,26 +185,8 @@ export const ApplicationBarView: React.FC = () => { style={{zIndex: 9999, transform: "translateX(-50%)"}}> - - {namespaceIndex ? ( - - ) : (null as any)} - {namespaceIndex && projectIndex ? ( - - ) : (null as any)} + {currentStep === "project" ? projectTabs : currentStep === "namespace" ? namespaceTabs : homeTabs} - @@ -107,4 +199,4 @@ export const ApplicationBarView: React.FC = () => { {userMenu} -} \ No newline at end of file +} From 7253a7ad2c7ae46e566c4b43bed7c7408be9366b Mon Sep 17 00:00:00 2001 From: nicosammito Date: Thu, 9 Jul 2026 17:56:48 +0200 Subject: [PATCH 02/36] feat: simplify ApplicationTabView by removing unused services and admin links --- .../application/views/ApplicationTabView.tsx | 77 ++++--------------- 1 file changed, 13 insertions(+), 64 deletions(-) diff --git a/src/packages/ce/src/application/views/ApplicationTabView.tsx b/src/packages/ce/src/application/views/ApplicationTabView.tsx index a607f704..e0397fc9 100644 --- a/src/packages/ce/src/application/views/ApplicationTabView.tsx +++ b/src/packages/ce/src/application/views/ApplicationTabView.tsx @@ -1,72 +1,21 @@ "use client" import React from "react"; -import {Tab, TabList, TabTrigger} from "@code0-tech/pictor/dist/components/tab/Tab"; -import {Button, useService, useStore} from "@code0-tech/pictor"; -import {IconBuilding, IconHome, IconServer, IconSettings, IconUser} from "@tabler/icons-react"; -import {usePathname, useRouter} from "next/navigation"; -import {UserService} from "@edition/user/services/User.service"; -import {RuntimeService} from "@edition/runtime/services/Runtime.service"; -import {OrganizationService} from "@edition/organization/services/Organization.service"; -import {useUserSession} from "@edition/user/hooks/User.session.hook"; +import {Button} from "@code0-tech/pictor"; +import {IconBuilding, IconHome} from "@tabler/icons-react"; +import {useRouter} from "next/navigation"; export const ApplicationTabView: React.FC = () => { - const pathname = usePathname() const router = useRouter() - const userService = useService(UserService) - const runtimeService = useService(RuntimeService) - const runtimeStore = useStore(RuntimeService) - const organizationService = useService(OrganizationService) - const organizationStore = useStore(OrganizationService) - const userStore = useStore(UserService) - const currentSession = useUserSession() - const currentUser = React.useMemo(() => userService.getById(currentSession?.user?.id), [userStore, currentSession]) - const defaultValue = pathname.includes("organizations") ? "organizations" - : pathname.includes("users") ? "users" - : pathname.includes("settings") ? "settings" - : pathname.includes("runtimes") ? "runtimes" - : "overview" - const adminLinks = React.useMemo(() => { - return currentUser && currentUser.admin ? ( - <> - - - - - - - - - - - - ) : null - }, [currentUser, runtimeStore, organizationStore]) - - return - - - - - - - - {adminLinks} - - -} \ No newline at end of file + return <> + + + +} From 9af312b19e75a7003248353f189319c985bc65cd Mon Sep 17 00:00:00 2001 From: nicosammito Date: Thu, 9 Jul 2026 17:57:17 +0200 Subject: [PATCH 03/36] feat: remove old tab views --- src/app/(dashboard)/@tab/default.ts | 5 -- .../(dashboard)/@tab/licenses/add/default.tsx | 5 -- .../[namespaceId]/licenses/default.tsx | 5 -- .../[namespaceId]/members/default.tsx | 5 -- .../@tab/namespace/[namespaceId]/page.tsx | 5 -- .../[namespaceId]/projects/default.tsx | 5 -- .../namespace/[namespaceId]/roles/default.tsx | 5 -- .../[namespaceId]/runtimes/default.tsx | 5 -- .../[namespaceId]/settings/default.tsx | 5 -- .../@tab/organizations/default.tsx | 10 --- src/app/(dashboard)/@tab/runtimes/default.tsx | 10 --- src/app/(dashboard)/@tab/settings/page.tsx | 10 --- src/app/(dashboard)/@tab/users/default.tsx | 10 --- .../[projectId]/flow/[flowId]/page.tsx | 5 -- .../project/[projectId]/flow/page.tsx | 5 -- .../[projectId]/module/[moduleId]/page.tsx | 5 -- .../project/[projectId]/module/page.tsx | 5 -- .../project/[projectId]/page.tsx | 5 -- .../project/[projectId]/runtime/page.tsx | 5 -- .../project/[projectId]/settings/page.tsx | 5 -- .../src/namespace/views/NamespaceTabView.tsx | 79 ----------------- .../ce/src/project/views/ProjectTabView.tsx | 85 ------------------- 22 files changed, 284 deletions(-) delete mode 100644 src/app/(dashboard)/@tab/default.ts delete mode 100644 src/app/(dashboard)/@tab/licenses/add/default.tsx delete mode 100644 src/app/(dashboard)/@tab/namespace/[namespaceId]/licenses/default.tsx delete mode 100644 src/app/(dashboard)/@tab/namespace/[namespaceId]/members/default.tsx delete mode 100644 src/app/(dashboard)/@tab/namespace/[namespaceId]/page.tsx delete mode 100644 src/app/(dashboard)/@tab/namespace/[namespaceId]/projects/default.tsx delete mode 100644 src/app/(dashboard)/@tab/namespace/[namespaceId]/roles/default.tsx delete mode 100644 src/app/(dashboard)/@tab/namespace/[namespaceId]/runtimes/default.tsx delete mode 100644 src/app/(dashboard)/@tab/namespace/[namespaceId]/settings/default.tsx delete mode 100644 src/app/(dashboard)/@tab/organizations/default.tsx delete mode 100644 src/app/(dashboard)/@tab/runtimes/default.tsx delete mode 100644 src/app/(dashboard)/@tab/settings/page.tsx delete mode 100644 src/app/(dashboard)/@tab/users/default.tsx delete mode 100644 src/app/(flow)/@tab/namespace/[namespaceId]/project/[projectId]/flow/[flowId]/page.tsx delete mode 100644 src/app/(flow)/@tab/namespace/[namespaceId]/project/[projectId]/flow/page.tsx delete mode 100644 src/app/(flow)/@tab/namespace/[namespaceId]/project/[projectId]/module/[moduleId]/page.tsx delete mode 100644 src/app/(flow)/@tab/namespace/[namespaceId]/project/[projectId]/module/page.tsx delete mode 100644 src/app/(flow)/@tab/namespace/[namespaceId]/project/[projectId]/page.tsx delete mode 100644 src/app/(flow)/@tab/namespace/[namespaceId]/project/[projectId]/runtime/page.tsx delete mode 100644 src/app/(flow)/@tab/namespace/[namespaceId]/project/[projectId]/settings/page.tsx delete mode 100644 src/packages/ce/src/namespace/views/NamespaceTabView.tsx delete mode 100644 src/packages/ce/src/project/views/ProjectTabView.tsx diff --git a/src/app/(dashboard)/@tab/default.ts b/src/app/(dashboard)/@tab/default.ts deleted file mode 100644 index ac3dd7f7..00000000 --- a/src/app/(dashboard)/@tab/default.ts +++ /dev/null @@ -1,5 +0,0 @@ -"use client" - -export default function Page() { - return null -} \ No newline at end of file diff --git a/src/app/(dashboard)/@tab/licenses/add/default.tsx b/src/app/(dashboard)/@tab/licenses/add/default.tsx deleted file mode 100644 index ac3dd7f7..00000000 --- a/src/app/(dashboard)/@tab/licenses/add/default.tsx +++ /dev/null @@ -1,5 +0,0 @@ -"use client" - -export default function Page() { - return null -} \ No newline at end of file diff --git a/src/app/(dashboard)/@tab/namespace/[namespaceId]/licenses/default.tsx b/src/app/(dashboard)/@tab/namespace/[namespaceId]/licenses/default.tsx deleted file mode 100644 index 3881c19f..00000000 --- a/src/app/(dashboard)/@tab/namespace/[namespaceId]/licenses/default.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import {NamespaceTabView} from "@edition/namespace/views/NamespaceTabView"; - -export default function Page() { - return -} \ No newline at end of file diff --git a/src/app/(dashboard)/@tab/namespace/[namespaceId]/members/default.tsx b/src/app/(dashboard)/@tab/namespace/[namespaceId]/members/default.tsx deleted file mode 100644 index 3881c19f..00000000 --- a/src/app/(dashboard)/@tab/namespace/[namespaceId]/members/default.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import {NamespaceTabView} from "@edition/namespace/views/NamespaceTabView"; - -export default function Page() { - return -} \ No newline at end of file diff --git a/src/app/(dashboard)/@tab/namespace/[namespaceId]/page.tsx b/src/app/(dashboard)/@tab/namespace/[namespaceId]/page.tsx deleted file mode 100644 index 3881c19f..00000000 --- a/src/app/(dashboard)/@tab/namespace/[namespaceId]/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import {NamespaceTabView} from "@edition/namespace/views/NamespaceTabView"; - -export default function Page() { - return -} \ No newline at end of file diff --git a/src/app/(dashboard)/@tab/namespace/[namespaceId]/projects/default.tsx b/src/app/(dashboard)/@tab/namespace/[namespaceId]/projects/default.tsx deleted file mode 100644 index 3881c19f..00000000 --- a/src/app/(dashboard)/@tab/namespace/[namespaceId]/projects/default.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import {NamespaceTabView} from "@edition/namespace/views/NamespaceTabView"; - -export default function Page() { - return -} \ No newline at end of file diff --git a/src/app/(dashboard)/@tab/namespace/[namespaceId]/roles/default.tsx b/src/app/(dashboard)/@tab/namespace/[namespaceId]/roles/default.tsx deleted file mode 100644 index 3881c19f..00000000 --- a/src/app/(dashboard)/@tab/namespace/[namespaceId]/roles/default.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import {NamespaceTabView} from "@edition/namespace/views/NamespaceTabView"; - -export default function Page() { - return -} \ No newline at end of file diff --git a/src/app/(dashboard)/@tab/namespace/[namespaceId]/runtimes/default.tsx b/src/app/(dashboard)/@tab/namespace/[namespaceId]/runtimes/default.tsx deleted file mode 100644 index 3881c19f..00000000 --- a/src/app/(dashboard)/@tab/namespace/[namespaceId]/runtimes/default.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import {NamespaceTabView} from "@edition/namespace/views/NamespaceTabView"; - -export default function Page() { - return -} \ No newline at end of file diff --git a/src/app/(dashboard)/@tab/namespace/[namespaceId]/settings/default.tsx b/src/app/(dashboard)/@tab/namespace/[namespaceId]/settings/default.tsx deleted file mode 100644 index 3881c19f..00000000 --- a/src/app/(dashboard)/@tab/namespace/[namespaceId]/settings/default.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import {NamespaceTabView} from "@edition/namespace/views/NamespaceTabView"; - -export default function Page() { - return -} \ No newline at end of file diff --git a/src/app/(dashboard)/@tab/organizations/default.tsx b/src/app/(dashboard)/@tab/organizations/default.tsx deleted file mode 100644 index 5251309f..00000000 --- a/src/app/(dashboard)/@tab/organizations/default.tsx +++ /dev/null @@ -1,10 +0,0 @@ -"use client" - -import React from "react"; -import {ApplicationTabView} from "@edition/application/views/ApplicationTabView"; - -const Page: React.FC = () => { - return -} - -export default Page \ No newline at end of file diff --git a/src/app/(dashboard)/@tab/runtimes/default.tsx b/src/app/(dashboard)/@tab/runtimes/default.tsx deleted file mode 100644 index 5251309f..00000000 --- a/src/app/(dashboard)/@tab/runtimes/default.tsx +++ /dev/null @@ -1,10 +0,0 @@ -"use client" - -import React from "react"; -import {ApplicationTabView} from "@edition/application/views/ApplicationTabView"; - -const Page: React.FC = () => { - return -} - -export default Page \ No newline at end of file diff --git a/src/app/(dashboard)/@tab/settings/page.tsx b/src/app/(dashboard)/@tab/settings/page.tsx deleted file mode 100644 index 5251309f..00000000 --- a/src/app/(dashboard)/@tab/settings/page.tsx +++ /dev/null @@ -1,10 +0,0 @@ -"use client" - -import React from "react"; -import {ApplicationTabView} from "@edition/application/views/ApplicationTabView"; - -const Page: React.FC = () => { - return -} - -export default Page \ No newline at end of file diff --git a/src/app/(dashboard)/@tab/users/default.tsx b/src/app/(dashboard)/@tab/users/default.tsx deleted file mode 100644 index 1be75b18..00000000 --- a/src/app/(dashboard)/@tab/users/default.tsx +++ /dev/null @@ -1,10 +0,0 @@ -"use client" - -import React from "react"; -import {ApplicationTabView} from "@edition/application/views/ApplicationTabView"; - -const Default: React.FC = () => { - return -} - -export default Default \ No newline at end of file diff --git a/src/app/(flow)/@tab/namespace/[namespaceId]/project/[projectId]/flow/[flowId]/page.tsx b/src/app/(flow)/@tab/namespace/[namespaceId]/project/[projectId]/flow/[flowId]/page.tsx deleted file mode 100644 index 5b941806..00000000 --- a/src/app/(flow)/@tab/namespace/[namespaceId]/project/[projectId]/flow/[flowId]/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -"use client" - -import {ProjectTabView} from "@edition/project/views/ProjectTabView"; - -export default ProjectTabView \ No newline at end of file diff --git a/src/app/(flow)/@tab/namespace/[namespaceId]/project/[projectId]/flow/page.tsx b/src/app/(flow)/@tab/namespace/[namespaceId]/project/[projectId]/flow/page.tsx deleted file mode 100644 index 5b941806..00000000 --- a/src/app/(flow)/@tab/namespace/[namespaceId]/project/[projectId]/flow/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -"use client" - -import {ProjectTabView} from "@edition/project/views/ProjectTabView"; - -export default ProjectTabView \ No newline at end of file diff --git a/src/app/(flow)/@tab/namespace/[namespaceId]/project/[projectId]/module/[moduleId]/page.tsx b/src/app/(flow)/@tab/namespace/[namespaceId]/project/[projectId]/module/[moduleId]/page.tsx deleted file mode 100644 index ee84a50d..00000000 --- a/src/app/(flow)/@tab/namespace/[namespaceId]/project/[projectId]/module/[moduleId]/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -"use client" - -import {ProjectTabView} from "@ce-internal/project/views/ProjectTabView"; - -export default ProjectTabView \ No newline at end of file diff --git a/src/app/(flow)/@tab/namespace/[namespaceId]/project/[projectId]/module/page.tsx b/src/app/(flow)/@tab/namespace/[namespaceId]/project/[projectId]/module/page.tsx deleted file mode 100644 index ee84a50d..00000000 --- a/src/app/(flow)/@tab/namespace/[namespaceId]/project/[projectId]/module/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -"use client" - -import {ProjectTabView} from "@ce-internal/project/views/ProjectTabView"; - -export default ProjectTabView \ No newline at end of file diff --git a/src/app/(flow)/@tab/namespace/[namespaceId]/project/[projectId]/page.tsx b/src/app/(flow)/@tab/namespace/[namespaceId]/project/[projectId]/page.tsx deleted file mode 100644 index 5b941806..00000000 --- a/src/app/(flow)/@tab/namespace/[namespaceId]/project/[projectId]/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -"use client" - -import {ProjectTabView} from "@edition/project/views/ProjectTabView"; - -export default ProjectTabView \ No newline at end of file diff --git a/src/app/(flow)/@tab/namespace/[namespaceId]/project/[projectId]/runtime/page.tsx b/src/app/(flow)/@tab/namespace/[namespaceId]/project/[projectId]/runtime/page.tsx deleted file mode 100644 index 5b941806..00000000 --- a/src/app/(flow)/@tab/namespace/[namespaceId]/project/[projectId]/runtime/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -"use client" - -import {ProjectTabView} from "@edition/project/views/ProjectTabView"; - -export default ProjectTabView \ No newline at end of file diff --git a/src/app/(flow)/@tab/namespace/[namespaceId]/project/[projectId]/settings/page.tsx b/src/app/(flow)/@tab/namespace/[namespaceId]/project/[projectId]/settings/page.tsx deleted file mode 100644 index 5b941806..00000000 --- a/src/app/(flow)/@tab/namespace/[namespaceId]/project/[projectId]/settings/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -"use client" - -import {ProjectTabView} from "@edition/project/views/ProjectTabView"; - -export default ProjectTabView \ No newline at end of file diff --git a/src/packages/ce/src/namespace/views/NamespaceTabView.tsx b/src/packages/ce/src/namespace/views/NamespaceTabView.tsx deleted file mode 100644 index 81af8d27..00000000 --- a/src/packages/ce/src/namespace/views/NamespaceTabView.tsx +++ /dev/null @@ -1,79 +0,0 @@ -"use client" - -import React from "react"; -import {Button, useService, useStore} from "@code0-tech/pictor"; -import {Tab, TabList, TabTrigger} from "@code0-tech/pictor/dist/components/tab/Tab"; -import {IconFolders, IconHome, IconServer, IconSettings, IconUserCog, IconUsers} from "@tabler/icons-react"; -import {useParams, usePathname, useRouter} from "next/navigation"; -import {NamespaceService} from "@edition/namespace/services/Namespace.service"; -import {OrganizationService} from "@edition/organization/services/Organization.service"; - -export const NamespaceTabView: React.FC = () => { - - const pathname = usePathname() - const router = useRouter() - const params = useParams() - const namespaceId = params.namespaceId as any - - const namespaceService = useService(NamespaceService) - const namespaceStore = useStore(NamespaceService) - const organizationService = useService(OrganizationService) - const organizationStore = useStore(OrganizationService) - - const namespace = React.useMemo(() => namespaceService.getById(`gid://sagittarius/Namespace/${namespaceId}`), [namespaceStore, namespaceId]) - const parentOrganization = React.useMemo(() => namespace?.parent?.__typename === "Organization" ? organizationService.getById(namespace?.parent?.id) : null, [organizationStore, namespace]) - - const baseLink = `/namespace/${namespaceId}` - const defaultValue = pathname.includes("projects") ? "projects" - : pathname.includes("members") ? "members" - : pathname.includes("roles") ? "roles" - : pathname.includes("runtimes") ? "runtimes" - : pathname.includes("settings") ? "settings" - : "overview" - - const settings = React.useMemo(() => { - return ( - (parentOrganization && (parentOrganization.userAbilities?.deleteOrganization - || parentOrganization?.userAbilities?.updateOrganization)) - || namespace?.userAbilities?.createLicense - //TODO add license check for enterprise features - ) ? ( - - - - ) : null - }, [namespace, parentOrganization]) - - return - - - - - - - - - - - - - - - - - {settings} - - -} \ No newline at end of file diff --git a/src/packages/ce/src/project/views/ProjectTabView.tsx b/src/packages/ce/src/project/views/ProjectTabView.tsx deleted file mode 100644 index 30416b3a..00000000 --- a/src/packages/ce/src/project/views/ProjectTabView.tsx +++ /dev/null @@ -1,85 +0,0 @@ -import React from "react"; -import {useParams, usePathname, useRouter} from "next/navigation"; -import {Tab, TabList, TabTrigger} from "@code0-tech/pictor/dist/components/tab/Tab"; -import {Button, Text, Tooltip, TooltipContent, TooltipPortal, TooltipTrigger} from "@code0-tech/pictor"; -import {IconBox, IconHome, IconServer, IconSettings} from "@tabler/icons-react"; - -export const ProjectTabView: React.FC = () => { - const pathname = usePathname() - const router = useRouter() - const params = useParams() - const defaultValue = pathname.includes("flow") ? "flow" - : pathname.includes("module") ? "module" - : pathname.includes("runtime") ? "runtime" : - "settings" - - const namespaceId = params.namespaceId as any - const projectId = params.projectId as any - const flowId = params.flowId as any - - return - - - - - - - - - - Flows - - - - - - - - - - - - Assigned runtimes - - - - - - - - - - - - Plugins - - - - - - - - - - - - Settings - - - - - -} \ No newline at end of file From c02381bf3d70cc9c22a1641930af3a9341fb295a Mon Sep 17 00:00:00 2001 From: nicosammito Date: Thu, 9 Jul 2026 17:57:28 +0200 Subject: [PATCH 04/36] feat: simplify default export by directly exporting ApplicationBarView --- src/app/(dashboard)/@bar/default.tsx | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/app/(dashboard)/@bar/default.tsx b/src/app/(dashboard)/@bar/default.tsx index 11a620f6..2b1a1ac3 100644 --- a/src/app/(dashboard)/@bar/default.tsx +++ b/src/app/(dashboard)/@bar/default.tsx @@ -1,10 +1,5 @@ "use client"; -import React from "react"; import {ApplicationBarView} from "@edition/application/views/ApplicationBarView"; -const Page = () => { - return -} - -export default Page \ No newline at end of file +export default ApplicationBarView From ec7c91a4c179f589cfcd6a5d71f150d345c22e77 Mon Sep 17 00:00:00 2001 From: nicosammito Date: Thu, 9 Jul 2026 17:57:37 +0200 Subject: [PATCH 05/36] feat: rename page.tsx to default.tsx for clarity in file structure --- src/app/(dashboard)/@tab/{page.tsx => default.tsx} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/app/(dashboard)/@tab/{page.tsx => default.tsx} (100%) diff --git a/src/app/(dashboard)/@tab/page.tsx b/src/app/(dashboard)/@tab/default.tsx similarity index 100% rename from src/app/(dashboard)/@tab/page.tsx rename to src/app/(dashboard)/@tab/default.tsx From 6e5e25e9e86b5f63b67cc3e05040776c10433a27 Mon Sep 17 00:00:00 2001 From: nicosammito Date: Thu, 9 Jul 2026 17:57:46 +0200 Subject: [PATCH 06/36] feat: simplify default export by directly exporting ApplicationBarView --- src/app/(flow)/@bar/default.tsx | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/app/(flow)/@bar/default.tsx b/src/app/(flow)/@bar/default.tsx index 11a620f6..2722f04c 100644 --- a/src/app/(flow)/@bar/default.tsx +++ b/src/app/(flow)/@bar/default.tsx @@ -1,10 +1,5 @@ "use client"; -import React from "react"; import {ApplicationBarView} from "@edition/application/views/ApplicationBarView"; -const Page = () => { - return -} - -export default Page \ No newline at end of file +export default ApplicationBarView \ No newline at end of file From 190dd4099ef52489c879cdb0e8bcfb3fb1376909 Mon Sep 17 00:00:00 2001 From: nicosammito Date: Thu, 9 Jul 2026 17:57:54 +0200 Subject: [PATCH 07/36] feat: replace Page component with direct export of ApplicationTabView --- src/app/(flow)/@tab/default.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/app/(flow)/@tab/default.tsx b/src/app/(flow)/@tab/default.tsx index ac3dd7f7..0e93b0db 100644 --- a/src/app/(flow)/@tab/default.tsx +++ b/src/app/(flow)/@tab/default.tsx @@ -1,5 +1,5 @@ "use client" -export default function Page() { - return null -} \ No newline at end of file +import {ApplicationTabView} from "@edition/application/views/ApplicationTabView"; + +export default ApplicationTabView From 675688131bfe3698e68e5dfda1eea4c285a3631f Mon Sep 17 00:00:00 2001 From: nicosammito Date: Thu, 9 Jul 2026 17:58:13 +0200 Subject: [PATCH 08/36] feat: update padding property in Layout component for improved spacing --- src/app/(dashboard)/layout.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/(dashboard)/layout.tsx b/src/app/(dashboard)/layout.tsx index a671d72d..714ecb0d 100644 --- a/src/app/(dashboard)/layout.tsx +++ b/src/app/(dashboard)/layout.tsx @@ -82,7 +82,7 @@ const ApplicationLayout: React.FC = ({children, bar, tab {tab} }> - {bar}}> + {bar}}> <>{children} From dd98d3d3657dc0c4ece44eddfc838e58f09955d5 Mon Sep 17 00:00:00 2001 From: nicosammito Date: Thu, 9 Jul 2026 17:58:29 +0200 Subject: [PATCH 09/36] feat: update navigation links in OrganizationCreatePage to point to workspaces --- .../ce/src/organization/pages/OrganizationCreatePage.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/packages/ce/src/organization/pages/OrganizationCreatePage.tsx b/src/packages/ce/src/organization/pages/OrganizationCreatePage.tsx index c5971720..b3fc2acd 100644 --- a/src/packages/ce/src/organization/pages/OrganizationCreatePage.tsx +++ b/src/packages/ce/src/organization/pages/OrganizationCreatePage.tsx @@ -29,7 +29,7 @@ export const OrganizationCreatePage = () => { name: values.name as unknown as string }).then(payload => { if ((payload?.errors?.length ?? 0) <= 0) { - router.push("/organizations") + router.push("/workspaces") } }) }) @@ -55,7 +55,7 @@ export const OrganizationCreatePage = () => { {...inputs.getInputProps("name")}/> - + From 11294bfe0786eb03ee6252ce6dc55903e005da8f Mon Sep 17 00:00:00 2001 From: nicosammito Date: Thu, 9 Jul 2026 17:58:54 +0200 Subject: [PATCH 10/36] feat: update link in OrganizationsView to point to workspaces creation --- src/packages/ce/src/organization/views/OrganizationsView.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/packages/ce/src/organization/views/OrganizationsView.tsx b/src/packages/ce/src/organization/views/OrganizationsView.tsx index 03e6c5d1..3f7cb0d1 100644 --- a/src/packages/ce/src/organization/views/OrganizationsView.tsx +++ b/src/packages/ce/src/organization/views/OrganizationsView.tsx @@ -40,7 +40,7 @@ export const OrganizationsView = () => { - + From 3104b8805ea1e562947c8103a1f3c48b5dc85607 Mon Sep 17 00:00:00 2001 From: nicosammito Date: Thu, 9 Jul 2026 17:59:07 +0200 Subject: [PATCH 11/36] feat: update @code0-tech/triangulum dependency to version 0.25.8 --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4383075e..507ee59a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "dependencies": { "@apollo/client": "^4.0.9", "@code0-tech/pictor": "^0.11.0", - "@code0-tech/triangulum": "^0.25.6", + "@code0-tech/triangulum": "^0.25.8", "@codemirror/lang-javascript": "^6.2.5", "@codemirror/lint": "^6.9.5", "@icons-pack/react-simple-icons": "^13.13.0", @@ -1946,9 +1946,9 @@ "peer": true }, "node_modules/@code0-tech/triangulum": { - "version": "0.25.6", - "resolved": "https://registry.npmjs.org/@code0-tech/triangulum/-/triangulum-0.25.6.tgz", - "integrity": "sha512-xCaaFafZyuGKYAzZ3J1W40FrTK0nKY+M25eVQQKEoxmJH5BN5LT6BYB8R3GbMESroGNKuEHibFcyLyzhqV2YLQ==", + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@code0-tech/triangulum/-/triangulum-0.25.8.tgz", + "integrity": "sha512-qEte2foHL78W0YW+4hVSjLtNgts1DnLXE6AMymypWspzzpKpzMLXZ0B2aRwBRaZL6yuh5GmG7nsG03Q9OAgxXg==", "peerDependencies": { "@code0-tech/sagittarius-graphql-types": "0.0.0-experimental-2616186698-14d97e4ac998067751f9cbd9f8fc05c6fed628fe", "@typescript/vfs": "^1.6.4", diff --git a/package.json b/package.json index f9d31dd4..162bbe07 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "dependencies": { "@apollo/client": "^4.0.9", "@code0-tech/pictor": "^0.11.0", - "@code0-tech/triangulum": "^0.25.6", + "@code0-tech/triangulum": "^0.25.8", "@codemirror/lang-javascript": "^6.2.5", "@codemirror/lint": "^6.9.5", "@icons-pack/react-simple-icons": "^13.13.0", From 464b9fa86ec7fd9e2d4d74edcab8b40d5ee9b6fc Mon Sep 17 00:00:00 2001 From: nicosammito Date: Thu, 9 Jul 2026 17:59:27 +0200 Subject: [PATCH 12/36] feat: simplify button group in UserEditDialogComponent and enhance layout --- .../components/UserEditDialogComponent.tsx | 67 +++++++------------ 1 file changed, 26 insertions(+), 41 deletions(-) diff --git a/src/packages/ce/src/user/components/UserEditDialogComponent.tsx b/src/packages/ce/src/user/components/UserEditDialogComponent.tsx index 75bebbe3..5df7832d 100644 --- a/src/packages/ce/src/user/components/UserEditDialogComponent.tsx +++ b/src/packages/ce/src/user/components/UserEditDialogComponent.tsx @@ -2,8 +2,8 @@ import React from "react"; import { + Badge, Button, - ButtonGroup, Card, Col, Dialog, @@ -31,7 +31,7 @@ import {Tab, TabContent, TabList, TabTrigger} from "@code0-tech/pictor/dist/comp import {User, UsersUpdateInput} from "@code0-tech/sagittarius-graphql-types"; import {UserService} from "@edition/user/services/User.service"; import {addIslandSuccessNotification} from "@code0-tech/pictor/dist/components/island/Island.hook"; -import {IconAt, IconLock, IconMail, IconUser, IconX} from "@tabler/icons-react"; +import {IconAt, IconLock, IconMail, IconUser} from "@tabler/icons-react"; import {Layout} from "@code0-tech/pictor/dist/components/layout/Layout"; import {motion} from "framer-motion"; @@ -151,20 +151,19 @@ export const UserEditDialogComponent: React.FC = ( }} initial={{ width: "200px", - opacity: 0.25, }} whileInView={{ width: "200px", - opacity: 0.25, }} whileHover={{ width: "250px", - opacity: 1, }} style={{ padding: "0.7rem", - marginTop: "0.55rem", - height: "100%" + paddingTop: "1rem", + height: "100%", + display: "flex", + flexDirection: "column" }} > @@ -193,23 +192,24 @@ export const UserEditDialogComponent: React.FC = ( + + + }> General - - - - - - + @@ -254,18 +254,10 @@ export const UserEditDialogComponent: React.FC = ( Permissions - - - - - - - + @@ -285,17 +277,10 @@ export const UserEditDialogComponent: React.FC = ( Security - - - - - - + From aa048df354758998d23bee4f6a6007dc08c6a0e4 Mon Sep 17 00:00:00 2001 From: nicosammito Date: Thu, 9 Jul 2026 18:03:28 +0200 Subject: [PATCH 13/36] feat: create NamespacesPage component for organization creation --- src/app/(dashboard)/organizations/page.tsx | 5 ----- .../{organizations => workspaces}/create/page.tsx | 0 src/app/(dashboard)/workspaces/page.tsx | 5 +++++ 3 files changed, 5 insertions(+), 5 deletions(-) delete mode 100644 src/app/(dashboard)/organizations/page.tsx rename src/app/(dashboard)/{organizations => workspaces}/create/page.tsx (100%) create mode 100644 src/app/(dashboard)/workspaces/page.tsx diff --git a/src/app/(dashboard)/organizations/page.tsx b/src/app/(dashboard)/organizations/page.tsx deleted file mode 100644 index e49f829e..00000000 --- a/src/app/(dashboard)/organizations/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import {OrganizationsPage} from "@edition/organization/pages/OrganizationsPage"; - -export default function Page() { - return -} diff --git a/src/app/(dashboard)/organizations/create/page.tsx b/src/app/(dashboard)/workspaces/create/page.tsx similarity index 100% rename from src/app/(dashboard)/organizations/create/page.tsx rename to src/app/(dashboard)/workspaces/create/page.tsx diff --git a/src/app/(dashboard)/workspaces/page.tsx b/src/app/(dashboard)/workspaces/page.tsx new file mode 100644 index 00000000..9b5c4961 --- /dev/null +++ b/src/app/(dashboard)/workspaces/page.tsx @@ -0,0 +1,5 @@ +"use client" + +import {NamespacesPage} from "@edition/namespace/pages/NamespacesPage"; + +export default NamespacesPage From 95d2a1fe8b244366f1aa991503d6c21fd2c29519 Mon Sep 17 00:00:00 2001 From: nicosammito Date: Thu, 9 Jul 2026 19:26:21 +0200 Subject: [PATCH 14/36] feat: add Workspaces button to ApplicationBarView for improved navigation --- src/packages/ce/src/application/views/ApplicationBarView.tsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/packages/ce/src/application/views/ApplicationBarView.tsx b/src/packages/ce/src/application/views/ApplicationBarView.tsx index 7b58ba1a..e85fbc3f 100644 --- a/src/packages/ce/src/application/views/ApplicationBarView.tsx +++ b/src/packages/ce/src/application/views/ApplicationBarView.tsx @@ -60,6 +60,10 @@ export const ApplicationBarView: React.FC = () => { aria-selected={pathname === "/"} onClick={() => router.push(`/`)}> {pathname === "/" ? Home : } , + , ...(currentUser?.admin ? [ + + + + + + return +
+ + + + Overview + + + + Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor
+ invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam + et +
+ + + + + + + Organizations + + + + +2 last month + + -
+ + + + + 7 + + + You are the owner of 3 organizations
and a member of 4 +
+
+
+
+ + + + + + Projects + + + + +8 last week + + + + + + + + 82 + + + You are the owner of 40 projects
and a member of 42 +
+
+
+
+ + + + + + Flows + + + + +102 last month + + + + + + + + 781 + + + You are the owner of 361 flows
and a member of 420 +
+
+
+
+ + + + + Overview + + + + Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor
+ invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam + et +
+ + + + + + + Personal projects + + + + + + + + + + + + + + Top organizations + + + + + + + + + + + + + + + + + } \ No newline at end of file From 507d9959cb3675306b57e4828584f239dc3daa53 Mon Sep 17 00:00:00 2001 From: nicosammito Date: Thu, 9 Jul 2026 19:26:47 +0200 Subject: [PATCH 16/36] feat: remove redundant header from OrganizationsTopView for cleaner UI --- .../src/organization/views/OrganizationsTopView.tsx | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/packages/ce/src/organization/views/OrganizationsTopView.tsx b/src/packages/ce/src/organization/views/OrganizationsTopView.tsx index 60a36763..bab3740c 100644 --- a/src/packages/ce/src/organization/views/OrganizationsTopView.tsx +++ b/src/packages/ce/src/organization/views/OrganizationsTopView.tsx @@ -1,6 +1,5 @@ "use client" -import {Flex, Spacing, Text} from "@code0-tech/pictor"; import React from "react"; import {useRouter} from "next/navigation"; import {OrganizationDataTableComponent} from "@edition/organization/components/OrganizationDataTableComponent"; @@ -10,16 +9,6 @@ export const OrganizationsTopView = () => { const router = useRouter() return <> - - - Top organizations - - - Manage organizations that you belong to. You can create new organizations and switch between them. - - - - {/**TODO: use namespaceId*/} index < 5} onSelect={(organization) => { From 432bae45999ee0e1405dcae3dee9a5fa9650a5ab Mon Sep 17 00:00:00 2001 From: nicosammito Date: Thu, 9 Jul 2026 19:27:00 +0200 Subject: [PATCH 17/36] feat: remove unnecessary UI elements from PersonalProjectsView for improved clarity --- .../project/views/PersonalProjectsView.tsx | 85 ------------------- 1 file changed, 85 deletions(-) diff --git a/src/packages/ce/src/project/views/PersonalProjectsView.tsx b/src/packages/ce/src/project/views/PersonalProjectsView.tsx index b4b719f8..013a4c7f 100644 --- a/src/packages/ce/src/project/views/PersonalProjectsView.tsx +++ b/src/packages/ce/src/project/views/PersonalProjectsView.tsx @@ -46,91 +46,6 @@ export const PersonalProjectsView: React.FC = () => { }, [currentUser, filter, sort]) return <> - - - - - Personal projects - - - Projects created in your personal namespace. You can also create organization projects if you are a - member of any organization. - - - - - - - - - - - - - { - if (sort["name"] === undefined) - setSort(prev => ({...prev, name: "asc"})) - else if (sort["name"] === "asc") - setSort(prev => ({...prev, name: "desc"})) - else - setSort(prev => ({...prev, name: undefined})) - - event.preventDefault() - event.stopPropagation() - }}> - {sort["name"] === undefined ? : sort["name"] === "asc" ? - : } - Name - - { - if (sort["createdAt"] === undefined) - setSort(prev => ({...prev, createdAt: "asc"})) - else if (sort["createdAt"] === "asc") - setSort(prev => ({...prev, createdAt: "desc"})) - else - setSort(prev => ({...prev, createdAt: undefined})) - - event.preventDefault() - event.stopPropagation() - }}> - {sort["createdAt"] === undefined ? - : sort["createdAt"] === "asc" ? - : } - Created At - - { - if (sort["updatedAt"] === undefined) - setSort(prev => ({...prev, updatedAt: "asc"})) - else if (sort["updatedAt"] === "asc") - setSort(prev => ({...prev, updatedAt: "desc"})) - else - setSort(prev => ({...prev, updatedAt: undefined})) - - event.preventDefault() - event.stopPropagation() - }}> - {sort["updatedAt"] === undefined ? - : sort["updatedAt"] === "asc" ? - : } - Updated At - - - - - - - -
- setFilter(filter)}/> -
- {projectsList} From 0e766237835a71ea50f9da9cd0c690ca2324da3c Mon Sep 17 00:00:00 2001 From: nicosammito Date: Thu, 9 Jul 2026 19:27:13 +0200 Subject: [PATCH 18/36] feat: add namespaceMemberships query and update User service for improved data retrieval --- src/packages/ce/src/user/services/User.service.ts | 12 +++++++++++- .../user/services/fragments/User.fragment.graphql | 13 +++++++++++++ .../src/user/services/queries/Users.query.graphql | 11 ++++++++++- 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/src/packages/ce/src/user/services/User.service.ts b/src/packages/ce/src/user/services/User.service.ts index f5bb9b39..95d9252e 100644 --- a/src/packages/ce/src/user/services/User.service.ts +++ b/src/packages/ce/src/user/services/User.service.ts @@ -61,7 +61,17 @@ export class UserService extends ReactiveArrayService { values(): User[] { if (super.values().length > 0) return super.values(); this.client.query({ - query: usersQuery + query: usersQuery, + variables: { + firstUser: 50, + afterUser: null, + firstIdentity: 50, + afterIdentity: null, + firstSession: 50, + afterSession: null, + firstNamespaceMembership: 50, + afterNamespaceMembership: null, + } }).then(result => { const data = result.data if (!data) return diff --git a/src/packages/ce/src/user/services/fragments/User.fragment.graphql b/src/packages/ce/src/user/services/fragments/User.fragment.graphql index d2cc7939..3aa47f58 100644 --- a/src/packages/ce/src/user/services/fragments/User.fragment.graphql +++ b/src/packages/ce/src/user/services/fragments/User.fragment.graphql @@ -14,6 +14,19 @@ fragment User on User { namespace { id } + namespaceMemberships (first: $firstNamespaceMembership, after: $afterNamespaceMembership) { + count + nodes { + id + namespace { + id + } + } + pageInfo { + endCursor + hasNextPage + } + } identities (first: $firstIdentity, after: $afterIdentity) { count nodes { diff --git a/src/packages/ce/src/user/services/queries/Users.query.graphql b/src/packages/ce/src/user/services/queries/Users.query.graphql index 6cac0624..242ba7e0 100644 --- a/src/packages/ce/src/user/services/queries/Users.query.graphql +++ b/src/packages/ce/src/user/services/queries/Users.query.graphql @@ -1,7 +1,16 @@ #import '../fragments/User.fragment.graphql' #import '../fragments/User.basic.fragment.graphql' -query Users($firstUser: Int, $afterUser: String, $firstIdentity: Int, $afterIdentity: String, $firstSession: Int, $afterSession: String) { +query Users( + $firstUser: Int, + $afterUser: String, + $firstIdentity: Int, + $afterIdentity: String, + $firstSession: Int, + $afterSession: String, + $firstNamespaceMembership: Int, + $afterNamespaceMembership: String +) { currentUser { ...User } From 71e687514daa17e6c7533f45d46cae8155a584e7 Mon Sep 17 00:00:00 2001 From: nicosammito Date: Thu, 9 Jul 2026 19:27:35 +0200 Subject: [PATCH 19/36] feat: add Namespace data table components for improved namespace management --- .../NamespaceDataTableComponent.tsx | 81 ++++++++++ ...NamespaceDataTableFilterInputComponent.tsx | 140 ++++++++++++++++++ .../NamespaceDataTableRowComponent.tsx | 115 ++++++++++++++ 3 files changed, 336 insertions(+) create mode 100644 src/packages/ce/src/namespace/components/NamespaceDataTableComponent.tsx create mode 100644 src/packages/ce/src/namespace/components/NamespaceDataTableFilterInputComponent.tsx create mode 100644 src/packages/ce/src/namespace/components/NamespaceDataTableRowComponent.tsx diff --git a/src/packages/ce/src/namespace/components/NamespaceDataTableComponent.tsx b/src/packages/ce/src/namespace/components/NamespaceDataTableComponent.tsx new file mode 100644 index 00000000..a223eb6a --- /dev/null +++ b/src/packages/ce/src/namespace/components/NamespaceDataTableComponent.tsx @@ -0,0 +1,81 @@ +import React from "react"; +import {DataTable, DataTableColumn, Text, useService, useStore} from "@code0-tech/pictor"; +import {DataTableFilterProps, DataTableSortProps} from "@code0-tech/pictor/dist/components/data-table/DataTable"; +import {Namespace} from "@code0-tech/sagittarius-graphql-types"; +import {NamespaceDataTableRowComponent} from "@edition/namespace/components/NamespaceDataTableRowComponent"; +import {NamespaceService} from "@edition/namespace/services/Namespace.service"; +import {OrganizationService} from "@edition/organization/services/Organization.service"; +import {MemberService} from "@edition/member/services/Member.service"; +import {UserService} from "@edition/user/services/User.service"; +import {useUserSession} from "@edition/user/hooks/User.session.hook"; +import {getNamespaceName} from "@edition/namespace/util/Namespace.name.util"; + +export type NamespaceRow = Namespace & { name?: string } + +export interface NamespaceDataTableComponentProps { + sort?: DataTableSortProps + filter?: DataTableFilterProps + preFilter?: (namespace: Namespace, index: number) => boolean + onSelect?: (item: Namespace | undefined) => void + minimized?: boolean +} + +export const NamespaceDataTableComponent: React.FC = (props) => { + + const {sort, filter, preFilter = () => true, onSelect, minimized} = props + + const namespaceService = useService(NamespaceService) + const namespaceStore = useStore(NamespaceService) + const organizationService = useService(OrganizationService) + const organizationStore = useStore(OrganizationService) + const memberService = useService(MemberService) + const memberStore = useStore(MemberService) + const userService = useService(UserService) + const userStore = useStore(UserService) + + const currentSession = useUserSession() + + const currentUser = React.useMemo( + () => userService.getById(currentSession?.user?.id), + [userStore, currentSession?.user?.id] + ) + + const memberships = React.useMemo( + () => currentUser?.namespaceMemberships?.nodes ?? [], + [currentUser?.namespaceMemberships?.nodes?.length] + ) + + const data = React.useMemo( + () => memberships.map(membership => { + const namespace = namespaceService.getById(membership?.namespace?.id) + if (!namespace) return undefined + + const members = memberService.values({namespaceId: namespace.id}) + const row: NamespaceRow = { + ...namespace, + name: getNamespaceName(namespace, organizationService, userService), + members: { + ...namespace.members, + nodes: members, + } + } + return row + }).filter((namespace): namespace is NamespaceRow => !!namespace).filter(preFilter), + [memberships.length, namespaceStore, memberStore, organizationStore, userStore, preFilter] + ) + + return + + No workspace found. Create one to get started. + + } + onSelect={(item) => item && onSelect?.(item)} + data={data}> + {(namespace, index) => { + return + }} + + +} diff --git a/src/packages/ce/src/namespace/components/NamespaceDataTableFilterInputComponent.tsx b/src/packages/ce/src/namespace/components/NamespaceDataTableFilterInputComponent.tsx new file mode 100644 index 00000000..b0f48bf9 --- /dev/null +++ b/src/packages/ce/src/namespace/components/NamespaceDataTableFilterInputComponent.tsx @@ -0,0 +1,140 @@ +import React from "react"; +import { + DataTableFilterInput, + DataTableFilterSuggestionMenu, + MenuCheckboxItem, + useService, + useStore +} from "@code0-tech/pictor"; +import {IconCheck} from "@tabler/icons-react"; +import {DataTableFilterProps} from "@code0-tech/pictor/dist/components/data-table/DataTable"; +import {NamespaceService} from "@edition/namespace/services/Namespace.service"; +import {OrganizationService} from "@edition/organization/services/Organization.service"; +import {MemberService} from "@edition/member/services/Member.service"; +import {UserService} from "@edition/user/services/User.service"; +import {useUserSession} from "@edition/user/hooks/User.session.hook"; +import {getNamespaceName} from "@edition/namespace/util/Namespace.name.util"; + +export interface NamespaceDataTableFilterInputComponentProps { + onChange: (filter: DataTableFilterProps) => void +} + +export const NamespaceDataTableFilterInputComponent: React.FC = (props) => { + + const {onChange} = props + + const namespaceService = useService(NamespaceService) + const namespaceStore = useStore(NamespaceService) + const organizationService = useService(OrganizationService) + const organizationStore = useStore(OrganizationService) + const memberService = useService(MemberService) + const memberStore = useStore(MemberService) + const userService = useService(UserService) + const userStore = useStore(UserService) + + const currentSession = useUserSession() + + const currentUser = React.useMemo( + () => userService.getById(currentSession?.user?.id), + [userStore, currentSession] + ) + + const memberships = React.useMemo( + () => currentUser?.namespaceMemberships?.nodes ?? [], + [currentUser] + ) + + const namespaces = React.useMemo( + () => memberships.map( + membership => namespaceService.getById(membership?.namespace?.id) + ).filter(namespace => !!namespace), + [namespaceStore, memberships] + ) + + const members = React.useMemo( + () => { + // A user can be a member of several namespaces; keep one entry per username + // since the suggestions filter on the username. + const seen = new Set() + return namespaces.map( + namespace => memberService.values({namespaceId: namespace?.id}) + ).flat().filter(member => { + const username = member?.user?.username + if (!username || seen.has(username)) return false + seen.add(username) + return true + }) + }, + [namespaces, memberStore] + ) + + // The editor inside DataTableFilterInput builds its suggestion extension once on + // mount, so the suggestion callbacks would otherwise close over the empty arrays + // of the first render. Refs let them read the latest data at invocation time. + const namespacesRef = React.useRef(namespaces) + const membersRef = React.useRef(members) + + React.useEffect(() => { + namespacesRef.current = namespaces + membersRef.current = members + }, [namespaces, members]) + + return { + + const split = currentValue.split(",").map(s => s.trim()).filter(Boolean) + + return + {namespacesRef.current.map(namespace => { + + const name = getNamespaceName(namespace, organizationService, userService) + const isChecked = split.includes(name!) + + return { + e.preventDefault(); + e.stopPropagation(); + const updated = isChecked + ? split.filter(n => n !== name) + : [...split, name]; + applySuggestion(updated.join(","), true); + }}> + {isChecked ? : } + {name} + + })} + + } + }, { + token: "Member", + key: "members.nodes.user.username", + operators: ["isOneOf"], + suggestion: (context, operator, currentValue, applySuggestion) => { + + const split = currentValue.split(",").map(s => s.trim()).filter(Boolean) + + return + {membersRef.current.map(member => { + + const isChecked = split.includes(member?.user?.username!) + + return { + e.preventDefault(); + e.stopPropagation(); + const updated = isChecked + ? split.filter(name => name !== member?.user?.username) + : [...split, member?.user?.username]; + applySuggestion(updated.join(","), true); + }}> + {isChecked ? : } + @{member?.user?.username} + + })} + + } + } + ]}/> +} diff --git a/src/packages/ce/src/namespace/components/NamespaceDataTableRowComponent.tsx b/src/packages/ce/src/namespace/components/NamespaceDataTableRowComponent.tsx new file mode 100644 index 00000000..5b816af7 --- /dev/null +++ b/src/packages/ce/src/namespace/components/NamespaceDataTableRowComponent.tsx @@ -0,0 +1,115 @@ +import React from "react"; +import {Namespace} from "@code0-tech/sagittarius-graphql-types"; +import {Avatar, Button, DataTableColumn, Flex, hashToColor, Text, useService, useStore} from "@code0-tech/pictor"; +import {IconLogout} from "@tabler/icons-react"; +import {NamespaceService} from "@edition/namespace/services/Namespace.service"; +import {OrganizationService} from "@edition/organization/services/Organization.service"; +import {MemberService} from "@edition/member/services/Member.service"; +import {UserService} from "@edition/user/services/User.service"; +import {formatDistanceToNow} from "date-fns"; +import {useUserSession} from "@edition/user/hooks/User.session.hook"; +import {getNamespaceName} from "@edition/namespace/util/Namespace.name.util"; + +export interface NamespaceDataTableRowComponentProps { + namespaceId: Namespace['id'] + onLeave?: (namespace: Namespace) => void + minimized?: boolean +} + +export const NamespaceDataTableRowComponent: React.FC = (props) => { + + const {namespaceId, onLeave, minimized} = props + + const namespaceService = useService(NamespaceService) + const namespaceStore = useStore(NamespaceService) + const organizationService = useService(OrganizationService) + const organizationStore = useStore(OrganizationService) + const memberService = useService(MemberService) + const memberStore = useStore(MemberService) + const userService = useService(UserService) + const userStore = useStore(UserService) + + const currentSession = useUserSession() + + const currentUser = React.useMemo( + () => userService.getById(currentSession?.user?.id), + [userStore, currentSession] + ) + + const namespace = React.useMemo( + () => namespaceService.getById(namespaceId), + [namespaceStore, namespaceId] + ) + + const name = React.useMemo( + () => getNamespaceName(namespace, organizationService, userService), + [namespace, organizationStore, userStore] + ) + + const namespaceMember = React.useMemo( + () => namespace && currentUser ? memberService.getByNamespaceIdAndUserId(namespace.id, currentUser.id) : null, + [memberStore, namespace, currentUser] + ) + + return <> + + + + + + + {name} + + + + {!minimized && ( + + Updated {formatDistanceToNow(namespace?.updatedAt!)} ago + + )} + + + + {!minimized && ( + <> + + + {namespace?.projects?.count ? ( + + {namespace?.projects?.count ?? 0} {" "} + projects + + ) : null} + + {namespace?.members?.count ? ( + + {namespace?.members?.count ?? 0}{" "} + members + + ) : null} + + {namespace?.runtimes?.count ? ( + + {namespace?.runtimes?.count ?? 0}{" "} + connected runtimes + + ) : null} + + + {onLeave && namespaceMember && namespaceMember.userAbilities?.deleteMember ? ( + + + + ) : null} + + )} + + +} From 8aaebc764d0297485fd810bec220edbf145f835f Mon Sep 17 00:00:00 2001 From: nicosammito Date: Thu, 9 Jul 2026 19:27:41 +0200 Subject: [PATCH 20/36] feat: add utility function to derive namespace display names from parent entities --- .../src/namespace/util/Namespace.name.util.ts | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 src/packages/ce/src/namespace/util/Namespace.name.util.ts diff --git a/src/packages/ce/src/namespace/util/Namespace.name.util.ts b/src/packages/ce/src/namespace/util/Namespace.name.util.ts new file mode 100644 index 00000000..16bcc663 --- /dev/null +++ b/src/packages/ce/src/namespace/util/Namespace.name.util.ts @@ -0,0 +1,21 @@ +import {Namespace} from "@code0-tech/sagittarius-graphql-types"; +import {OrganizationService} from "@edition/organization/services/Organization.service"; +import {UserService} from "@edition/user/services/User.service"; + +/** + * A namespace has no own name. Its display name is derived from its parent: + * the organization name or the username of the user it belongs to. + */ +export const getNamespaceName = ( + namespace: Namespace | undefined | null, + organizationService: OrganizationService, + userService: UserService +): string | undefined => { + if (!namespace?.parent) return undefined + if (namespace.parent.__typename === "Organization") + return organizationService.getById(namespace.parent.id)?.name ?? undefined + if (namespace.parent.__typename === "User") + return userService.getById(namespace.parent.id)?.username ? + `@${userService.getById(namespace.parent.id)?.username}'s workspace` : undefined + return undefined +} From 25c3477eb182e66e75923136066356f0bdc6016a Mon Sep 17 00:00:00 2001 From: nicosammito Date: Thu, 9 Jul 2026 19:27:45 +0200 Subject: [PATCH 21/36] feat: add NamespacesPage and NamespacesView components for namespace management --- .../ce/src/namespace/pages/NamespacesPage.tsx | 90 +++++++++++++ .../ce/src/namespace/views/NamespacesView.tsx | 124 ++++++++++++++++++ 2 files changed, 214 insertions(+) create mode 100644 src/packages/ce/src/namespace/pages/NamespacesPage.tsx create mode 100644 src/packages/ce/src/namespace/views/NamespacesView.tsx diff --git a/src/packages/ce/src/namespace/pages/NamespacesPage.tsx b/src/packages/ce/src/namespace/pages/NamespacesPage.tsx new file mode 100644 index 00000000..7edc513d --- /dev/null +++ b/src/packages/ce/src/namespace/pages/NamespacesPage.tsx @@ -0,0 +1,90 @@ +"use client" + +import React from "react"; +import {NamespacesView} from "@edition/namespace/views/NamespacesView"; +import { + AuroraBackground, + Avatar, + Badge, + Button, + Flex, + ScrollArea, + ScrollAreaScrollbar, + ScrollAreaThumb, + ScrollAreaViewport, + Spacing, + Text, + useService, + useStore +} from "@code0-tech/pictor"; +import {IconMail, IconSparkles, IconUser} from "@tabler/icons-react"; +import {UserService} from "@edition/user/services/User.service"; +import {useUserSession} from "@edition/user/hooks/User.session.hook"; +import {Layout} from "@code0-tech/pictor/dist/components/layout/Layout"; + +export const NamespacesPage = () => { + + + const userStore = useStore(UserService) + const userService = useService(UserService) + + const userSession = useUserSession() + const currentUser = React.useMemo(() => userService.getById(userSession?.user?.id), [userStore, userSession]) + + const leftContent = + + +
+ + + 👋 + +
+ + {currentUser?.firstname} {currentUser?.lastname} + + + + + @{currentUser?.username} + + + + {currentUser?.email} + + + + BASIC + + + + + + +
+
+
+ + return +
+ + + + + + + + +
+
+ +} diff --git a/src/packages/ce/src/namespace/views/NamespacesView.tsx b/src/packages/ce/src/namespace/views/NamespacesView.tsx new file mode 100644 index 00000000..b125bef6 --- /dev/null +++ b/src/packages/ce/src/namespace/views/NamespacesView.tsx @@ -0,0 +1,124 @@ +"use client" + +import { + Button, + Flex, + Menu, + MenuCheckboxItem, + MenuContent, + MenuPortal, + MenuTrigger, + Spacing, + Text +} from "@code0-tech/pictor"; +import Link from "next/link"; +import React from "react"; +import {useRouter} from "next/navigation"; +import {NamespaceDataTableComponent} from "@edition/namespace/components/NamespaceDataTableComponent"; +import { + NamespaceDataTableFilterInputComponent +} from "@edition/namespace/components/NamespaceDataTableFilterInputComponent"; +import {DataTableFilterProps, DataTableSortProps} from "@code0-tech/pictor/dist/components/data-table/DataTable"; +import {ButtonGroup} from "@code0-tech/pictor/dist/components/button-group/ButtonGroup"; +import {IconMinus, IconSortAscending, IconSortDescending} from "@tabler/icons-react"; + +export const NamespacesView = () => { + + const router = useRouter() + + const [filter, setFilter] = React.useState({}) + const [sort, setSort] = React.useState({}) + + return <> + +
+ + Workspaces + + + + Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor
+ invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam + et +
+
+ + + + + + + + + + + { + if (sort["name"] === undefined) + setSort(prev => ({...prev, name: "asc"})) + else if (sort["name"] === "asc") + setSort(prev => ({...prev, name: "desc"})) + else + setSort(prev => ({...prev, name: undefined})) + + event.preventDefault() + event.stopPropagation() + }}> + {sort["name"] === undefined ? : sort["name"] === "asc" ? + : } + Name + + { + if (sort["createdAt"] === undefined) + setSort(prev => ({...prev, createdAt: "asc"})) + else if (sort["createdAt"] === "asc") + setSort(prev => ({...prev, createdAt: "desc"})) + else + setSort(prev => ({...prev, createdAt: undefined})) + + event.preventDefault() + event.stopPropagation() + }}> + {sort["createdAt"] === undefined ? + : sort["createdAt"] === "asc" ? + : } + Created At + + { + if (sort["updatedAt"] === undefined) + setSort(prev => ({...prev, updatedAt: "asc"})) + else if (sort["updatedAt"] === "asc") + setSort(prev => ({...prev, updatedAt: "desc"})) + else + setSort(prev => ({...prev, updatedAt: undefined})) + + event.preventDefault() + event.stopPropagation() + }}> + {sort["updatedAt"] === undefined ? + : sort["updatedAt"] === "asc" ? + : } + Updated At + + + + + +
+ +
+ setFilter(filter)}/> +
+ + { + const number = namespace?.id?.match(/Namespace\/(\d+)$/)?.[1] + router.push(`/namespace/${number}`) + }}/> + + +} From 66ad965fbb5768b830a1a4ae62662fdfa2df474d Mon Sep 17 00:00:00 2001 From: nicosammito Date: Thu, 9 Jul 2026 19:39:21 +0200 Subject: [PATCH 22/36] feat: enhance user retrieval logic in User service and NamespaceDataTableComponent --- .../namespace/components/NamespaceDataTableComponent.tsx | 2 +- src/packages/ce/src/user/services/User.service.ts | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/packages/ce/src/namespace/components/NamespaceDataTableComponent.tsx b/src/packages/ce/src/namespace/components/NamespaceDataTableComponent.tsx index a223eb6a..f5637caa 100644 --- a/src/packages/ce/src/namespace/components/NamespaceDataTableComponent.tsx +++ b/src/packages/ce/src/namespace/components/NamespaceDataTableComponent.tsx @@ -37,7 +37,7 @@ export const NamespaceDataTableComponent: React.FC userService.getById(currentSession?.user?.id), - [userStore, currentSession?.user?.id] + [userStore, userService, currentSession?.user?.id] ) const memberships = React.useMemo( diff --git a/src/packages/ce/src/user/services/User.service.ts b/src/packages/ce/src/user/services/User.service.ts index 95d9252e..288dbf67 100644 --- a/src/packages/ce/src/user/services/User.service.ts +++ b/src/packages/ce/src/user/services/User.service.ts @@ -76,7 +76,11 @@ export class UserService extends ReactiveArrayService { const data = result.data if (!data) return - if (data && data.currentUser && !this.hasById(data.currentUser.id)) this.set(this.i++, new View(data.currentUser)) + if (data && data.currentUser) { + const currentUser = data.currentUser + const index = super.values().findIndex(user => user && user.id === currentUser.id) + this.set(index >= 0 ? index : this.i++, new View(currentUser)) + } if (data.users && data.users.nodes) { data.users.nodes.forEach((user) => { if (user && !(user.id === data.currentUser?.id) && !this.hasById(user.id)) this.set(this.i++, new View(user)) @@ -87,7 +91,7 @@ export class UserService extends ReactiveArrayService { } getById(id: User["id"]): User | undefined { - const user = this.values().find(user => user && user.id === id) + const user = super.values().find(user => user && user.id === id) if (user) return user if (id) { From d92b09c4d1eb60d3d5c149d2795b74529d2a1ee6 Mon Sep 17 00:00:00 2001 From: nicosammito Date: Fri, 10 Jul 2026 10:31:47 +0200 Subject: [PATCH 23/36] feat: simplify ApplicationBarView by removing unused icons and improving button text --- .../application/views/ApplicationBarView.tsx | 63 ++++++++++--------- 1 file changed, 32 insertions(+), 31 deletions(-) diff --git a/src/packages/ce/src/application/views/ApplicationBarView.tsx b/src/packages/ce/src/application/views/ApplicationBarView.tsx index e85fbc3f..45c7547f 100644 --- a/src/packages/ce/src/application/views/ApplicationBarView.tsx +++ b/src/packages/ce/src/application/views/ApplicationBarView.tsx @@ -6,19 +6,14 @@ import {useParams, usePathname, useRouter} from "next/navigation"; import React from "react"; import Link from "next/link"; import { - IconBox, + IconArrowLeft, + IconArrowUpRight, IconBuilding, IconFolders, - IconHome, IconInbox, IconLogout, - IconRoute, IconSearch, - IconServer, - IconSettings, - IconUser, - IconUserCog, - IconUsers + IconUser } from "@tabler/icons-react"; import {ApplicationBreadcrumbView} from "@edition/application/views/ApplicationBreadcrumbView"; import UserMenuComponent from "@edition/user/components/UserMenuComponent"; @@ -58,24 +53,24 @@ export const ApplicationBarView: React.FC = () => { return [ , , ...(currentUser?.admin ? [ , , ] : []) ] @@ -91,29 +86,25 @@ export const ApplicationBarView: React.FC = () => { return [ , - , , , , ...(showSettings ? [ ] : []) ] @@ -125,19 +116,19 @@ export const ApplicationBarView: React.FC = () => { return [ , - , , + , ] }, [namespaceIndex, projectIndex, pathname]) @@ -184,11 +175,21 @@ export const ApplicationBarView: React.FC = () => { }, [currentUser, currentSession, userNamespaceIndex]) return - + {currentStep === "project" ? + + : currentStep === "namespace" ? + + :
} - + {currentStep === "project" ? projectTabs : currentStep === "namespace" ? namespaceTabs : homeTabs} From 3e5486e5c5cb56aa38d67e2f2bb2e2147d48513b Mon Sep 17 00:00:00 2001 From: nicosammito Date: Fri, 10 Jul 2026 10:32:00 +0200 Subject: [PATCH 24/36] feat: enhance ApplicationPage with button groups for project and organization creation --- .../src/application/pages/ApplicationPage.tsx | 36 +++++++++++++++---- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/src/packages/ce/src/application/pages/ApplicationPage.tsx b/src/packages/ce/src/application/pages/ApplicationPage.tsx index 94a94e17..2dc7ac22 100644 --- a/src/packages/ce/src/application/pages/ApplicationPage.tsx +++ b/src/packages/ce/src/application/pages/ApplicationPage.tsx @@ -4,6 +4,7 @@ import { Avatar, Badge, Button, + ButtonGroup, Card, Col, Flex, @@ -21,8 +22,9 @@ import {UserService} from "@edition/user/services/User.service"; import React from "react"; import {OrganizationsTopView} from "@edition/organization/views/OrganizationsTopView"; import {useUserSession} from "@edition/user/hooks/User.session.hook"; -import {IconMail, IconSparkles, IconTrendingUp, IconUser} from "@tabler/icons-react"; +import {IconArrowUpRight, IconMail, IconSparkles, IconTrendingUp, IconUser} from "@tabler/icons-react"; import {Layout} from "@code0-tech/pictor/dist/components/layout/Layout"; +import Link from "next/link"; export const ApplicationPage = () => { @@ -31,6 +33,7 @@ export const ApplicationPage = () => { const userSession = useUserSession() const currentUser = React.useMemo(() => userService.getById(userSession?.user?.id), [userStore, userSession]) + const namespaceIndex = currentUser?.namespace?.id?.match(/Namespace\/(\d+)$/)?.[1] const leftContent = @@ -184,9 +187,19 @@ export const ApplicationPage = () => { Personal projects - + + + + + + + + + @@ -200,9 +213,18 @@ export const ApplicationPage = () => { Top organizations - + + + + + + + + From 5645759262622a2bba3757c81082037c82a3642e Mon Sep 17 00:00:00 2001 From: nicosammito Date: Fri, 10 Jul 2026 10:32:12 +0200 Subject: [PATCH 25/36] feat: update NamespaceOverviewOrganizationLeftView to link to organization settings --- .../views/NamespaceOverviewOrganizationLeftView.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/packages/ce/src/namespace/views/NamespaceOverviewOrganizationLeftView.tsx b/src/packages/ce/src/namespace/views/NamespaceOverviewOrganizationLeftView.tsx index 3aa6c1e3..2a643c17 100644 --- a/src/packages/ce/src/namespace/views/NamespaceOverviewOrganizationLeftView.tsx +++ b/src/packages/ce/src/namespace/views/NamespaceOverviewOrganizationLeftView.tsx @@ -63,9 +63,11 @@ export const NamespaceOverviewOrganizationLeftView: React.FC = () => { {parentOrganization?.name} - + + + - From 997d30380cfe6413f10bcada5ebdf3c2fe773ca5 Mon Sep 17 00:00:00 2001 From: nicosammito Date: Fri, 10 Jul 2026 10:32:19 +0200 Subject: [PATCH 26/36] feat: adjust layout padding in NamespaceOverviewPage for improved spacing --- src/packages/ce/src/namespace/pages/NamespaceOverviewPage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/packages/ce/src/namespace/pages/NamespaceOverviewPage.tsx b/src/packages/ce/src/namespace/pages/NamespaceOverviewPage.tsx index e2cf02a7..c50a3bd4 100644 --- a/src/packages/ce/src/namespace/pages/NamespaceOverviewPage.tsx +++ b/src/packages/ce/src/namespace/pages/NamespaceOverviewPage.tsx @@ -21,7 +21,7 @@ export const NamespaceOverviewPage: React.FC = () => { const namespaceIndexCurrentUser = currentUser?.namespace?.id?.match(/Namespace\/(\d+)$/)?.[1] const namespaceId = params.namespaceId as any as string - return : }>
Date: Fri, 10 Jul 2026 10:32:36 +0200 Subject: [PATCH 27/36] feat: refactor page component exports to directly export NamespaceOverviewPage and ApplicationPage --- src/app/(dashboard)/namespace/[namespaceId]/page.tsx | 4 +--- .../(dashboard)/namespace/[namespaceId]/projects/page.tsx | 5 ----- src/app/(dashboard)/page.tsx | 5 +---- 3 files changed, 2 insertions(+), 12 deletions(-) delete mode 100644 src/app/(dashboard)/namespace/[namespaceId]/projects/page.tsx diff --git a/src/app/(dashboard)/namespace/[namespaceId]/page.tsx b/src/app/(dashboard)/namespace/[namespaceId]/page.tsx index dbfc7343..7e9c8ab8 100644 --- a/src/app/(dashboard)/namespace/[namespaceId]/page.tsx +++ b/src/app/(dashboard)/namespace/[namespaceId]/page.tsx @@ -2,6 +2,4 @@ import {NamespaceOverviewPage} from "@edition/namespace/pages/NamespaceOverviewPage"; -export default function Page() { - return -} \ No newline at end of file +export default NamespaceOverviewPage \ No newline at end of file diff --git a/src/app/(dashboard)/namespace/[namespaceId]/projects/page.tsx b/src/app/(dashboard)/namespace/[namespaceId]/projects/page.tsx deleted file mode 100644 index b6743871..00000000 --- a/src/app/(dashboard)/namespace/[namespaceId]/projects/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import {NamespaceProjectsPage} from "@edition/namespace/pages/NamespaceProjectsPage"; - -export default function Page() { - return -} \ No newline at end of file diff --git a/src/app/(dashboard)/page.tsx b/src/app/(dashboard)/page.tsx index 7b4dd440..c749a281 100644 --- a/src/app/(dashboard)/page.tsx +++ b/src/app/(dashboard)/page.tsx @@ -1,8 +1,5 @@ "use client" -import React from "react"; import {ApplicationPage} from "@edition/application/pages/ApplicationPage"; -export default function Page() { - return -} +export default ApplicationPage From 299ceaac5234936b0badafb2e3463a9d9ac4da13 Mon Sep 17 00:00:00 2001 From: nicosammito Date: Fri, 10 Jul 2026 10:32:47 +0200 Subject: [PATCH 28/36] feat: improve layout and spacing in ProjectsView for better readability --- .../ce/src/project/views/ProjectsView.tsx | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/packages/ce/src/project/views/ProjectsView.tsx b/src/packages/ce/src/project/views/ProjectsView.tsx index 65c76a19..71f73b67 100644 --- a/src/packages/ce/src/project/views/ProjectsView.tsx +++ b/src/packages/ce/src/project/views/ProjectsView.tsx @@ -43,22 +43,23 @@ export const ProjectsView: React.FC = () => { return <> - - - + +
+ Projects - - Manage projects that you belong to. You can create new projects and switch between them. + + + Manage projects that you belong to.
You can create new projects and switch between them.
- +
- + - + From 148a3d980fee729327dd773b95b1fa4e7d182164 Mon Sep 17 00:00:00 2001 From: nicosammito Date: Fri, 10 Jul 2026 10:32:56 +0200 Subject: [PATCH 29/36] feat: update text hierarchy in UserEditDialogComponent for improved visibility --- src/packages/ce/src/user/components/UserEditDialogComponent.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/packages/ce/src/user/components/UserEditDialogComponent.tsx b/src/packages/ce/src/user/components/UserEditDialogComponent.tsx index 5df7832d..f14600d1 100644 --- a/src/packages/ce/src/user/components/UserEditDialogComponent.tsx +++ b/src/packages/ce/src/user/components/UserEditDialogComponent.tsx @@ -166,7 +166,7 @@ export const UserEditDialogComponent: React.FC = ( flexDirection: "column" }} > - + Settings of @{user?.username ?? ""} From 30df286194bce4308f9bffa32c50e435080a48d8 Mon Sep 17 00:00:00 2001 From: nicosammito Date: Fri, 10 Jul 2026 10:33:05 +0200 Subject: [PATCH 30/36] feat: clean up button props in UserMenuComponent for improved readability --- src/packages/ce/src/user/components/UserMenuComponent.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/packages/ce/src/user/components/UserMenuComponent.tsx b/src/packages/ce/src/user/components/UserMenuComponent.tsx index 0b4c1885..d69c9782 100644 --- a/src/packages/ce/src/user/components/UserMenuComponent.tsx +++ b/src/packages/ce/src/user/components/UserMenuComponent.tsx @@ -3,7 +3,8 @@ import React from "react" import {Scalars} from "@code0-tech/sagittarius-graphql-types"; import { - Avatar, Button, + Avatar, + Button, Flex, Menu, MenuContent, @@ -29,7 +30,7 @@ const UserMenuComponent: React.FC = props => { return ( -
From 90852a4e6d902a590749d7323820dfc1ce9111f5 Mon Sep 17 00:00:00 2001 From: nicosammito Date: Fri, 10 Jul 2026 15:25:26 +0200 Subject: [PATCH 33/36] feat: add createdAt field to Project fragment for enhanced data retrieval --- .../ce/src/project/services/fragments/Project.fragment.graphql | 1 + 1 file changed, 1 insertion(+) diff --git a/src/packages/ce/src/project/services/fragments/Project.fragment.graphql b/src/packages/ce/src/project/services/fragments/Project.fragment.graphql index 287c91f2..f28e8a0b 100644 --- a/src/packages/ce/src/project/services/fragments/Project.fragment.graphql +++ b/src/packages/ce/src/project/services/fragments/Project.fragment.graphql @@ -17,6 +17,7 @@ fragment Project on NamespaceProject { nodes { __typename id + createdAt } pageInfo { __typename From 19efa30ac633cf33a6ce25634b970efaab2bb68a Mon Sep 17 00:00:00 2001 From: nicosammito Date: Fri, 10 Jul 2026 15:25:39 +0200 Subject: [PATCH 34/36] feat: add NamespacesTopView component for improved namespace management --- .../src/namespace/views/NamespacesTopView.tsx | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 src/packages/ce/src/namespace/views/NamespacesTopView.tsx diff --git a/src/packages/ce/src/namespace/views/NamespacesTopView.tsx b/src/packages/ce/src/namespace/views/NamespacesTopView.tsx new file mode 100644 index 00000000..e6b84f14 --- /dev/null +++ b/src/packages/ce/src/namespace/views/NamespacesTopView.tsx @@ -0,0 +1,20 @@ +"use client" + +import React from "react"; +import {useRouter} from "next/navigation"; +import {NamespaceDataTableComponent} from "@edition/namespace/components/NamespaceDataTableComponent"; + +export const NamespacesTopView = () => { + + const router = useRouter() + + return <> + index < 5} onSelect={(namespace) => { + const number = namespace?.id?.match(/Namespace\/(\d+)$/)?.[1] + router.push(`/namespace/${number}`) + }}/> + + +} From d399f1bb0e6963bf15dd21dba3df903b65a2351b Mon Sep 17 00:00:00 2001 From: nicosammito Date: Fri, 10 Jul 2026 15:25:46 +0200 Subject: [PATCH 35/36] feat: enhance ApplicationPage with namespace and organization data integration --- .../src/application/pages/ApplicationPage.tsx | 98 +++++++++++++++---- 1 file changed, 79 insertions(+), 19 deletions(-) diff --git a/src/packages/ce/src/application/pages/ApplicationPage.tsx b/src/packages/ce/src/application/pages/ApplicationPage.tsx index 90e29dcd..14af16d7 100644 --- a/src/packages/ce/src/application/pages/ApplicationPage.tsx +++ b/src/packages/ce/src/application/pages/ApplicationPage.tsx @@ -19,22 +19,79 @@ import { useStore } from "@code0-tech/pictor"; import {UserService} from "@edition/user/services/User.service"; +import {NamespaceService} from "@edition/namespace/services/Namespace.service"; +import {OrganizationService} from "@edition/organization/services/Organization.service"; +import {OrganizationView} from "@edition/organization/services/Organization.view"; +import {ProjectService} from "@edition/project/services/Project.service"; +import {Namespace, Organization} from "@code0-tech/sagittarius-graphql-types"; import React from "react"; -import {OrganizationsTopView} from "@edition/organization/views/OrganizationsTopView"; +import {NamespacesTopView} from "@edition/namespace/views/NamespacesTopView"; import {useUserSession} from "@edition/user/hooks/User.session.hook"; import {IconArrowUpRight, IconMail, IconSparkles, IconTrendingUp, IconUser} from "@tabler/icons-react"; import {Layout} from "@code0-tech/pictor/dist/components/layout/Layout"; import Link from "next/link"; +const withinDays = (time: string | null | undefined, days: number): boolean => + !!time && Date.now() - new Date(time).getTime() < days * 24 * 60 * 60 * 1000 + export const ApplicationPage = () => { const userStore = useStore(UserService) const userService = useService(UserService) + const namespaceService = useService(NamespaceService) + const namespaceStore = useStore(NamespaceService) + const organizationService = useService(OrganizationService) + const organizationStore = useStore(OrganizationService) + const projectService = useService(ProjectService) + const projectStore = useStore(ProjectService) const userSession = useUserSession() const currentUser = React.useMemo(() => userService.getById(userSession?.user?.id), [userStore, userSession]) const namespaceIndex = currentUser?.namespace?.id?.match(/Namespace\/(\d+)$/)?.[1] + const memberships = React.useMemo( + () => currentUser?.namespaceMemberships?.nodes ?? [], + [currentUser?.namespaceMemberships?.nodes?.length] + ) + + const namespaces = React.useMemo( + () => memberships + .map(membership => namespaceService.getById(membership?.namespace?.id)) + .filter((namespace): namespace is Namespace => !!namespace), + [memberships.length, namespaceStore] + ) + + const organizationNamespaces = React.useMemo( + () => namespaces.filter(namespace => namespace.parent?.__typename === "Organization"), + [namespaces] + ) + + const organizations = React.useMemo( + () => organizationNamespaces + .map(namespace => organizationService.getById((namespace.parent as Organization).id)) + .filter((organization): organization is OrganizationView => !!organization), + [organizationNamespaces, organizationStore] + ) + + const projects = React.useMemo( + () => namespaces.flatMap(namespace => projectService.values({namespaceId: namespace.id})), + [namespaces, projectStore] + ) + + const ownedOrganizationsCount = organizations.filter(organization => organization.userAbilities?.deleteOrganization).length + const memberOrganizationsCount = organizationNamespaces.length - ownedOrganizationsCount + const newOrganizationsLastMonth = organizations.filter(organization => withinDays(organization.createdAt, 30)).length + + const totalProjectsCount = namespaces.reduce((sum, namespace) => sum + (namespace.projects?.count ?? 0), 0) + const personalProjectsCount = namespaces.find(namespace => namespace.id === currentUser?.namespace?.id)?.projects?.count ?? 0 + const organizationProjectsCount = totalProjectsCount - personalProjectsCount + const newProjectsLastWeek = projects.filter(project => withinDays(project.createdAt, 7)).length + + const totalFlowsCount = projects.reduce((sum, project) => sum + (project.flows?.count ?? 0), 0) + const newFlowsLastMonth = projects + .flatMap(project => project.flows?.nodes ?? []) + .filter(flow => withinDays(flow?.createdAt, 30)).length + const leftContent = @@ -99,20 +156,21 @@ export const ApplicationPage = () => { Organizations - + {newOrganizationsLastMonth > 0 && - +2 last month - + +{newOrganizationsLastMonth} last month + } - 7 + {organizationNamespaces.length} - You are the owner of 3 organizations
and a member of 4 + You are the owner of {ownedOrganizationsCount} organizations
and a + member of {memberOrganizationsCount}
@@ -124,20 +182,21 @@ export const ApplicationPage = () => { Projects - + {newProjectsLastWeek > 0 && - +8 last week - + +{newProjectsLastWeek} last week + } - 82 + {totalProjectsCount} - You are the owner of 40 projects
and a member of 42 + {personalProjectsCount} in your personal workspace
and + {" "}{organizationProjectsCount} in your organizations
@@ -149,20 +208,21 @@ export const ApplicationPage = () => { Flows - + {newFlowsLastMonth > 0 && - +102 last month - + +{newFlowsLastMonth} last month + } - 781 + {totalFlowsCount} - You are the owner of 361 flows
and a member of 420 + Spread across {totalProjectsCount} projects
and + {" "}{namespaces.length} workspaces
@@ -211,12 +271,12 @@ export const ApplicationPage = () => { - Top organizations + Top workspaces @@ -228,7 +288,7 @@ export const ApplicationPage = () => { - + From aeaeda3849cf91e9950b1c46909a7517a33b760c Mon Sep 17 00:00:00 2001 From: nicosammito Date: Fri, 10 Jul 2026 15:28:16 +0200 Subject: [PATCH 36/36] feat: implement scrollable area in ModulesPage for better plugin visibility --- .../ce/src/module/pages/ModulesPage.tsx | 192 ++++++++++-------- 1 file changed, 103 insertions(+), 89 deletions(-) diff --git a/src/packages/ce/src/module/pages/ModulesPage.tsx b/src/packages/ce/src/module/pages/ModulesPage.tsx index 8ac6b205..78ddb000 100644 --- a/src/packages/ce/src/module/pages/ModulesPage.tsx +++ b/src/packages/ce/src/module/pages/ModulesPage.tsx @@ -8,10 +8,11 @@ import { Button, Card, Col, - DataTableFilterInput, Flex, hashToColor, Row, + ScrollArea, ScrollAreaScrollbar, ScrollAreaThumb, + ScrollAreaViewport, Spacing, Text, useService, @@ -60,100 +61,113 @@ export const ModulesPage: React.FC = () => { borderTopLeftRadius: "1rem", borderTopRightRadius: "1rem" }}> - - - Installed plugins on {project?.name} - - - - - - { - modules.map(module => { + + + + + Installed plugins on {project?.name} + + + + + + { + modules.map(module => { - const DisplayIcon = icon(module.icon as IconString) + const DisplayIcon = icon(module.icon as IconString) - return - - - - - - - - - - - {module.names?.[0].content} - - - {module.flowTypes?.count ? `${module.flowTypes.count} flow types` : null} - {module.flowTypes?.count && module.functionDefinitions?.count ? " and " : null} - {module.functionDefinitions?.count ? `${module.functionDefinitions.count} functions` : null} - + return + + + + + + + + + + + {module.names?.[0].content} + + + {module.flowTypes?.count ? `${module.flowTypes.count} flow types` : null} + {module.flowTypes?.count && module.functionDefinitions?.count ? " and " : null} + {module.functionDefinitions?.count ? `${module.functionDefinitions.count} functions` : null} + + + + + + installed + + + {module.descriptions?.[0]?.content}
+ This plugin was developed by + + @{module.author} + +
+
+
+ + + + - - - installed - -
- - {module.descriptions?.[0]?.content}
- This plugin was developed by - - @{module.author} - -
-
-
- - - - - - + +
+ + }) + } + + + Are you missing a plugin? + + + Create a issue on our github repository or join our discord to request a plugin + + + + + - }) - } - - - Are you missing a plugin? - - - Create a issue on our github repository or join our discord to request a plugin - - - - - - - -
+
+ + + +
+