Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 6 additions & 0 deletions frontend/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ import DeploymentCampaignsPage from "@/pages/DeploymentCampaigns";
import DeploymentCampaign from "@/pages/DeploymentCampaign";
import DeploymentCampaignCreate from "@/pages/DeploymentCampaignCreate";
import Deployment from "@/pages/Deployment";
import Repositories from "@/pages/Repositories";
import RepositoryCreatePage from "@/pages/RepositoryCreate";
import Repository from "@/pages/Repository";

import { hideNavigationElements } from "@/api";
import { bugs, repository, version } from "../package.json";
Expand Down Expand Up @@ -129,6 +132,9 @@ const authenticatedRoutes: RouterRule[] = [
{ path: Route.deploymentCampaigns, element: <DeploymentCampaignsPage /> },
{ path: Route.deploymentCampaignsNew, element: <DeploymentCampaignCreate /> },
{ path: Route.deploymentCampaignsEdit, element: <DeploymentCampaign /> },
{ path: Route.repositories, element: <Repositories /> },
{ path: Route.repositoryNew, element: <RepositoryCreatePage /> },
{ path: Route.repositoryEdit, element: <Repository /> },
{ path: Route.logout, element: <Logout /> },
{ path: "*", element: <Navigate to={Route.devices} replace /> },
];
Expand Down
27 changes: 26 additions & 1 deletion frontend/src/Navigation.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
This file is part of Edgehog.

Copyright 2021-2025 SECO Mind Srl
Copyright 2021-2026 SECO Mind Srl

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -72,6 +72,9 @@
deploymentCampaigns = "/deployment-campaigns",
deploymentCampaignsNew = "/deployment-campaigns/new",
deploymentCampaignsEdit = "/deployment-campaigns/:deploymentCampaignId",
repositories = "/repositories",
repositoryNew = "/repositories/new",
repositoryEdit = "/repositories/:repositoryId/edit",
login = "/login",
logout = "/logout",
}
Expand Down Expand Up @@ -129,6 +132,8 @@
case Route.deployments:
case Route.deploymentCampaigns:
case Route.deploymentCampaignsNew:
case Route.repositories:
case Route.repositoryNew:
case Route.login:
case Route.logout:
return { route } as ParametricRoute;
Expand Down Expand Up @@ -281,6 +286,14 @@
params: { deploymentCampaignId: params.deploymentCampaignId },
}
: null;

case Route.repositoryEdit:
return params && typeof params["repositoryId"] === "string"
? {
route,
params: { repositoryId: params.repositoryId },
}
: null;
}
};

Expand Down Expand Up @@ -495,15 +508,27 @@
id: "navigation.routeTitle.DeploymentCampaignsEdit",
defaultMessage: "Edit Campaign",
},
[Route.repositories]: {
id: "navigation.routeTitle.Repositories",
defaultMessage: "Repositories",
},
[Route.repositoryNew]: {
id: "navigation.routeTitle.RepositoryNew",
defaultMessage: "Create Repository",
},
[Route.repositoryEdit]: {
id: "navigation.routeTitle.RepositoryEdit",
defaultMessage: "Edit Repository",
},
});

export {
Link,
matchingParametricRoute,

Check warning on line 527 in frontend/src/Navigation.tsx

View workflow job for this annotation

GitHub Actions / coverage / coverage-test

Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components

Check warning on line 527 in frontend/src/Navigation.tsx

View workflow job for this annotation

GitHub Actions / linting / check-linting

Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components
matchingRoute,

Check warning on line 528 in frontend/src/Navigation.tsx

View workflow job for this annotation

GitHub Actions / coverage / coverage-test

Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components

Check warning on line 528 in frontend/src/Navigation.tsx

View workflow job for this annotation

GitHub Actions / linting / check-linting

Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components
matchPaths,

Check warning on line 529 in frontend/src/Navigation.tsx

View workflow job for this annotation

GitHub Actions / coverage / coverage-test

Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components

Check warning on line 529 in frontend/src/Navigation.tsx

View workflow job for this annotation

GitHub Actions / linting / check-linting

Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components
Route,
routeTitles,

Check warning on line 531 in frontend/src/Navigation.tsx

View workflow job for this annotation

GitHub Actions / coverage / coverage-test

Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components

Check warning on line 531 in frontend/src/Navigation.tsx

View workflow job for this annotation

GitHub Actions / linting / check-linting

Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components
useNavigate,

Check warning on line 532 in frontend/src/Navigation.tsx

View workflow job for this annotation

GitHub Actions / linting / check-linting

Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components
};
export type { LinkProps, ParametricRoute };
2 changes: 2 additions & 0 deletions frontend/src/components/Icon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import {
faSpinner,
faStop,
faSwatchbook,
faFolderOpen,
faTabletAlt,
faTimes,
faTrash,
Expand All @@ -65,6 +66,7 @@ const icons = {
delete: faTrash,
devices: faTabletAlt,
deviceGroups: faDatabase,
folder: faFolderOpen,
github: faGithub,
models: faSwatchbook,
os: faCompactDisc,
Expand Down
8 changes: 7 additions & 1 deletion frontend/src/components/Page.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* This file is part of Edgehog.
*
* Copyright 2021-2025 SECO Mind Srl
* Copyright 2021-2026 SECO Mind Srl
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -95,6 +95,7 @@ const useBreadcrumbItems = (): BreadcrumbItem[] => {
case Route.networks:
case Route.deployments:
case Route.deploymentCampaigns:
case Route.repositories:
case Route.login:
case Route.logout:
return [currentRoute];
Expand Down Expand Up @@ -181,6 +182,11 @@ const useBreadcrumbItems = (): BreadcrumbItem[] => {
case Route.deploymentCampaignsEdit:
case Route.deploymentCampaignsNew:
return [{ route: Route.deploymentCampaigns }, currentRoute];

case Route.repositoryNew:
case Route.repositoryEdit:
return [{ route: Route.repositories }, currentRoute];

default:
return [];
}
Expand Down
115 changes: 115 additions & 0 deletions frontend/src/components/RepositoriesTable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
// This file is part of Edgehog.
//
// Copyright 2026 SECO Mind Srl
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// SPDX-License-Identifier: Apache-2.0

import _ from "lodash";
import { useMemo } from "react";
import { FormattedMessage } from "react-intl";
import { graphql, useFragment } from "react-relay/hooks";

import type {
RepositoriesTable_RepositoryEdgeFragment$data,
RepositoriesTable_RepositoryEdgeFragment$key,
} from "@/api/__generated__/RepositoriesTable_RepositoryEdgeFragment.graphql";

import InfiniteTable from "@/components/InfiniteTable";
import { createColumnHelper } from "@/components/Table";
import { Link, Route } from "@/Navigation";

// We use graphql fields below in columns configuration
/* eslint-disable relay/unused-fields */
const REPOSITORIES_FRAGMENT = graphql`
fragment RepositoriesTable_RepositoryEdgeFragment on RepositoryConnection {
edges {
node {
id
name
handle
}
}
}
`;

type TableRecord = NonNullable<
NonNullable<RepositoriesTable_RepositoryEdgeFragment$data>["edges"]
>[number]["node"];

const columnHelper = createColumnHelper<TableRecord>();
const columns = [
columnHelper.accessor("name", {
header: () => (
<FormattedMessage
id="components.RepositoriesTable.nameTitle"
defaultMessage="Repository Name"
description="Title for the Name column of the repositories table"
/>
),
cell: ({ row, getValue }) => (
<Link
route={Route.repositoryEdit}
params={{ repositoryId: row.original.id }}
>
{getValue()}
</Link>
),
}),
columnHelper.accessor("handle", {
header: () => (
<FormattedMessage
id="components.RepositoriesTable.handleTitle"
defaultMessage="Handle"
description="Title for the Handle column of the repositories table"
/>
),
}),
];

type Props = {
className?: string;
repositoriesRef: RepositoriesTable_RepositoryEdgeFragment$key;
loading?: boolean;
onLoadMore?: () => void;
};

const RepositoriesTable = ({
className,
repositoriesRef,
loading = false,
onLoadMore,
}: Props) => {
const repositoriesFragment = useFragment(
REPOSITORIES_FRAGMENT,
repositoriesRef || null,
);

const repositories = useMemo<TableRecord[]>(() => {
return _.compact(repositoriesFragment?.edges?.map((e) => e?.node)) ?? [];
}, [repositoriesFragment]);

return (
<InfiniteTable
className={className}
columns={columns}
data={repositories}
loading={loading}
onLoadMore={onLoadMore}
hideSearch
/>
);
};

export default RepositoriesTable;
27 changes: 26 additions & 1 deletion frontend/src/components/Sidebar.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* This file is part of Edgehog.
*
* Copyright 2021-2025 SECO Mind Srl
* Copyright 2021-2026 SECO Mind Srl
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -128,6 +128,31 @@ const Sidebar = () => (
route={Route.channels}
activeRoutes={[Route.channels, Route.channelsEdit, Route.channelsNew]}
/>
<SidebarItemGroup
label={
<FormattedMessage
id="components.Sidebar.filesManagementGroupLabel"
defaultMessage="Files Management"
/>
}
icon="folder"
>
<SidebarItem
label={
<FormattedMessage
id="components.Sidebar.repositoriesLabel"
defaultMessage="Repositories"
/>
}
route={Route.repositories}
activeRoutes={[
Route.repositories,
Route.repositoryNew,
Route.repositoryEdit,
]}
/>
</SidebarItemGroup>

<SidebarItemGroup
label={
<FormattedMessage
Expand Down
Loading
Loading