{{ 'DASHBOARD.DISK' | translate }}
@@ -55,7 +52,14 @@{{ 'DASHBOARD.DISK' | translate }}
{{ usage.DiskUsage | byteFormat }} / {{ usage.DiskCapacity | byteFormat }}
+
+
diff --git a/App/Backend/cmd/kubernetes/handlers/GetConfigMaps.go b/App/Backend/cmd/kubernetes/handlers/GetConfigMaps.go index f094045..e7f613d 100644 --- a/App/Backend/cmd/kubernetes/handlers/GetConfigMaps.go +++ b/App/Backend/cmd/kubernetes/handlers/GetConfigMaps.go @@ -4,21 +4,24 @@ import ( "context" "github.com/eliasdehondt/K10s/App/Backend/cmd/kubernetes" "github.com/gin-gonic/gin" + v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "net/http" + "sync" "time" ) func GetConfigMapsHandler(ctx *gin.Context) { namespace, ok := ctx.GetQuery("namespace") + pageSize, pageToken := GetPageSizeAndPageToken(ctx) - var configMapList *[]kubernetes.ConfigMap + var configMapList *PaginatedResponse[[]kubernetes.ConfigMap] var err error if ok { - configMapList, err = GetConfigMaps(c, namespace) + configMapList, err = GetConfigMaps(c, namespace, pageSize, pageToken) } else { - configMapList, err = GetConfigMaps(c, "") + configMapList, err = GetConfigMaps(c, "", pageSize, pageToken) } if err != nil { @@ -28,19 +31,42 @@ func GetConfigMapsHandler(ctx *gin.Context) { ctx.JSON(http.StatusOK, configMapList) } -func GetConfigMaps(c *kubernetes.IClient, namespace string) (*[]kubernetes.ConfigMap, error) { +func GetConfigMaps(c *kubernetes.IClient, namespace string, pageSize int, pageToken string) (*PaginatedResponse[[]kubernetes.ConfigMap], error) { ct, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() - list, err := (*c).GetConfigMaps(namespace).List(ct, metav1.ListOptions{}) + list, err := (*c).GetConfigMaps(namespace).List(ct, metav1.ListOptions{ + Limit: int64(pageSize), + Continue: pageToken, + }) if err != nil { return nil, err } - var configMapList = make([]kubernetes.ConfigMap, len(list.Items)) + return &PaginatedResponse[[]kubernetes.ConfigMap]{ + Response: transformConfigMaps(&list.Items), + PageToken: list.Continue, + }, nil +} + +func transformConfigMaps(list *[]v1.ConfigMap) []kubernetes.ConfigMap { + var configList = make([]kubernetes.ConfigMap, len(*list)) + + var wg sync.WaitGroup + concurrency := 20 + semaphore := make(chan struct{}, concurrency) - for i, configMap := range list.Items { - configMapList[i] = kubernetes.NewConfigMap(configMap) + for i, config := range *list { + wg.Add(1) + semaphore <- struct{}{} + + go func(i int, node v1.ConfigMap) { + defer wg.Done() + configList[i] = kubernetes.NewConfigMap(config) + <-semaphore + }(i, config) } - return &configMapList, nil + + wg.Wait() + return configList } diff --git a/App/Backend/cmd/kubernetes/handlers/GetDeployments.go b/App/Backend/cmd/kubernetes/handlers/GetDeployments.go index b82e5e5..fe0403c 100644 --- a/App/Backend/cmd/kubernetes/handlers/GetDeployments.go +++ b/App/Backend/cmd/kubernetes/handlers/GetDeployments.go @@ -4,22 +4,24 @@ import ( "context" "github.com/eliasdehondt/K10s/App/Backend/cmd/kubernetes" "github.com/gin-gonic/gin" + v1 "k8s.io/api/apps/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "net/http" + "sync" "time" ) func GetDeploymentsHandler(ctx *gin.Context) { - namespace, ok := ctx.GetQuery("namespace") + pageSize, pageToken := GetPageSizeAndPageToken(ctx) - var deploymentList *[]kubernetes.Deployment + var deploymentList *PaginatedResponse[[]kubernetes.Deployment] var err error if ok { - deploymentList, err = GetDeployments(c, namespace) + deploymentList, err = GetDeployments(c, namespace, pageSize, pageToken) } else { - deploymentList, err = GetDeployments(c, "") + deploymentList, err = GetDeployments(c, "", pageSize, pageToken) } if err != nil { @@ -29,19 +31,42 @@ func GetDeploymentsHandler(ctx *gin.Context) { ctx.JSON(http.StatusOK, deploymentList) } -func GetDeployments(c *kubernetes.IClient, namespace string) (*[]kubernetes.Deployment, error) { +func GetDeployments(c *kubernetes.IClient, namespace string, pageSize int, pageToken string) (*PaginatedResponse[[]kubernetes.Deployment], error) { ct, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() - list, err := (*c).GetDeployments(namespace).List(ct, metav1.ListOptions{}) + list, err := (*c).GetDeployments(namespace).List(ct, metav1.ListOptions{ + Limit: int64(pageSize), + Continue: pageToken, + }) if err != nil { return nil, err } - var deploymentList = make([]kubernetes.Deployment, len(list.Items)) + return &PaginatedResponse[[]kubernetes.Deployment]{ + Response: transformDeployments(&list.Items), + PageToken: list.Continue, + }, nil +} + +func transformDeployments(list *[]v1.Deployment) []kubernetes.Deployment { + var deploymentList = make([]kubernetes.Deployment, len(*list)) - for i, deployment := range list.Items { - deploymentList[i] = kubernetes.NewDeployment(deployment) + var wg sync.WaitGroup + concurrency := 20 + semaphore := make(chan struct{}, concurrency) + + for i, deployment := range *list { + wg.Add(1) + semaphore <- struct{}{} + + go func(i int, node v1.Deployment) { + defer wg.Done() + deploymentList[i] = kubernetes.NewDeployment(deployment) + <-semaphore + }(i, deployment) } - return &deploymentList, nil + + wg.Wait() + return deploymentList } diff --git a/App/Backend/cmd/kubernetes/handlers/GetNodes.go b/App/Backend/cmd/kubernetes/handlers/GetNodes.go index 7eca921..ded3c24 100644 --- a/App/Backend/cmd/kubernetes/handlers/GetNodes.go +++ b/App/Backend/cmd/kubernetes/handlers/GetNodes.go @@ -4,13 +4,17 @@ import ( "context" "github.com/eliasdehondt/K10s/App/Backend/cmd/kubernetes" "github.com/gin-gonic/gin" + v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "net/http" + "sync" "time" ) func GetNodesHandler(ctx *gin.Context) { - nodeList, err := GetNodes(c) + pageSize, pageToken := GetPageSizeAndPageToken(ctx) + + nodeList, err := GetNodes(c, pageSize, pageToken) if err != nil { ctx.JSON(http.StatusInternalServerError, gin.H{"error": "An error has occurred or the request has been timed out."}) return @@ -18,19 +22,42 @@ func GetNodesHandler(ctx *gin.Context) { ctx.JSON(http.StatusOK, nodeList) } -func GetNodes(c *kubernetes.IClient) (*[]kubernetes.Node, error) { +func GetNodes(c *kubernetes.IClient, pageSize int, pageToken string) (*PaginatedResponse[[]kubernetes.Node], error) { ct, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() - list, err := (*c).GetNodes().List(ct, metav1.ListOptions{}) + list, err := (*c).GetNodes().List(ct, metav1.ListOptions{ + Limit: int64(pageSize), + Continue: pageToken, + }) if err != nil { return nil, err } - var nodeList = make([]kubernetes.Node, len(list.Items)) + return &PaginatedResponse[[]kubernetes.Node]{ + Response: transformNodes(&list.Items), + PageToken: list.Continue, + }, nil +} + +func transformNodes(list *[]v1.Node) []kubernetes.Node { + var nodeList = make([]kubernetes.Node, len(*list)) - for i, node := range list.Items { - nodeList[i] = kubernetes.NewNode(node, c) + var wg sync.WaitGroup + concurrency := 20 + semaphore := make(chan struct{}, concurrency) + + for i, node := range *list { + wg.Add(1) + semaphore <- struct{}{} + + go func(i int, node v1.Node) { + defer wg.Done() + nodeList[i] = kubernetes.NewNode(node, c) + <-semaphore + }(i, node) } - return &nodeList, nil + + wg.Wait() + return nodeList } diff --git a/App/Backend/cmd/kubernetes/handlers/GetPods.go b/App/Backend/cmd/kubernetes/handlers/GetPods.go index fcaf97f..970ff2f 100644 --- a/App/Backend/cmd/kubernetes/handlers/GetPods.go +++ b/App/Backend/cmd/kubernetes/handlers/GetPods.go @@ -4,21 +4,24 @@ import ( "context" "github.com/eliasdehondt/K10s/App/Backend/cmd/kubernetes" "github.com/gin-gonic/gin" + v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "net/http" + "sync" "time" ) func GetPodsHandler(ctx *gin.Context) { namespace, ok := ctx.GetQuery("namespace") + pageSize, pageToken := GetPageSizeAndPageToken(ctx) - var podList *[]kubernetes.Pod + var podList *PaginatedResponse[[]kubernetes.Pod] var err error if ok { - podList, err = GetPods(c, namespace) + podList, err = GetPods(c, namespace, pageSize, pageToken) } else { - podList, err = GetPods(c, "") + podList, err = GetPods(c, "", pageSize, pageToken) } if err != nil { @@ -28,19 +31,42 @@ func GetPodsHandler(ctx *gin.Context) { ctx.JSON(http.StatusOK, podList) } -func GetPods(c *kubernetes.IClient, namespace string) (*[]kubernetes.Pod, error) { +func GetPods(c *kubernetes.IClient, namespace string, pageSize int, continueToken string) (*PaginatedResponse[[]kubernetes.Pod], error) { ct, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() - list, err := (*c).GetPods(namespace).List(ct, metav1.ListOptions{}) + list, err := (*c).GetPods(namespace).List(ct, metav1.ListOptions{ + Limit: int64(pageSize), + Continue: continueToken, + }) if err != nil { return nil, err } - var podList = make([]kubernetes.Pod, len(list.Items)) + return &PaginatedResponse[[]kubernetes.Pod]{ + Response: transformPods(&list.Items), + PageToken: list.Continue, + }, nil +} + +func transformPods(list *[]v1.Pod) []kubernetes.Pod { + var podList = make([]kubernetes.Pod, len(*list)) + + var wg sync.WaitGroup + concurrency := 20 + semaphore := make(chan struct{}, concurrency) - for i, pod := range list.Items { - podList[i] = kubernetes.NewPod(pod, c) + for i, pod := range *list { + wg.Add(1) + semaphore <- struct{}{} + + go func(i int, pod v1.Pod) { + defer wg.Done() + podList[i] = kubernetes.NewPod(pod, c) + <-semaphore + }(i, pod) } - return &podList, nil + + wg.Wait() + return podList } diff --git a/App/Backend/cmd/kubernetes/handlers/GetSecrets.go b/App/Backend/cmd/kubernetes/handlers/GetSecrets.go index 0ae6e64..7edb731 100644 --- a/App/Backend/cmd/kubernetes/handlers/GetSecrets.go +++ b/App/Backend/cmd/kubernetes/handlers/GetSecrets.go @@ -4,21 +4,24 @@ import ( "context" "github.com/eliasdehondt/K10s/App/Backend/cmd/kubernetes" "github.com/gin-gonic/gin" + v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "net/http" + "sync" "time" ) func GetSecretsHandler(ctx *gin.Context) { namespace, ok := ctx.GetQuery("namespace") + pageSize, pageToken := GetPageSizeAndPageToken(ctx) - var secretList *[]kubernetes.Secret + var secretList *PaginatedResponse[[]kubernetes.Secret] var err error if ok { - secretList, err = GetSecrets(c, namespace) + secretList, err = GetSecrets(c, namespace, pageSize, pageToken) } else { - secretList, err = GetSecrets(c, "") + secretList, err = GetSecrets(c, "", pageSize, pageToken) } if err != nil { ctx.JSON(http.StatusInternalServerError, gin.H{"error": "An error has occurred or the request has been timed out."}) @@ -27,19 +30,43 @@ func GetSecretsHandler(ctx *gin.Context) { ctx.JSON(http.StatusOK, secretList) } -func GetSecrets(c *kubernetes.IClient, namespace string) (*[]kubernetes.Secret, error) { +func GetSecrets(c *kubernetes.IClient, namespace string, pageSize int, pageToken string) (*PaginatedResponse[[]kubernetes.Secret], error) { ct, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() - list, err := (*c).GetSecrets(namespace).List(ct, metav1.ListOptions{}) + list, err := (*c).GetSecrets(namespace).List(ct, metav1.ListOptions{ + Limit: int64(pageSize), + Continue: pageToken, + }) if err != nil { return nil, err } - var secretList = make([]kubernetes.Secret, len(list.Items)) + return &PaginatedResponse[[]kubernetes.Secret]{ + Response: transformSecrets(&list.Items), + PageToken: list.Continue, + }, nil +} + +func transformSecrets(list *[]v1.Secret) []kubernetes.Secret { + var secretList = make([]kubernetes.Secret, len(*list)) + + var wg sync.WaitGroup + concurrency := 20 + semaphore := make(chan struct{}, concurrency) + + for i, secret := range *list { + wg.Add(1) + semaphore <- struct{}{} + + go func(i int, node v1.Secret) { + defer wg.Done() + secretList[i] = kubernetes.NewSecret(secret) + <-semaphore + }(i, secret) - for i, secret := range list.Items { - secretList[i] = kubernetes.NewSecret(secret) } - return &secretList, nil + wg.Wait() + + return secretList } diff --git a/App/Backend/cmd/kubernetes/handlers/GetServices.go b/App/Backend/cmd/kubernetes/handlers/GetServices.go index a4f6366..82ed702 100644 --- a/App/Backend/cmd/kubernetes/handlers/GetServices.go +++ b/App/Backend/cmd/kubernetes/handlers/GetServices.go @@ -4,21 +4,24 @@ import ( "context" "github.com/eliasdehondt/K10s/App/Backend/cmd/kubernetes" "github.com/gin-gonic/gin" + v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "net/http" + "sync" "time" ) func GetServicesHandler(ctx *gin.Context) { namespace, ok := ctx.GetQuery("namespace") + pageSize, pageToken := GetPageSizeAndPageToken(ctx) - var serviceList *[]kubernetes.Service + var serviceList *PaginatedResponse[[]kubernetes.Service] var err error if ok { - serviceList, err = GetServices(c, namespace) + serviceList, err = GetServices(c, namespace, pageSize, pageToken) } else { - serviceList, err = GetServices(c, "") + serviceList, err = GetServices(c, "", pageSize, pageToken) } if err != nil { @@ -28,19 +31,40 @@ func GetServicesHandler(ctx *gin.Context) { ctx.JSON(http.StatusOK, serviceList) } -func GetServices(c *kubernetes.IClient, namespace string) (*[]kubernetes.Service, error) { +func GetServices(c *kubernetes.IClient, namespace string, pageSize int, pageToken string) (*PaginatedResponse[[]kubernetes.Service], error) { ct, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() - list, err := (*c).GetServices(namespace).List(ct, metav1.ListOptions{}) + list, err := (*c).GetServices(namespace).List(ct, metav1.ListOptions{ + Limit: int64(pageSize), + Continue: pageToken, + }) if err != nil { return nil, err } - var serviceList = make([]kubernetes.Service, len(list.Items)) + return &PaginatedResponse[[]kubernetes.Service]{ + Response: transformServices(&list.Items), + PageToken: list.Continue, + }, nil +} + +func transformServices(list *[]v1.Service) []kubernetes.Service { + var serviceList = make([]kubernetes.Service, len(*list)) + var wg sync.WaitGroup + concurrency := 20 + semaphore := make(chan struct{}, concurrency) - for i, service := range list.Items { - serviceList[i] = kubernetes.NewService(service) + for i, service := range *list { + wg.Add(1) + + go func(i int, service v1.Service) { + defer wg.Done() + serviceList[i] = kubernetes.NewService(service) + semaphore <- struct{}{} + }(i, service) } - return &serviceList, nil + wg.Wait() + + return serviceList } diff --git a/App/Backend/cmd/kubernetes/handlers/Vars.go b/App/Backend/cmd/kubernetes/handlers/Vars.go deleted file mode 100644 index b1bcf43..0000000 --- a/App/Backend/cmd/kubernetes/handlers/Vars.go +++ /dev/null @@ -1,5 +0,0 @@ -package handlers - -import "github.com/eliasdehondt/K10s/App/Backend/cmd/kubernetes" - -var c = kubernetes.GetClients() diff --git a/App/Backend/cmd/kubernetes/handlers/util.go b/App/Backend/cmd/kubernetes/handlers/util.go new file mode 100644 index 0000000..c504015 --- /dev/null +++ b/App/Backend/cmd/kubernetes/handlers/util.go @@ -0,0 +1,24 @@ +package handlers + +import ( + "github.com/eliasdehondt/K10s/App/Backend/cmd/kubernetes" + "github.com/gin-gonic/gin" + "strconv" +) + +var c = kubernetes.GetClients() + +type PaginatedResponse[T any] struct { + Response T + PageToken string +} + +func GetPageSizeAndPageToken(ctx *gin.Context) (int, string) { + pageSizeString, _ := ctx.GetQuery("pageSize") + pageToken, _ := ctx.GetQuery("pageToken") + pageSize, err := strconv.Atoi(pageSizeString) + if err != nil { + pageSize = 20 + } + return pageSize, pageToken +} diff --git a/App/Backend/testing/get_handler_test.go b/App/Backend/testing/get_handler_test.go index 2073f9c..c2380dc 100644 --- a/App/Backend/testing/get_handler_test.go +++ b/App/Backend/testing/get_handler_test.go @@ -10,93 +10,93 @@ import ( var client = kubernetes.TestFakeClient() func TestGetNodes(t *testing.T) { - nodes, err := handlers.GetNodes(&client) + nodes, err := handlers.GetNodes(&client, 20, "") assert.NoError(t, err) assert.NotEmpty(t, nodes) - assert.Equal(t, "node-1", (*nodes)[0].Name) - assert.Equal(t, "node-2", (*nodes)[1].Name) + assert.Equal(t, "node-1", (*nodes).Response[0].Name) + assert.Equal(t, "node-2", (*nodes).Response[1].Name) } func TestGetPods(t *testing.T) { - pods, err := handlers.GetPods(&client, "") + pods, err := handlers.GetPods(&client, "", 20, "") assert.NoError(t, err) assert.NotEmpty(t, pods) - assert.Equal(t, "pod-1", (*pods)[0].Name) - assert.Equal(t, "pod-2", (*pods)[1].Name) + assert.Equal(t, "pod-1", (*pods).Response[0].Name) + assert.Equal(t, "pod-2", (*pods).Response[1].Name) } func TestGetPodsWithNamespace(t *testing.T) { - pods, err := handlers.GetPods(&client, "test") + pods, err := handlers.GetPods(&client, "test", 20, "") assert.NoError(t, err) assert.NotEmpty(t, pods) - assert.Equal(t, "pod-3", (*pods)[0].Name) + assert.Equal(t, "pod-3", (*pods).Response[0].Name) } func TestGetServices(t *testing.T) { - services, err := handlers.GetServices(&client, "") + services, err := handlers.GetServices(&client, "", 20, "") assert.NoError(t, err) assert.NotEmpty(t, services) - assert.Equal(t, "service-1", (*services)[0].Name) + assert.Equal(t, "service-1", (*services).Response[0].Name) } func TestGetServicesWithNamespace(t *testing.T) { - services, err := handlers.GetServices(&client, "test") + services, err := handlers.GetServices(&client, "test", 20, "") assert.NoError(t, err) assert.NotEmpty(t, services) - assert.Equal(t, "service-2", (*services)[0].Name) + assert.Equal(t, "service-2", (*services).Response[0].Name) } func TestGetDeployments(t *testing.T) { - deployments, err := handlers.GetDeployments(&client, "") + deployments, err := handlers.GetDeployments(&client, "", 20, "") assert.NoError(t, err) assert.NotEmpty(t, deployments) - assert.Equal(t, "deployment-1", (*deployments)[0].Name) + assert.Equal(t, "deployment-1", (*deployments).Response[0].Name) } func TestGetDeploymentsWithNamespace(t *testing.T) { - deployments, err := handlers.GetDeployments(&client, "test") + deployments, err := handlers.GetDeployments(&client, "test", 20, "") assert.NoError(t, err) assert.NotEmpty(t, deployments) - assert.Equal(t, "deployment-2", (*deployments)[0].Name) + assert.Equal(t, "deployment-2", (*deployments).Response[0].Name) } func TestGetConfigMaps(t *testing.T) { - maps, err := handlers.GetConfigMaps(&client, "") + maps, err := handlers.GetConfigMaps(&client, "", 20, "") assert.NoError(t, err) assert.NotEmpty(t, maps) - assert.Equal(t, "configmap-1", (*maps)[0].Name) + assert.Equal(t, "configmap-1", (*maps).Response[0].Name) } func TestGetConfigMapsWithNamespace(t *testing.T) { - maps, err := handlers.GetConfigMaps(&client, "test") + maps, err := handlers.GetConfigMaps(&client, "test", 20, "") assert.NoError(t, err) assert.NotEmpty(t, maps) - assert.Equal(t, "configmap-2", (*maps)[0].Name) + assert.Equal(t, "configmap-2", (*maps).Response[0].Name) } func TestGetSecrets(t *testing.T) { - secrets, err := handlers.GetSecrets(&client, "") + secrets, err := handlers.GetSecrets(&client, "", 20, "") assert.NoError(t, err) assert.NotEmpty(t, secrets) - assert.Equal(t, "secret-1", (*secrets)[0].Name) + assert.Equal(t, "secret-1", (*secrets).Response[0].Name) } func TestGetSecretsWithNamespace(t *testing.T) { - secrets, err := handlers.GetSecrets(&client, "test") + secrets, err := handlers.GetSecrets(&client, "test", 20, "") assert.NoError(t, err) assert.NotEmpty(t, secrets) - assert.Equal(t, "secret-2", (*secrets)[0].Name) + assert.Equal(t, "secret-2", (*secrets).Response[0].Name) } func TestGetTotalUsage(t *testing.T) { diff --git a/App/Frontend/src/app/add/add.component.css b/App/Frontend/src/app/add/add.component.css new file mode 100644 index 0000000..666fa9d --- /dev/null +++ b/App/Frontend/src/app/add/add.component.css @@ -0,0 +1,185 @@ +/**********************************/ +/* @since 01/01/2025 */ +/* @author K10s Open Source Team */ +/**********************************/ + +/* SetUp Grid */ +.add-header { grid-area: header; } +.nav { grid-area: nav; } +.add-main { grid-area: main; } +.footer { grid-area: footer; } + +.add-body { + display: grid; + grid-template-areas: + 'nav header' + 'nav main' + 'footer footer'; + grid-template-columns: 1fr 9fr; + grid-template-rows: 1fr 10fr 0.5fr; + gap: 16px; + padding: 10px; + height: 95vh; +} +/* SetUp Grid */ + +.add-header { + background-color: var(--quaternary); + color: var(--text); + border-radius: var(--radius); + box-shadow: 2px 0 5px var(--shadow); + width: 100%; + height: 100%; + font-weight: bold; + font-size: 1rem; + display: flex; + align-items: center; + justify-content: center; +} + +/* Add Main */ +.add-main { + background-color: var(--tertiary); + color: var(--text); + border-radius: var(--radius); + box-shadow: 2px 0 5px var(--shadow); + width: 100%; + height: 100%; + overflow: hidden; + display: flex; + flex-direction: column; + align-items: center; + justify-content: flex-start; + gap: 8vh; +} + +.add-svg-yaml { + width: 28px; + fill: var(--text); +} + +.add-textarea-container { + position: relative; + width: 100%; + height: 80%; + display: flex; +} + +.add-textarea { + width: 100%; + height: 100%; + padding: var(--spacing); + background-color: var(--tertiary); + color: var(--text); + border-radius: var(--radius); + box-shadow: 2px 0 5px var(--shadow); + overflow: hidden; +} + +.add-clear-button { + position: absolute; + top: 10px; + right: 10px; + background: var(--secondary); + color: white; + border: none; + width: 25px; + height: 25px; + border-radius: 50%; + cursor: pointer; + font-size: 14px; + display: flex; + align-items: center; + justify-content: center; + transition: background 0.3s ease; +} + +.add-clear-button:hover { + background: var(--primary); +} + +.add-button { + width: 10%; + padding: 12px 15px; + border: 1px solid var(--secondary); + border-radius: var(--radius); + background-color: var(--secondary); + color: var(--text); + font-size: 16px; + font-weight: bold; + text-align: center; + transition: background-color 0.3s ease, border-color 0.3s ease; +} + +.add-button:hover{ + background-color: var(--primary); + border-color: var(--primary); +} + +.add-yaml-button { + width: 15%; + border: 1px solid var(--secondary); + border-radius: var(--radius); + background-color: var(--secondary); + color: var(--text); + font-size: 16px; + font-weight: bold; + text-align: center; + transition: background-color 0.3s ease, border-color 0.3s ease; + display: flex; + align-items: center; + justify-content: center; + gap: 0.5rem; +} + +.add-yaml-button:hover { + background-color: var(--primary); + border-color: var(--primary); +} +/* Add Main */ + +/* Media Queries */ +@media screen and (max-width: 1360px) { + .add-body { + grid-template-areas: + 'nav header' + 'nav main' + 'footer footer'; + grid-template-columns: 0.5fr 3fr; + grid-template-rows: 2fr 9fr 0.5fr; + } + + .add-header { + grid-template-areas: + 'header1 header2' + 'header3 header3'; + grid-template-columns: 1fr 1fr; + grid-template-rows: 1fr 1fr; + } +} + +@media screen and (max-width: 1045px) { + .add-header { + grid-template-areas: + 'header1' + 'header2' + 'header3'; + grid-template-columns: 1fr; + grid-template-rows: 1fr 1fr 1fr; + } +} + +@media screen and (max-width: 610px) { + .add-body { + grid-template-areas: + 'nav' + 'main' + 'footer'; + grid-template-columns: 1fr; + grid-template-rows: 2fr 9fr 0.5fr; + } + + .add-header { + display: none; + } +} \ No newline at end of file diff --git a/App/Frontend/src/app/add/add.component.html b/App/Frontend/src/app/add/add.component.html new file mode 100644 index 0000000..091c928 --- /dev/null +++ b/App/Frontend/src/app/add/add.component.html @@ -0,0 +1,22 @@ + +
+{{ usage.DiskUsage | byteFormat }} / {{ usage.DiskCapacity | byteFormat }}
+
+
{{ 'SEARCH.CLUSTER_NAME' | translate }} | -{{ 'SEARCH.NAMESPACE' | translate }} | -{{ 'SEARCH.POD_NAME' | translate }} | -{{ 'SEARCH.STATUS' | translate }} | -{{ 'SEARCH.RESTART_COUNT' | translate }} | -{{ 'SEARCH.LAST_UPDATED' | translate }} | -
---|---|---|---|---|---|
Cluster-A | -default | -nginx-pod-1 | -Running | -0 | -2025-01-04 10:15:30 | -
Cluster-B | -kube-system | -kube-proxy-2 | -Running | -1 | -2025-01-03 18:45:12 | -
Cluster-C | -production | -backend-api-4 | -CrashLoopBackOff | -5 | -2025-01-04 09:30:45 | -
Cluster-D | -staging | -frontend-web-3 | -Pending | -0 | -2025-01-03 22:12:20 | -
Cluster-E | -monitoring | -prometheus-pod-7 | -Running | -2 | -2025-01-04 08:50:10 | -
Cluster-F | -default | -redis-cache-9 | -Running | -0 | -2025-01-04 07:45:00 | -
Cluster-G | -dev | -worker-node-5 | -ImagePullBackOff | -3 | -2025-01-04 10:00:00 | -
Cluster-H | -test | -db-service-10 | -Running | -0 | -2025-01-04 06:30:30 | -
Cluster-I | -default | -nginx-pod-1 | -Running | -0 | -2025-01-04 10:15:30 | -
Cluster-J | -kube-system | -kube-proxy-2 | -Running | -1 | -2025-01-03 18:45:12 | -
Cluster-L | -production | -backend-api-4 | -CrashLoopBackOff | -5 | -2025-01-04 09:30:45 | -
Cluster-M | -staging | -frontend-web-3 | -Pending | -0 | -2025-01-03 22:12:20 | -
Cluster-O | -monitoring | -prometheus-pod-7 | -Running | -2 | -2025-01-04 08:50:10 | -
Cluster-P | -default | -redis-cache-9 | -Running | -0 | -2025-01-04 07:45:00 | -
Cluster-K | -dev | -worker-node-5 | -ImagePullBackOff | -3 | -2025-01-04 10:00:00 | -
Cluster-R | -test | -db-service-10 | -Running | -0 | -2025-01-04 06:30:30 | -
Cluster-S | -default | -nginx-pod-1 | -Running | -0 | -2025-01-04 10:15:30 | -
Cluster-T | -default | -redis-cache-9 | -Running | -0 | -2025-01-04 07:45:00 | -
Cluster-V | -dev | -worker-node-5 | -ImagePullBackOff | -3 | -2025-01-04 10:00:00 | -
Cluster-W | -test | -db-service-10 | -Running | -0 | -2025-01-04 06:30:30 | -
Cluster-X | -default | -nginx-pod-1 | -Running | -0 | -2025-01-04 10:15:30 | -
Cluster-Y | -dev | -worker-node-5 | -ImagePullBackOff | -3 | -2025-01-04 10:00:00 | -
Cluster-Z | -test | -db-service-10 | -Running | -0 | -2025-01-04 06:30:30 | -
{{ 'SEARCH.CLUSTER_NAME' | translate }} | +{{ 'SEARCH.NAMESPACE' | translate }} | +{{ 'SEARCH.POD_NAME' | translate }} | +{{ 'SEARCH.STATUS' | translate }} | +{{ 'SEARCH.RESTART_COUNT' | translate }} | +{{ 'SEARCH.LAST_UPDATED' | translate }} | +
---|---|---|---|---|---|
{{ item.cluster }} | +{{ item.namespace }} | +{{ item.podName }} | +{{ item.status }} | +{{ item.restartCount }} | +{{ item.lastUpdated }} | +