Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ApplicationCreate page for new application creation #716

Merged
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- **Applications page**: Displays a list of all existing applications, with navigation to individual Application pages.
- **Application page**: Shows the details of a selected application, including its name, description and a list of releases, with navigation to individual Release pages.
- **Release page**: Provides details of a specific release, including a list of containers and configurations, such as image reference, image credentials (label, username), networks, and port bindings.
- Added `ApplicationCreate` page to enable users to create a new application with fields for application name and description.

## [0.9.1] - 2024-10-28
### Fixed
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ import Login from "pages/Login";
import Logout from "pages/Logout";
import AttemptLogin from "pages/AttemptLogin";
import Applications from "pages/Applications";
import ApplicationCreatePage from "pages/ApplicationCreate";
import Application from "pages/Application";
import Release from "pages/Release";

Expand Down Expand Up @@ -94,6 +95,7 @@ const authenticatedRoutes: RouterRule[] = [
{ path: Route.updateCampaignsNew, element: <UpdateCampaignCreate /> },
{ path: Route.updateCampaignsEdit, element: <UpdateCampaign /> },
{ path: Route.applications, element: <Applications /> },
{ path: Route.applicationNew, element: <ApplicationCreatePage /> },
{ path: Route.application, element: <Application /> },
{ path: Route.release, element: <Release /> },
{ path: Route.logout, element: <Logout /> },
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/Navigation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
updateCampaignsNew = "/update-campaigns/new",
updateCampaignsEdit = "/update-campaigns/:updateCampaignId",
applications = "/applications",
applicationNew = "/applications/new",
application = "/applications/:applicationId",
release = "/release/:releaseId",
login = "/login",
Expand Down Expand Up @@ -116,6 +117,7 @@
case Route.login:
case Route.logout:
case Route.applications:
case Route.applicationNew:
return route.route;
}
};
Expand All @@ -142,5 +144,5 @@
return navigate;
};

export { Link, Route, matchPaths, useNavigate };

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

View workflow job for this annotation

GitHub Actions / Build and 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 147 in frontend/src/Navigation.tsx

View workflow job for this annotation

GitHub Actions / Build and Test

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 };
107 changes: 84 additions & 23 deletions frontend/src/api/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@ schema {
query: RootQueryType
}

input ContainerCreateWithNestedImageInput {
id: ID
reference: String!
imageCredentialsId: ID
}

input UpdateCampaignRolloutMechanismPushInput {
"This boolean flag determines if the Base Image will be pushed to the Device even if it already has a greater version of the Base Image."
forceDowngrade: Boolean
Expand Down Expand Up @@ -414,6 +420,9 @@ enum NetworkInterfaceTechnology {
}

enum ApplicationDeploymentStatus {
"The deployment is being deleted"
DELETING

"The deployment process entered an error state."
ERROR

Expand Down Expand Up @@ -829,10 +838,22 @@ type MutationError {
fields: [String!]
}

input ApplicationCreateInitialReleaseInput {
version: String!
containers: [ReleaseCreateContainersInput!]
}

input ReleaseCreateContainersInput {
env: JsonString
image: ContainerCreateWithNestedImageInput
hostname: String
privileged: Boolean
restartPolicy: String
}

enum NetworkSortField {
ID
DRIVER
CHECK_DUPLICATE
INTERNAL
ENABLE_IPV6
}
Expand Down Expand Up @@ -880,17 +901,6 @@ input NetworkFilterInternal {
greaterThanOrEqual: Boolean
}

input NetworkFilterCheckDuplicate {
isNil: Boolean
eq: Boolean
notEq: Boolean
in: [Boolean!]
lessThan: Boolean
greaterThan: Boolean
lessThanOrEqual: Boolean
greaterThanOrEqual: Boolean
}

input NetworkFilterDriver {
isNil: Boolean
eq: String
Expand Down Expand Up @@ -921,7 +931,6 @@ input NetworkFilterInput {
not: [NetworkFilterInput!]
id: NetworkFilterId
driver: NetworkFilterDriver
checkDuplicate: NetworkFilterCheckDuplicate
internal: NetworkFilterInternal
enableIpv6: NetworkFilterEnableIpv6
}
Expand All @@ -934,9 +943,24 @@ input NetworkSortInput {
type Network {
id: ID!
driver: String!
checkDuplicate: Boolean!
internal: Boolean!
enableIpv6: Boolean!
options: [String!]!
}

"The result of the :create_release mutation"
type CreateReleaseResult {
"The successful result of the mutation"
result: Release

"Any errors generated, if the mutation failed"
errors: [MutationError!]!
}

input CreateReleaseInput {
version: String!
applicationId: ID
containers: [ReleaseCreateContainersInput!]
}

enum ReleaseSortField {
Expand Down Expand Up @@ -1232,8 +1256,8 @@ type DeployReleaseResult {
}

input DeployReleaseInput {
deviceId: ID
releaseId: ID
deviceId: ID!
}

enum DeploymentSortField {
Expand Down Expand Up @@ -1277,13 +1301,13 @@ input DeploymentFilterReleaseId {

input DeploymentFilterDeviceId {
isNil: Boolean
eq: ID
notEq: ID
in: [ID]
lessThan: ID
greaterThan: ID
lessThanOrEqual: ID
greaterThanOrEqual: ID
eq: Int
notEq: Int
in: [Int]
lessThan: Int
greaterThan: Int
lessThanOrEqual: Int
greaterThanOrEqual: Int
}

input DeploymentFilterStatus {
Expand Down Expand Up @@ -1340,6 +1364,7 @@ enum ContainerSortField {
HOSTNAME
ENV
PRIVILEGED
NETWORK_MODE
IMAGE_ID
}

Expand Down Expand Up @@ -1375,6 +1400,19 @@ input ContainerFilterImageId {
greaterThanOrEqual: ID
}

input ContainerFilterNetworkMode {
isNil: Boolean
eq: String
notEq: String
in: [String!]
lessThan: String
greaterThan: String
lessThanOrEqual: String
greaterThanOrEqual: String
like: String
ilike: String
}

input ContainerFilterPrivileged {
isNil: Boolean
eq: Boolean
Expand Down Expand Up @@ -1441,6 +1479,7 @@ input ContainerFilterInput {
hostname: ContainerFilterHostname
env: ContainerFilterEnv
privileged: ContainerFilterPrivileged
networkMode: ContainerFilterNetworkMode
imageId: ContainerFilterImageId
image: ImageFilterInput
networks: NetworkFilterInput
Expand All @@ -1458,6 +1497,7 @@ type Container {
hostname: String!
env: JsonString
privileged: Boolean
networkMode: String!
imageId: ID!
image: Image!
networks(
Expand All @@ -1481,6 +1521,21 @@ type Container {
): NetworkConnection!
}

"The result of the :create_application mutation"
type CreateApplicationResult {
"The successful result of the mutation"
result: Application

"Any errors generated, if the mutation failed"
errors: [MutationError!]!
}

input CreateApplicationInput {
name: String!
description: String
initialRelease: ApplicationCreateInitialReleaseInput
}

enum ApplicationSortField {
ID
NAME
Expand Down Expand Up @@ -3688,8 +3743,11 @@ type RootMutationType {
"Deletes a system model."
deleteSystemModel(id: ID!): DeleteSystemModelResult

"Create a new application."
createApplication(input: CreateApplicationInput!): CreateApplicationResult

"Deploy the application on a device"
deployRelease(input: DeployReleaseInput): DeployReleaseResult
deployRelease(input: DeployReleaseInput!): DeployReleaseResult

"Sends a :start command to the release on the device."
startDeployment(id: ID!): StartDeploymentResult
Expand All @@ -3704,6 +3762,9 @@ type RootMutationType {

deleteImageCredentials(id: ID!): DeleteImageCredentialsResult

"Create a new release."
createRelease(input: CreateReleaseInput!): CreateReleaseResult

"Create a new base image in a base image collection."
createBaseImage(input: CreateBaseImageInput!): CreateBaseImageResult

Expand Down
5 changes: 5 additions & 0 deletions frontend/src/components/DeployedApplicationsTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ const statusColors: Record<ApplicationDeploymentStatus, string> = {
STOPPING: "text-muted",
STOPPED: "text-secondary",
ERROR: "text-danger",
DELETING: "text-warning",
};

// Define status messages for localization
Expand All @@ -114,6 +115,10 @@ const statusMessages = defineMessages<ApplicationDeploymentStatus>({
id: "components.DeployedApplicationsTable.error",
defaultMessage: "Error",
},
DELETING: {
id: "components.DeployedApplicationsTable.deleting",
defaultMessage: "Deleting",
},
});

// Component to render the status with an icon and optional spin
Expand Down
7 changes: 6 additions & 1 deletion frontend/src/components/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,12 @@ const Sidebar = () => (
/>
}
route={Route.applications}
activeRoutes={[Route.applications, Route.application, Route.release]}
activeRoutes={[
Route.applications,
Route.applicationNew,
Route.application,
Route.release,
]}
/>
</SidebarItemGroup>
</Navbar>
Expand Down
Loading
Loading